/* Shared light theme for every Pine DSP page. Page specific layout lives
   in each page's own <style> block.

   ── LIGHT THEME ──
   Design decisions (keep to these when extending the page):
   · Solid surfaces only. No gradients, glows or frosted glass.
   · Warm off white page, white raised surfaces, charcoal footer.
   · Soft black ink for text; one mid grey for secondary text.
   · Solid buttons use the warm yellow of Delay's feature text (--action) with near
     black text; outline buttons are near black. Module colors appear only as small swatches, never as
     text on the light background.
   · One corner radius (--radius) everywhere; hairline borders
     instead of soft shadows. No pill shapes.
   · The plugin UI stays dark and is the most colorful thing on
     the page. */
:root {
  /* Charcoal theme: warm near black page, text in warm off white. */
  --page: #1d1c1a;
  --surface: #252422;
  --stage: #2b2a27;
  --ink: #f0eee9;
  --ink-soft: #d6d3cc;
  --muted: #a29e95;
  --line: #3a3835;
  --footer: #131211;
  --footer-text: #e9e7e2;
  --footer-muted: #9a978f;
  --footer-line: #2c2b28;
  /* Fixed dark ink for text sitting on bright fills (tags, yellow). */
  --on-bright: #161616;
  --brand: #00a3a3;
  /* Match Delay's Diffuse Mode yellow, with dark text on bright fills. */
  --action: #ffe500;
  --action-hover: #eed600;
  --action-ink: #0d0e0f;
  --action-on-dark: var(--action);
  --radius: 4px;
  --wrap: 1200px;
  --gutter: clamp(16px, 5vw, 48px);
  --font: "Instrument Sans", system-ui, sans-serif;
  /* Wide Archivo headings paired with Instrument Sans body text. */
  --font-display: "Archivo", var(--font);
  /* Read by storefront.css for the discount line. */
  --accent: var(--ink);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  color-scheme: dark;
  scroll-behavior: smooth;
  background-color: var(--page);
}

section[id],
article[id] {
  scroll-margin-top: 90px;
}

body {
  font-family: var(--font);
  background: var(--page);
  color: var(--ink);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

[hidden] {
  display: none !important;
}

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

/* ── NAV ── */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 200;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px var(--gutter);
  background: var(--page);
  border-bottom: 1px solid var(--line);
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 22px;
  letter-spacing: 0.01em;
  color: var(--ink);
  text-decoration: none;
}
.logo svg path {
  fill: var(--brand);
}

/* Groups #navLinks with the cart button and mobile toggle so .nav's
   space-between still only ever balances two things: the logo and
   this whole right-hand cluster. */
.nav-right {
  display: flex;
  align-items: center;
}

.nav-right a {
  color: var(--ink-soft);
  margin-left: 28px;
  text-decoration: none;
  font-size: 16px;
  font-weight: 500;
  transition: color 0.15s;
}
.nav-right a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 6px;
  text-decoration-thickness: 1px;
}

.nav-btn {
  background: none;
  border: none;
  color: var(--ink-soft);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 28px;
  padding: 0;
}
.nav-btn:hover {
  color: var(--ink);
}

.nav-btn-signin {
  border: 1px solid var(--ink);
  color: var(--ink);
  padding: 7px 16px;
  border-radius: var(--radius);
  font-size: 15px;
  transition:
    background 0.15s,
    color 0.15s;
}
.nav-btn-signin:hover {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-ink);
}

.nav-cart {
  position: relative;
  display: inline-flex;
  align-items: center;
  color: var(--ink-soft);
  /* Needs to out-rank #navLinks' z-index: 250, or the open mobile
     panel covers it — same reason #navToggle carries z-index: 260. */
  z-index: 260;
}
.nav-cart:hover {
  color: var(--ink);
}
.cart-badge {
  position: absolute;
  top: -6px;
  right: -8px;
  background: var(--action-ink);
  color: var(--action);
  font-size: 10px;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: var(--radius);
  min-width: 16px;
  text-align: center;
}

