/* modou dsp — Home page
   Section order is the brand narrative (see front-page.php). Shared
   rhythm: .section-head for the big claim, .section-sub for the line
   under it, .eyebrow for the label above. */

.section-head { font-size: var(--text-2xl); line-height: 1.12; letter-spacing: -0.015em; margin: 0.4rem 0 var(--space-sm); }
.section-head .accent { color: var(--accent-mint); }
.section-sub { color: var(--text-muted); max-width: 60ch; margin: 0 0 var(--space-lg); }

/* ── 01 HERO ─────────────────────────────────────────────────────────
   Statement left, framed 3D gallery right.

   The clips are framed, not full-bleed: a plugin GUI used as a page
   background has to be blurred and darkened so heavily to keep text
   legible that the product stops being visible. Inside a frame it can
   be shown sharp and at full contrast, which is the whole point. */

.hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  align-items: center;
  gap: var(--space-xl);
  max-width: 1320px;
  margin-inline: auto;
  padding: calc(var(--space-section) + 1rem) var(--space-lg) var(--space-section);

  /* Contains the ::before glow below, which is deliberately wider than
     this box (inset -25% each side = ±330px at the 1320px max-width).
     Left overspill is harmless; the right-hand 330px was pushing the
     document to 1710px inside a 1440px viewport and putting a horizontal
     scrollbar on every page of the site.

     `clip`, not `hidden`, and on one axis only:
       - `hidden` would make this a scroll container, and a scroll
         container clips nothing while breaking `position: sticky` on any
         descendant — the same reason `body { overflow-x: hidden }` is the
         wrong fix here, since the site header is sticky.
       - `clip` clips without creating a scrollport, and unlike `hidden`
         it can be set on one axis while the other stays `visible`, so the
         3D gallery keeps its vertical shadow spill.
     Safari below 16 ignores `clip` and simply keeps the old overspill —
     a cosmetic scrollbar on an old browser, not a broken layout. */
  overflow-x: clip;
}
.hero::before {
  content: "";
  position: absolute; inset: -15% -25% auto -25%; height: 95%;
  background: radial-gradient(45% 55% at 35% 10%, color-mix(in srgb, var(--accent-mint) 12%, transparent), transparent 70%);
  pointer-events: none; z-index: -1;
}

/* Set flush against the gallery, not against the page gutter.
   Every block in this column is width-constrained (18ch on the headline,
   44ch on the lede), so aligning left put the ragged edge next to the
   product and left a dead gap between the sentence and the thing it is
   describing. Reversed: hard edge toward the frame, ragged edge outward.

   align-items rather than `margin-left: auto` on each child, so a block
   added later inherits the alignment instead of needing to remember it. */
.hero-copy {
  text-align: right;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.hero h1 {
  /* Deliberately below --text-hero: this headline is two full sentences,
     and at the global hero size the second one broke with a single word
     ("need.") stranded on its own line. */
  font-size: clamp(2.2rem, 1.3rem + 3.1vw, 3.6rem);
  line-height: 1.06;
  letter-spacing: -0.03em;
  margin: 0 0 var(--space-md);
  max-width: 18ch;
  text-wrap: balance;
}
.hero h1 .accent { color: var(--accent-mint); }
.hero p.lede {
  color: var(--text-muted);
  font-size: var(--text-lg);
  max-width: 44ch;
  margin: 0;
}
.hero-claim {
  margin: var(--space-md) 0 0;
  font-size: var(--text-sm);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-mint);
}
.hero-ctas { display: flex; justify-content: flex-end; gap: var(--space-sm); margin-top: var(--space-lg); flex-wrap: wrap; }

/* ── 3D framed gallery ─────────────────────────────────────────────── */
.hero-stage { perspective: 1400px; perspective-origin: 50% 50%; }

.hero-deck {
  /* Pointer script writes these; the defaults are the resting pose, so
     the frame is correctly angled with no JS at all. */
  --px: 0;
  --py: 0;
  transform:
    rotateY(calc(-9deg + var(--px) * 7deg))
    rotateX(calc(3deg + var(--py) * 5deg));
  transform-style: preserve-3d;
  transition: transform 350ms var(--ease-out-expo);
  will-change: transform;
}