/* ── NAV DROPDOWN ── */
/* Products only opens the menu; it doesn't link anywhere itself, so it
   is a button styled to match the nav links. */
.nav-dropdown-trigger {
  display: inline-flex;
  align-items: center;
  padding: 0;
  background: none;
  border: 0;
  color: var(--ink-soft);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
}
.nav-dropdown-trigger:hover,
.nav-dropdown:focus-within .nav-dropdown-trigger {
  color: var(--ink);
}
.nav-dropdown {
  position: relative;
  display: inline-block;
  margin-left: 28px;
  /* Same reason as .nav-cart: out-ranks the open mobile drawer. */
  z-index: 260;
}
.nav-dropdown-caret {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-3px) rotate(45deg);
  vertical-align: middle;
  margin-left: 8px;
  transition: transform 0.2s;
}
.nav-dropdown:hover .nav-dropdown-caret,
.nav-dropdown.open .nav-dropdown-caret {
  transform: translateY(0) rotate(225deg);
}
.nav-dropdown-menu {
  position: absolute;
  top: 100%;
  /* Opens straight down from Products, with the menu items' text lined
     up under the word (panel padding 6px + link padding 12px). */
  left: -18px;
  /* padding-top (not a `top` offset) bridges the gap to the trigger
     so the hover area stays continuous. */
  padding-top: 18px;
  min-width: 220px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 0.15s ease,
    visibility 0.15s;
  z-index: 300;
}
/* .open is toggled by JS for touch, where hover can't drive it. */
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu,
.nav-dropdown.open .nav-dropdown-menu {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.nav-dropdown-menu-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: 0 8px 24px rgba(22, 22, 22, 0.08);
}
.nav-dropdown-menu a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 15px;
  margin-left: 0;
  color: var(--ink);
}
.nav-dropdown-menu a:hover {
  background: var(--page);
  text-decoration: none;
}
.nav-dropdown-icon {
  display: block;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* ── NAV: MOBILE TOGGLE ── */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  padding: 0;
  margin-left: 16px;
  background: none;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  z-index: 260;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--ink);
  transition:
    transform 0.25s ease,
    opacity 0.2s ease;
}
.nav-toggle.open span:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}
.nav-toggle.open span:nth-child(2) {
  opacity: 0;
}
.nav-toggle.open span:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}
.nav-overlay {
  display: none;
}

@media (max-width: 860px) {
  .nav-toggle {
    display: flex;
  }
  /* mobile.css spaces the Products trigger itself at this size. */
  .nav-dropdown {
    margin-left: 0;
  }
  .logo {
    flex-shrink: 0;
    gap: 8px;
    font-size: 19px;
  }
  .logo svg {
    width: 18px;
    height: 18px;
  }
  .nav-right .nav-btn {
    margin-left: 12px;
  }
  .nav-toggle {
    margin-left: 10px;
  }
  .nav-links {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(78vw, 320px);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    margin: 0;
    padding: 96px 28px 32px;
    background: var(--page);
    border-left: 1px solid var(--line);
    transform: translateX(100%);
    transition: transform 0.3s ease;
    overflow-y: auto;
    z-index: 250;
  }
  .nav-links.open {
    transform: translateX(0);
  }
  .nav-links a,
  .nav-links .nav-btn {
    margin-left: 0;
    font-size: 18px;
  }
  .nav-links a,
  .nav-links .nav-btn-signin {
    width: 100%;
  }
  .nav-links .nav-btn-signin {
    text-align: center;
    margin-top: 6px;
  }
  /* Below .nav's own z-index (200): .nav is its own stacking
     context, so a higher value here would cover the whole nav bar
     and swallow every tap on the open menu. */
  .nav-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(22, 22, 22, 0.35);
    opacity: 0;
    visibility: hidden;
    transition:
      opacity 0.25s ease,
      visibility 0.25s;
    z-index: 199;
  }
  .nav-overlay.open {
    opacity: 1;
    visibility: visible;
  }
  body.nav-open {
    overflow: hidden;
  }
}

/* ── BUTTONS ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 26px;
  border-radius: var(--radius);
  border: 1px solid var(--ink);
  cursor: pointer;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 600;
  transition:
    background 0.15s,
    color 0.15s,
    border-color 0.15s;
}
.btn-primary {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-ink);
}
.btn-buy,
.btn-add-cart {
  border-radius: 999px;
}
.btn-primary:hover {
  background: var(--action-hover);
  border-color: var(--action-hover);
}
.btn-ghost {
  background: transparent;
  color: var(--ink);
}
.btn-ghost:hover {
  background: var(--ink);
  color: var(--page);
}
.btn:disabled {
  cursor: default;
}
.btn:focus-visible,
.product-stage:focus-visible,
.footer-subscribe button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ── PRODUCTS ── */
.product {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
  padding-block: clamp(48px, 7vw, 96px);
}
.product:first-child {
  padding-top: clamp(28px, 3vw, 40px);
}
.product + .product {
  border-top: 1px solid var(--line);
}
.product--reverse {
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
}
.product--reverse .product-stage {
  order: 2;
}

/* The plugin sits on a plain studio grey backdrop, like a product
   photo. Its screenshot has black corners outside the rounded
   faceplate, so the video is clipped to that curve (24px radius at
   380 x 968, i.e. 6.3% / 2.5%). */
.product-stage {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: clamp(24px, 4vw, 48px) 24px;
  background: var(--stage);
  border-radius: var(--radius);
}
.plugin-img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  /* Shrinks on short laptop screens so the whole plugin fits on
     the first screen under the intro. */
  max-height: clamp(320px, calc(100vh - 380px), 520px);
  border-radius: 6.3% / 2.5%;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.06),
    0 18px 40px rgba(0, 0, 0, 0.45);
}

.product-flag {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 20px;
}
/* Offer label, cut like a shop tag: solid in the product's own color
   with dark text, a punched hole and a pointed end. When Moonbase
   reports a discount the real saving is printed on the tag. The body
   carries the cut shape; the outer element outlines it, because a plain
   border would be clipped away at the angled edges. */
.offer-tag {
  --tag-edge: color-mix(in srgb, var(--swatch) 65%, white);
  display: inline-flex;
  margin-bottom: 22px;
  transform-origin: 0 50%;
  filter: drop-shadow(1px 0 0 var(--tag-edge))
    drop-shadow(-1px 0 0 var(--tag-edge)) drop-shadow(0 1px 0 var(--tag-edge))
    drop-shadow(0 -1px 0 var(--tag-edge));
}
.offer-tag-body {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px 9px 28px;
  background: var(--swatch);
  color: var(--on-bright);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  line-height: 1.2;
  clip-path: polygon(12px 0, 100% 0, 100% 100%, 12px 100%, 0 50%);
}
.offer-tag--launch {
  --swatch: #ffe500;
}
.offer-tag-body::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: var(--page);
  box-shadow: inset 0 0 0 1px var(--tag-edge);
}
/* Give the offer its own line above the product name. */
.product-title-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
}
.product-title-row .offer-tag {
  margin: 0;
  order: -1;
  flex-shrink: 0;
}
.product-title-row .offer-tag-body {
  gap: 8px;
  font-size: 13px;
}
/* Swings in from its hole when the product is revealed. */
.motion .reveal:not(.product-stage) .offer-tag {
  rotate: -8deg;
  transition:
    opacity 0.7s ease,
    translate 0.9s cubic-bezier(0.2, 0.7, 0.1, 1),
    rotate 1.1s cubic-bezier(0.3, 1.6, 0.5, 1);
}
.motion .reveal.in:not(.product-stage) .offer-tag {
  rotate: 0deg;
}