.hero-frame {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: var(--bg-charcoal);
  border: 1px solid color-mix(in srgb, var(--text-primary) 14%, transparent);
  box-shadow:
    0 50px 100px -40px rgba(0, 0, 0, 0.9),
    0 0 0 1px rgba(0, 0, 0, 0.4),
    0 0 90px -50px color-mix(in srgb, var(--accent-mint) 55%, transparent);
}

/* Fixed aspect so the frame never resizes between slides — the clips have
   different native ratios (1.33 to 1.76) and a frame that jumps size on
   every transition reads as a bug. cover crops instead. */
.gallery { position: relative; aspect-ratio: 16 / 10; }

.slide {
  position: absolute; inset: 0; margin: 0;
  opacity: 0;
  transform: scale(1.015);
  transition: opacity 700ms var(--ease-out-expo), transform 700ms var(--ease-out-expo);
  pointer-events: none;
}
.slide.is-active { opacity: 1; transform: scale(1); pointer-events: auto; }
.slide .slide-video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Caption bar: which processor you're looking at, and the picker */
.frame-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border-overlay);
  background: color-mix(in srgb, var(--bg-obsidian) 80%, transparent);
  backdrop-filter: blur(12px);
}
.frame-name { display: flex; align-items: center; gap: 0.55rem; font-size: var(--text-sm); font-weight: 600; }
.frame-name .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--product-accent, var(--accent-mint));
  box-shadow: 0 0 10px var(--product-accent, var(--accent-mint));
  transition: background var(--duration-normal), box-shadow var(--duration-normal);
}
.frame-name:hover .label { color: var(--accent-mint); }

.frame-dots { display: flex; gap: 0.4rem; }
.gdot {
  width: 22px; height: 4px; border-radius: 2px; border: 0; padding: 0;
  background: color-mix(in srgb, var(--text-primary) 22%, transparent);
  cursor: pointer;
  transition: background var(--duration-fast), width var(--duration-normal) var(--ease-out-expo);
}
.gdot:hover { background: color-mix(in srgb, var(--text-primary) 45%, transparent); }
.gdot.is-active { background: var(--accent-mint); width: 30px; }

.loop-video { display: block; width: 100%; height: auto; background: var(--bg-obsidian); }

@media (prefers-reduced-motion: reduce) {
  .hero-deck { transition: none; }
  .slide { transition: opacity 200ms linear; transform: none; }
  .slide.is-active { transform: none; }
}

/* ── 01 CHOICES ──────────────────────────────────────────────────────
   The ecosystem shown as a palette, not a burden. Categories we don't
   build for stay perfectly legible — dimming them would reintroduce the
   "your other plugins are the problem" message this section exists to
   avoid. Ours are simply marked. */

.choice-palette {
  list-style: none; margin: var(--space-lg) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.6rem;
}
.choice-palette .chip {
  font-family: var(--font-mono); font-size: var(--text-sm);
  padding: 0.6rem 1rem; border-radius: var(--radius-pill);
  border: 1px solid var(--border-overlay);
  color: var(--text-muted);
}
.choice-palette .chip.is-ours {
  border-color: var(--accent-mint);
  color: var(--accent-mint);
  background: color-mix(in srgb, var(--accent-mint) 8%, transparent);
}
.choices-note { margin: var(--space-lg) 0 0; font-size: var(--text-lg); color: var(--text-primary); }

/* ── 02 THE STANDARD ─────────────────────────────────────────────── */

.permissions { list-style: none; margin: var(--space-lg) 0 0; padding: 0; display: grid; gap: 0.5rem; max-width: 40ch; }
.permissions li {
  font-size: var(--text-lg); color: var(--text-muted);
  padding-left: 1.6rem; position: relative;
}
.permissions li::before {
  content: "✓"; position: absolute; left: 0;
  color: var(--accent-mint); font-size: var(--text-base);
}
.permissions-turn { margin: var(--space-md) 0 0; color: var(--text-faint); }