.swatch {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  background: var(--swatch);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}
/* Display headings: plugin names at 800, big statements at 900. */
.product-name,
.section-title,
.feature-word,
.feature h2 {
  font-family: var(--font-display);
  font-stretch: 125%;
  letter-spacing: -0.02em;
}
.product-name {
  font-size: clamp(32px, 3.8vw, 50px);
  font-weight: 800;
  line-height: 1;
}
.product-type {
  margin-top: 10px;
  font-size: clamp(18px, 1.8vw, 21px);
  color: var(--muted);
}
.product-desc {
  max-width: 42ch;
  margin-top: 24px;
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink-soft);
}

.product-buy {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.product-buy .moonbase-price-details {
  align-items: flex-start;
  margin-bottom: 18px;
}
.product-buy .moonbase-price {
  justify-content: flex-start;
  gap: 10px;
}
/* Two tags may sit beside the price; let the row wrap on narrow screens. */
.product-buy .moonbase-price {
  flex-wrap: wrap;
  row-gap: 10px;
}
/* Personal discount: a solid green capsule on its own line under the
   price when a signed-in owner of other Blox plugins gets a lower price
   from Moonbase (site.js shows it and fills in the amount), so the price
   row keeps its place over the buttons. Same lettering as the offer
   tags. */
.personal-discount {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 9px 16px;
  border-radius: 999px;
  background: #3fd47a;
  color: var(--on-bright);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  line-height: 1.2;
  white-space: nowrap;
  margin-top: 8px;
}
.personal-discount-amount {
  font-variant-numeric: tabular-nums;
}
.personal-discount-amount:not(:empty)::before {
  content: "\00b7";
  margin-right: 0.5em;
}
.moonbase-price-current {
  color: var(--ink);
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
/* Was price sits beside the sale price at the same size, in red and
   struck through, so the two read as a pair. */
.moonbase-price-original {
  color: #ff7a6e;
  font-size: 28px;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-decoration-line: line-through;
  text-decoration-color: currentColor;
  text-decoration-thickness: 2px;
}
.moonbase-discount-description {
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
}
.product-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.learn-more-link {
  display: inline-block;
  margin-top: 20px;
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line);
  transition: text-decoration-color 0.15s;
}
.learn-more-link:hover {
  text-decoration-color: currentColor;
}

@media (max-width: 800px) {
  .product {
    grid-template-columns: minmax(0, 1fr);
  }
  .product--reverse .product-stage {
    order: 0;
  }
  .plugin-img {
    max-height: 420px;
  }
}

/* ── MOTION AND ARTWORK ──
   Everything that moves is tied to the products: the signal line
   behaves like a delay, and each stage carries its plugin's own
   faceplate artwork. The hidden starting states only apply under
   html.motion, which a head script sets unless the visitor asks
   for reduced motion — so without JS or with reduced motion the
   page is simply static. */
.hero {
  position: relative;
}
.signal {
  position: absolute;
  left: 0;
  bottom: -28px;
  width: 100%;
  height: 56px;
  display: block;
  pointer-events: none;
  z-index: 2;
}

.product-stage {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.product-stage .plugin-img {
  position: relative;
  z-index: 1;
}
.stage-art {
  position: absolute;
  z-index: 0;
  pointer-events: none;
}
/* Blox Delay: the echo spiral from its faceplate, turning slowly. */
.stage-art--spiral {
  left: 50%;
  top: 50%;
  width: 78%;
  aspect-ratio: 149 / 260;
  translate: -50% -50%;
  background: color-mix(in srgb, var(--swatch) 45%, var(--ink));
  opacity: 0.32;
  -webkit-mask: url("module-svgs/BLOX_MODULE__DELAY_SPIRAL.svg") center /
    contain no-repeat;
  mask: url("module-svgs/BLOX_MODULE__DELAY_SPIRAL.svg") center / contain
    no-repeat;
}
/* Blox Exciter: the lava contours from its faceplate. */
.stage-art--lava {
  inset: -6%;
  width: 112%;
  height: 112%;
  fill: none;
  stroke: color-mix(in srgb, var(--swatch) 55%, var(--ink));
  opacity: 0.5;
}
.stage-art--lava path {
  stroke-width: 1.25px;
  vector-effect: non-scaling-stroke;
}

.motion .hero-title,
.motion .hero-sub {
  animation: rise 1s cubic-bezier(0.2, 0.7, 0.1, 1) both;
}
.motion .hero-sub {
  animation-delay: 0.15s;
}
@keyframes rise {
  from {
    opacity: 0;
    translate: 0 24px;
  }
}

.motion .stage-art--spiral {
  animation: spin 120s linear infinite;
}
@keyframes spin {
  to {
    rotate: 360deg;
  }
}
.motion .stage-art--lava {
  animation: drift 9s ease-in-out infinite;
}
@keyframes drift {
  50% {
    translate: 0 -26px;
    scale: 1.05;
  }
}
/* A faint full copy of the contours stays put while the trace layer
   keeps drawing over it: each line traces in, holds, then erases
   forward, staggered so one is always mid stroke. */
.stage-art--lava .lava-ghost {
  opacity: 0.35;
}
.motion .stage-art--lava .lava-trace path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  stroke-width: 1.75px;
}
.motion .in .stage-art--lava .lava-trace path {
  animation: lava-draw 18s cubic-bezier(0.45, 0, 0.25, 1) infinite both;
}
.motion .in .stage-art--lava .lava-trace path:nth-child(2) {
  animation-delay: 6s;
}
.motion .in .stage-art--lava .lava-trace path:nth-child(3) {
  animation-delay: 12s;
}
@keyframes lava-draw {
  0% {
    stroke-dashoffset: 1;
  }
  40%,
  60% {
    stroke-dashoffset: 0;
  }
  100% {
    stroke-dashoffset: -1;
  }
}
/* Without motion the trace layer simply shows the finished drawing. */
html:not(.motion) .stage-art--lava .lava-ghost {
  display: none;
}

/* Clickable stages (the home page tiles) lift the plugin slightly on
   hover, hinting that the tile opens its product page. Uses transform,
   which neither the reveal (scale) nor the scroll drift (translate)
   touches, so all three combine. */
.product-stage .plugin-img {
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.1, 1);
}
@media (hover: hover) {
  a.product-stage:hover .plugin-img {
    transform: scale(1.05);
  }
}
a.product-stage:focus-visible .plugin-img {
  transform: scale(1.05);
}

/* Stages marked data-tilt lean toward the cursor instead (site.js writes
   the transform every frame), so the hover zoom and its transition are
   switched off on them while a mouse or trackpad is in use. */
[data-tilt] .plugin-img {
  will-change: transform;
}
[data-tilt].is-tilting .plugin-img {
  transition: none;
}
@media (hover: hover) and (pointer: fine) {
  .motion [data-tilt]:hover .plugin-img {
    transform: none;
  }
}

/* Stages open upward like a shutter; the plugin settles in from
   slightly larger. `scale` and `translate` are separate properties
   so this and the scroll drift set in JS never overwrite each other. */
.motion .product-stage.reveal {
  clip-path: inset(100% 0 0 0);
  transition: clip-path 1.1s cubic-bezier(0.7, 0, 0.2, 1);
}
.motion .product-stage.reveal.in {
  clip-path: inset(0 0 0 0);
}
.motion .product-stage.reveal .plugin-img {
  scale: 1.08;
  transition:
    scale 1.5s cubic-bezier(0.2, 0.7, 0.1, 1) 0.1s,
    transform 0.5s cubic-bezier(0.2, 0.7, 0.1, 1);
}
.motion .product-stage.reveal.in .plugin-img {
  scale: 1;
}

/* Text arrives line by line. */
.motion .reveal:not(.product-stage) > * {
  opacity: 0;
  translate: 0 18px;
  transition:
    opacity 0.7s ease,
    translate 0.9s cubic-bezier(0.2, 0.7, 0.1, 1);
}
.motion .reveal.in:not(.product-stage) > * {
  opacity: 1;
  translate: 0 0;
}
.motion .reveal.in > :nth-child(2) {
  transition-delay: 0.08s;
}
.motion .reveal.in > :nth-child(3) {
  transition-delay: 0.16s;
}
.motion .reveal.in > :nth-child(4) {
  transition-delay: 0.24s;
}
.motion .reveal.in > :nth-child(5) {
  transition-delay: 0.32s;
}