.standard-line {
  margin: var(--space-md) 0 var(--space-md);
  padding: 0 0 0 var(--space-md);
  border-left: 3px solid var(--accent-mint);
  font-size: var(--text-2xl);
  line-height: 1.12;
  letter-spacing: -0.02em;
  font-weight: 700;
  max-width: 22ch;
}
.standard-line .accent { color: var(--accent-mint); display: block; }
.standard-body { color: var(--text-muted); max-width: 62ch; margin: 0; }

/* ── 04 PRODUCTS ────────────────────────────────────────────────── */

.products { padding-bottom: 0; }
.product-story { padding: var(--space-xl) var(--space-lg); border-top: 1px solid var(--border-overlay); }
.product-story-inner { max-width: 1180px; margin-inline: auto; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-xl); align-items: center; }
.product-story.is-reversed .product-story-visual { order: -1; }
.product-kicker { font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--product-accent); margin: 0 0 0.6rem; }
.product-hook { font-size: var(--text-xl); line-height: 1.18; letter-spacing: -0.015em; margin: 0 0 var(--space-md); max-width: 20ch; }

.story-row { margin-bottom: var(--space-sm); }
.story-label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-faint); margin: 0 0 0.3rem; }
.story-row p:not(.story-label) { color: var(--text-muted); margin: 0; }

/* The one-job line carries the "enough of its kind" claim, so it gets
   weight the other rows don't. */
.story-settles .settles-line {
  color: var(--text-primary) !important;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  padding: 0.5rem 0.8rem;
  border-left: 2px solid var(--product-accent);
  background: color-mix(in srgb, var(--product-accent) 7%, transparent);
  border-radius: 0 6px 6px 0;
}

.story-chain { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; margin: var(--space-md) 0; }
.story-chain .node {
  font-size: var(--text-xs); padding: 0.3rem 0.55rem; border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--product-accent) 35%, var(--border-overlay));
  color: var(--product-accent);
}
.story-chain .sep { color: var(--text-faint); }
.story-link { font-size: var(--text-sm); font-weight: 600; color: var(--product-accent); }
.story-link:hover { text-decoration: underline; }

.product-story-visual { border-radius: var(--radius-card); overflow: hidden; border: 1px solid var(--border-overlay); }
.product-story-visual img,
.product-story-visual .loop-video { width: 100%; display: block; }

/* ── 05 TECHNOLOGY ──────────────────────────────────────────────── */

.tech-chain {
  list-style: none; margin: var(--space-xl) 0 0; padding: 0;
  display: flex; align-items: stretch; gap: var(--space-sm); flex-wrap: wrap;
}
.tech-chain .chain-node {
  flex: 1; min-width: 190px;
  padding: var(--space-md);
  border-radius: var(--radius-card);
  border: 1px solid var(--border-overlay);
  background: var(--bg-charcoal);
  display: flex; flex-direction: column; gap: 0.4rem;
}
.tech-chain .code { font-size: var(--text-xs); color: var(--accent-cyan); }
.tech-chain .name { font-size: var(--text-lg); font-weight: 700; letter-spacing: -0.01em; }
.tech-chain .what { font-size: var(--text-sm); color: var(--text-muted); }
.tech-chain .chain-sep { display: flex; align-items: center; color: var(--text-faint); }

/* ── 04b PRODUCTS — the rest, after the lead story ─────────────────
   Compact by design. The lead story above already spent a full screen
   making the argument; repeating that rhythm four more times is how a
   landing page turns into a catalogue. These are scannable: one visual,
   one name, one job. */

.home-products {
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: var(--space-lg);
}

.home-product-link {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  text-decoration: none;
  color: inherit;
}

.home-product-visual {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 8 / 5;              /* matches the modou-card crop */
  border-radius: var(--radius-card);
  border: 1px solid var(--border-overlay);
  background: var(--bg-charcoal);
  overflow: hidden;
  transition: border-color .18s ease, transform .18s var(--ease-out-expo);
}
/* `contain`, not `cover`.
   These are plugin interfaces, and the reason they are on the page at
   all is so the interface can be seen. Cropping a 16:10 tile out of
   CYANO CH — which is taller than it is wide, 1030×1186 — throws away
   more than half the channel strip and leaves a band of meters that
   means nothing. Letterboxing against the tile's own background costs a
   little empty space and keeps the product visible, which is the whole
   point of showing it. */