/* Nav tucks away while scrolling down and returns on the way up. */
.nav {
  transition: translate 0.35s cubic-bezier(0.2, 0.7, 0.1, 1);
}
.nav.nav-hidden {
  translate: 0 -100%;
}

.learn-more-link .arrow {
  display: inline-block;
  transition: translate 0.2s ease;
}
.learn-more-link:hover .arrow {
  translate: 4px 0;
}

/* ══ PRODUCT PAGES ══
   Shared by every plugin page (Blox Exciter, Blox Delay): hero row,
   sticky buy bar, walkthrough video, numbered feature rows and system
   requirements. Each page only sets its --swatch. */

/* Let product visuals and animated artwork sit directly on the page. */
.product-hero .product-stage,
.feature .product-stage {
  background: transparent;
}

/* ── HERO ── the same product row as the home page, with the
   page's h1 in place of the card title. */
.hero-band {
  position: relative;
}
.product.product-hero {
  padding-top: clamp(96px, 11vw, 128px);
  padding-bottom: clamp(40px, 5vw, 64px);
}
.product-hero .plugin-img {
  max-height: clamp(360px, calc(100vh - 220px), 560px);
}
.risk-free {
  max-width: 40ch;
  margin-top: 20px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.risk-free strong {
  color: var(--ink);
  font-weight: 600;
}
.risk-free a {
  color: var(--ink);
  text-underline-offset: 3px;
}

/* ── STICKY BUY BAR ──
   Slides in under the nav once the hero buy row has scrolled away,
   and moves up to the top edge whenever the nav tucks itself away. */
.sticky-buy {
  position: fixed;
  top: 66px;
  left: 0;
  right: 0;
  z-index: 190;
  background: var(--page);
  border-bottom: 1px solid var(--line);
  translate: 0 -100%;
  opacity: 0;
  pointer-events: none;
  transition:
    translate 0.3s cubic-bezier(0.2, 0.7, 0.1, 1),
    opacity 0.2s ease,
    top 0.35s cubic-bezier(0.2, 0.7, 0.1, 1);
}
.sticky-buy.visible {
  translate: 0 0;
  opacity: 1;
  pointer-events: auto;
}
.nav.nav-hidden ~ .sticky-buy {
  top: 0;
}
.sticky-buy-inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 10px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
}
.sticky-buy-name {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 16px;
}
.sticky-buy-price .moonbase-price-current {
  font-size: 18px;
}
.sticky-buy-price .moonbase-price-original {
  font-size: 18px;
}
.sticky-buy-cta {
  min-height: 40px;
  padding: 0 20px;
  font-size: 15px;
}
/* ── SECTIONS ── */
.section {
  padding-block: clamp(56px, 8vw, 104px);
  border-top: 1px solid var(--line);
}
.section-label {
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 12px;
}
.section-title {
  font-size: clamp(28px, 3.2vw, 40px);
  font-weight: 900;
  line-height: 1;
  margin-bottom: clamp(28px, 4vw, 48px);
}

/* The signal line already divides the hero from what follows. */
#how-it-works {
  border-top: 0;
}

/* ── WALKTHROUGH VIDEO ── */
/* The video sits in a dark bezel, like a monitor, so light YouTube
   thumbnails don't bleed into the light page around them. */
.video-frame {
  padding: clamp(8px, 1.1vw, 16px);
  background: #121110;
  border-radius: 10px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 1px 2px rgba(0, 0, 0, 0.12),
    0 18px 40px rgba(0, 0, 0, 0.14);
}
.video-frame iframe {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 4px;
  background: #000;
}

/* ── FEATURES ──
   Alternating rows: a feature clip on its own stage beside the
   copy, numbered so the list reads as a sequence. */
.features {
  counter-reset: feature;
}
.feature {
  counter-increment: feature;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
  padding-block: clamp(40px, 6vw, 72px);
}
.features {
  padding-top: 0;
}
.feature:first-child {
  padding-top: clamp(24px, 3vw, 40px);
}
.feature + .feature {
  border-top: 1px solid var(--line);
}
.feature--reverse {
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
}
.feature--reverse .product-stage {
  order: -1;
}
.feature .plugin-img {
  max-height: 460px;
}
/* The feature name is set large in the product's color, sitting above
   its heading rather than behind it so it stays easy to read. Pages
   whose swatch is too light to read (Delay's yellow) set --feature-word
   and --feature-dot themselves. */
.feature-word {
  margin-bottom: 10px;
  font-size: clamp(36px, 3.8vw, 54px);
  font-weight: 900;
  line-height: 0.95;
  color: var(--feature-word, var(--swatch));
}
/* Full stop in a deeper shade, added here so the copy itself stays
   plain. */
.feature-word::after {
  content: ".";
  color: var(
    --feature-dot,
    color-mix(in srgb, var(--swatch) 70%, var(--ink))
  );
}
.feature h2 {
  font-size: clamp(24px, 2.5vw, 32px);
  font-weight: 800;
  line-height: 1.08;
  max-width: 20ch;
  text-wrap: balance;
}
.feature p:not(.feature-word) {
  max-width: 46ch;
  margin-top: 20px;
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-soft);
}
@media (max-width: 800px) {
  .feature,
  .feature--reverse {
    grid-template-columns: minmax(0, 1fr);
  }
  .feature .product-stage {
    order: -1;
  }
  .feature .plugin-img {
    max-height: 400px;
  }
}

/* ── SYSTEM REQUIREMENTS ── */
.specs-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(32px, 6vw, 88px);
}
.spec {
  border-top: 1px solid var(--ink);
  padding-top: 18px;
}
.spec h3 {
  font-size: 20px;
  font-weight: 600;
  margin-bottom: 14px;
}
.spec ul {
  list-style: none;
}
.spec li {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: 16px;
  color: var(--ink-soft);
}
.specs-note {
  margin-top: 28px;
  font-size: 15px;
  color: var(--muted);
}
@media (max-width: 640px) {
  .specs-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 40px;
  }
}

/* ══ TEXT PAGES ══
   FAQ, Contact, Refund Policy, EULA and 404: the title sits in a narrow
   left column (staying in view on long pages) with the reading column
   to its right. */