.home-product-visual img,
.home-product-visual .loop-video {
  width: 100%; height: 100%;
  object-fit: contain;
  padding: 6px;
  box-sizing: border-box;
  display: block;
}
/* object-fit applies to the poster as well as the frames, so a portrait
   clip letterboxes the same way before and after it starts playing —
   no jump at the moment the video takes over. */
.home-product-visual .loop-video { background: transparent; }

/* Typographic stand-in when a product has no screenshot yet. Tinted with
   the product's own accent so the row still reads as a set rather than
   as one broken tile. */
.home-product-mark {
  font-size: var(--text-sm);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--product-accent);
  padding: 0 1rem;
  text-align: center;
  background:
    radial-gradient(70% 90% at 50% 110%,
      color-mix(in srgb, var(--product-accent) 16%, transparent), transparent 70%);
  inset: 0;
  position: absolute;
  display: flex; align-items: center; justify-content: center;
}

.home-product-name { font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--product-accent); }
.home-product-cat { color: var(--text-faint); }
.home-product-line { font-size: var(--text-sm); color: var(--text-muted); line-height: 1.5; }

.home-product-link:hover .home-product-visual {
  border-color: color-mix(in srgb, var(--product-accent) 55%, var(--border-overlay));
  transform: translateY(-2px);
}
.home-product-link:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 4px;
  border-radius: var(--radius-card);
}

@media (prefers-reduced-motion: reduce) {
  .home-product-visual { transition: none; }
  .home-product-link:hover .home-product-visual { transform: none; }
}

/* ── 06 CLOSING ─────────────────────────────────────────────────── */

.closing { text-align: center; padding-block: var(--space-section); }
.closing-line { font-size: var(--text-xl); line-height: 1.18; letter-spacing: -0.015em; margin: 0 auto var(--space-lg); max-width: 32ch; }
.closing-line .dim { color: var(--text-faint); }
.closing-line .accent { color: var(--accent-mint); }
/* The how-to-start paragraph. Set quieter and narrower than the line
   above it on purpose: it is practical instruction, not another claim,
   and the page has just finished saying it will stop arguing. */
.closing-trial {
  font-size: var(--text-sm);
  color: var(--text-faint);
  max-width: 54ch;
  margin-inline: auto;
}

.closing-mark { font-size: var(--text-sm); letter-spacing: 0.3em; text-transform: uppercase; color: var(--text-muted); margin: 0 0 0.4rem; }
/* Set as a signature, not a declaration.
   The sentence stays — it is the standard the products are held to — but
   at display weight above the buttons it was the loudest thing on the
   page, which is the opposite of the intended register. Under the brand
   mark, one step down in size and weight, it reads as a sign-off. The
   place it is allowed to be emphatic is section 02, where it arrives
   properly qualified. */
.closing-claim { font-size: var(--text-lg); font-weight: 600; letter-spacing: -0.01em; color: var(--text-muted); margin: 0 0 var(--space-lg); }
.closing-ctas { justify-content: center; }

/* ── Responsive ─────────────────────────────────────────────────── */
@media (max-width: 980px) {
  /* Stack the hero: a 3D-angled frame needs horizontal room the viewport
     no longer has, and an angled card in a narrow column reads as a bug. */
  .hero { grid-template-columns: 1fr; gap: var(--space-lg); text-align: left; }
  /* Once the frame is below the copy there is no edge to sit against, and
     right-aligned prose across a full-width column reads as a mistake. */
  .hero-copy { text-align: left; align-items: flex-start; }
  .hero-ctas { justify-content: flex-start; }
  .hero-stage { perspective: none; }
  .hero-deck { transform: none; }
  .hero h1 { max-width: 100%; }

  .product-story-inner { grid-template-columns: 1fr; }
  .product-story.is-reversed .product-story-visual { order: 0; }
}
@media (max-width: 620px) {
  .practice-list li { grid-template-columns: 1fr; gap: 0.2rem; }
  .tech-chain .chain-sep { display: none; }
}