.text-page {
  min-height: 72vh;
  padding: clamp(112px, 13vw, 152px) 0 clamp(72px, 9vw, 120px);
}
.text-layout {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
}
.page-head {
  position: sticky;
  top: 112px;
}
.page-head h1 {
  font-family: var(--font-display);
  font-stretch: 125%;
  font-size: clamp(32px, 3.8vw, 52px);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.page-intro {
  margin-top: 18px;
  max-width: 34ch;
  font-size: 17px;
  line-height: 1.6;
  color: var(--muted);
}
.prose {
  max-width: 68ch;
  font-size: 17px;
  line-height: 1.7;
  color: var(--ink-soft);
}
.prose > :first-child {
  margin-top: 0;
}
.prose p {
  margin-top: 18px;
}
.prose h2 {
  margin-top: 48px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.prose h2 + p {
  margin-top: 12px;
}
.prose a,
.text-link {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color 0.15s;
}
.prose a:hover,
.text-link:hover {
  text-decoration-color: currentColor;
}
.prose .lead {
  font-size: clamp(20px, 2vw, 24px);
  line-height: 1.45;
  color: var(--ink);
}
.prose .legal-disclaimer {
  font-size: 14px;
  line-height: 1.7;
  letter-spacing: 0.01em;
  color: var(--muted);
}
/* A single address worth making big: the contact email. */
.prose .big-link {
  display: inline-block;
  margin-top: 6px;
  font-size: clamp(28px, 3.6vw, 48px);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--action);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 8px;
  overflow-wrap: anywhere;
}
.prose .big-link:hover {
  color: var(--ink);
}
@media (max-width: 800px) {
  .text-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .page-head {
    position: static;
  }
}

/* ── SUBSCRIBE FORMS (newsletter band + footer) ── */
.footer-subscribe {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
/* Visibility here is Cloudflare's to control, not ours. The widget
   renders with appearance: "interaction-only", so it stays unseen
   for virtually every visitor and only paints when Turnstile
   genuinely needs the visitor to solve something. Forcing
   display: none instead meant an interactive challenge could never
   be shown or clicked. The :empty guard only suppresses the
   container before turnstile.render() fills it. */
.footer-subscribe .cf-turnstile-widget:empty {
  display: none;
}
/* Once rendered the widget is a zero width flex item; ordered last
   so its gap trails the button instead of indenting it. */
.footer-subscribe .cf-turnstile-widget {
  order: 1;
}
/* Fully JS controlled, so the visitor always sees verification
   happen even when Turnstile resolves with no visible UI. */
.footer-subscribe .subscribe-status {
  flex: 1 0 100%;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
}
.footer-subscribe input {
  min-height: 48px;
  padding: 0 16px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  outline: none;
  transition: border-color 0.15s;
}
.footer-subscribe input:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(255, 229, 0, 0.45);
}
.footer-subscribe input::placeholder {
  color: #8d8a83;
}
.footer-subscribe button {
  min-height: 48px;
  padding: 0 24px;
  border-radius: var(--radius);
  border: 1px solid var(--action);
  background: var(--action);
  color: var(--action-ink);
  cursor: pointer;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 600;
  transition: background 0.15s;
}
.footer-subscribe button:hover {
  background: var(--action-hover);
  border-color: var(--action-hover);
}
.footer-newsletter-terms {
  font-size: 13px;
  line-height: 1.6;
  color: var(--muted);
}

/* ── FOOTER ── */
.footer {
  background: var(--footer);
  color: var(--footer-text);
  padding: 72px var(--gutter) 64px;
}
.footer-top {
  max-width: var(--wrap);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  gap: 48px;
}
.footer-logo {
  display: flex;
  gap: 10px;
  font-weight: 700;
  font-size: 19px;
  letter-spacing: 0.01em;
  align-items: center;
}
.footer-copy {
  margin-top: 18px;
  color: var(--footer-muted);
  font-size: 14px;
  line-height: 1.7;
}
.footer-right {
  display: flex;
  gap: 72px;
}
.footer-links a,
.footer-socials a {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  color: var(--footer-text);
  text-decoration: none;
  font-size: 15px;
  transition: color 0.15s;
}
.footer-links a:hover,
.footer-socials a:hover {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 4px;
}
.footer-socials svg {
  flex-shrink: 0;
  fill: currentColor;
}
.footer-newsletter {
  max-width: 320px;
}
.footer-newsletter-title {
  font-weight: 600;
  margin-bottom: 14px;
}
.footer-newsletter .footer-subscribe {
  margin-bottom: 12px;
}
.footer-newsletter .footer-subscribe input {
  flex: 1 1 100%;
  background: #1f1f1f;
  border-color: var(--footer-line);
  color: var(--footer-text);
}
.footer-newsletter .footer-subscribe input:focus {
  border-color: var(--footer-muted);
}
.footer-newsletter .footer-subscribe input::placeholder {
  color: #77746d;
}
.footer-newsletter .footer-subscribe button {
  background: var(--action-on-dark);
  border-color: var(--action-on-dark);
  color: var(--action-ink);
}
.footer-newsletter .footer-subscribe button:hover {
  background: var(--action-hover);
  border-color: var(--action-hover);
}
.footer .subscribe-status {
  color: var(--footer-text);
}
.footer .footer-newsletter-terms {
  color: var(--footer-muted);
}

@media (max-width: 900px) {
  .footer-top {
    flex-direction: column;
    gap: 40px;
  }
  .footer-right {
    gap: 40px;
    flex-wrap: wrap;
  }
  .footer-newsletter {
    max-width: 420px;
  }
}
