/* ==========================================================================
   Deskrune — Homepage v2 IMPECCABLE pass
   File: /assets/v2-home-v20260508b.css
   Loaded LAST in <head>, so every rule here is the final word.

   Reuses the canonical --ds-* tokens from theme-v20260508a.css so every
   change is automatically dark-mode-parity. No new color literals are
   introduced except brand orange #c9613f which is already canon.

   Each block is commented with the principle it serves.
   ========================================================================== */


/* --------------------------------------------------------------------------
   01. Universal :focus-visible — brand-orange, 2px, 2px offset, ALL routes.
   Principle: keyboard users get a single, calm, branded focus indicator.
   The browser default (mostly black or blue) breaks visual hierarchy.
   We keep :focus (no -visible) suppressed for mouse, but :focus-visible
   always gets the ring — link, button, input, summary, [tabindex].
   -------------------------------------------------------------------------- */
:where(a, button, input, select, textarea, summary, [tabindex]):focus {
  outline: none;
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid #c9613f;
  outline-offset: 2px;
  border-radius: 3px;
}
/* Inputs need a different offset to stay clear of their border */
:where(input, textarea, select):focus-visible {
  outline-offset: 1px;
}


/* --------------------------------------------------------------------------
   02. Skip-to-content link — visible on focus, not just SR.
   Principle: keyboard users should SEE the affordance, not feel it.
   Was visually hidden permanently; impeccable means it materializes
   into the viewport top-left when keyboarded to.
   -------------------------------------------------------------------------- */
.skip-to-content {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 10000;
  padding: 10px 16px;
  background: var(--ds-ink, #1A1814);
  color: var(--ds-bg, #FAF7F2);
  border-radius: 6px;
  text-decoration: none;
  font-family: var(--ds-font-sans, system-ui, sans-serif);
  font-weight: 600;
  font-size: 14px;
  transform: translateY(-200%);
  transition: transform 180ms cubic-bezier(0.45, 0, 0.55, 1);
}
.skip-to-content:focus,
.skip-to-content:focus-visible {
  transform: translateY(0);
  outline: 2px solid #c9613f;
  outline-offset: 2px;
}


/* --------------------------------------------------------------------------
   03. Per-property transitions on interactive elements.
   Principle: `transition: all` is the wildcard nobody asked for. It
   re-triggers on layout-affecting properties and burns paint budget.
   Each interactive element gets named-property transitions only.
   -------------------------------------------------------------------------- */
.hero-action,
.tool-card,
.audience-card,
.afm-card,
.product-rich,
.quote-card,
nav .links a,
nav .brand,
.cmdk-trigger,
.theme-toggle {
  transition:
    background-color 180ms cubic-bezier(0.45, 0, 0.55, 1),
    border-color 180ms cubic-bezier(0.45, 0, 0.55, 1),
    color 180ms cubic-bezier(0.45, 0, 0.55, 1),
    transform 220ms cubic-bezier(0.45, 0, 0.55, 1),
    box-shadow 220ms cubic-bezier(0.45, 0, 0.55, 1);
}


/* --------------------------------------------------------------------------
   04. Restrained hover micro-motion — 1px lift, no overshoot, no bounce.
   Principle: bounce/overshoot easing is hype motion. Sinusoidal
   ease-in-out reads as competence. 1px lift is enough to register;
   anything larger feels like a button trying too hard.
   -------------------------------------------------------------------------- */
@media (hover: hover) {
  .tool-card:hover,
  .audience-card:hover,
  .afm-card:hover,
  .product-rich:hover {
    transform: translateY(-1px);
    box-shadow: var(--ds-shadow-2, 0 8px 24px rgba(26, 24, 20, 0.08));
  }
  .hero-action.primary:hover {
    transform: translateY(-1px);
  }
  .hero-action.secondary:hover {
    border-color: var(--ds-rule-strong, #CFC6B6);
  }
}


/* --------------------------------------------------------------------------
   05. Active-state press feedback — sub-pixel sink.
   Principle: pressed buttons should *feel* pressed. 0.5px sink, no
   color flash, no scale wobble.
   -------------------------------------------------------------------------- */
.hero-action:active,
button:active,
.tool-card:active,
.audience-card:active,
.afm-card:active,
.product-rich:active {
  transform: translateY(0.5px);
}


/* --------------------------------------------------------------------------
   06. Image aspect-ratio reservation — kill CLS on lazy-loaded covers.
   Principle: layout shift > 0.05 is reading-jarring. Reserving the
   height before the image decodes prevents the "scroll, jump back" bug.
   Library cover images already have width/height attrs in markup, but
   we double-belt with explicit aspect-ratio so any future generator
   that omits the attrs is still CLS-clean.
   -------------------------------------------------------------------------- */
.products-rich .img,
.product-rich .img {
  aspect-ratio: 3 / 4;
  background: var(--ds-surface-2, #F2EDE3);
  overflow: hidden;
}
.products-rich .img img,
.product-rich .img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}


/* --------------------------------------------------------------------------
   07. Hero typography rhythm — Fraunces serif headline, opsz tuned.
   Principle: magazine-grade hierarchy comes from font-feature-settings,
   not just size. Fraunces optical-size axis should be set explicitly
   for display sizes so the strokes stay confident.
   We do NOT change the headline copy — only its tracking and rendering.
   -------------------------------------------------------------------------- */
#vp-h1,
.hero-vp h1 {
  font-family: var(--ds-font-serif, Fraunces, Georgia, serif);
  font-feature-settings: "ss01" on, "kern" on, "liga" on;
  font-variation-settings: "opsz" 144, "SOFT" 50, "WONK" 0;
  letter-spacing: -0.018em;
  text-wrap: balance;
}

/* The lede directly below the H1 needs a measure cap so eye-travel from
   end-of-line back to start-of-line stays inside ~65 characters. */
.hero-vp .hero-lede {
  max-width: 58ch;
  text-wrap: pretty;
}


/* --------------------------------------------------------------------------
   08. Section headline rhythm — h2s use Fraunces, balanced wrap.
   Principle: every h2 across the homepage shares the same display
   treatment. Without text-wrap: balance, headlines orphan their last
   word; balance prevents widow lines on flexible widths.
   -------------------------------------------------------------------------- */
.section h2 {
  font-family: var(--ds-font-serif, Fraunces, Georgia, serif);
  font-feature-settings: "kern" on, "liga" on;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.section .lede,
.section p.lede {
  text-wrap: pretty;
  max-width: 62ch;
}


/* --------------------------------------------------------------------------
   09. Scroll-driven reveals via IntersectionObserver-friendly classes.
   Principle: scroll-jacking is hostile. We only fade-in elements as
   they enter the viewport, never hijack the scroll. The observer is
   wired in /assets/dramatic-effects-v20260508a.js (already loaded).
   We add a CSS-only fallback so even without JS the content is visible.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal],
  [data-reveal-stagger] > * {
    opacity: 0;
    transform: translateY(8px);
    transition:
      opacity 360ms cubic-bezier(0.45, 0, 0.55, 1),
      transform 360ms cubic-bezier(0.45, 0, 0.55, 1);
  }
  [data-reveal].in-view,
  [data-reveal-stagger].in-view > *,
  [data-reveal-stagger] > *.in-view {
    opacity: 1;
    transform: translateY(0);
  }
}
/* JS-disabled / no-JS fallback — make sure content is always readable. */
.no-js [data-reveal],
.no-js [data-reveal-stagger] > * {
  opacity: 1 !important;
  transform: none !important;
}


/* --------------------------------------------------------------------------
   10. prefers-reduced-motion respected on every animation.
   Principle: reduced-motion users should still see the brand, just
   without movement. We strip all transforms and transitions and
   collapse animation durations to a tiny 1ms (so animationend still
   fires, JS that listens won't deadlock).
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal],
  [data-reveal-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
  }
  .hero-action:hover,
  .tool-card:hover,
  .audience-card:hover,
  .afm-card:hover,
  .product-rich:hover {
    transform: none !important;
  }
}


/* --------------------------------------------------------------------------
   11. Link state polish — underline-on-hover, never on body links by
   default; CTA text gets a subtle underline-offset for legibility.
   Principle: we are a reading brand. Underlines should look intentional
   and not collide with descenders. text-underline-offset 3px clears.
   -------------------------------------------------------------------------- */
.section p a,
.brand-strip a,
footer.minimal a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in oklch, currentColor 40%, transparent);
}
.section p a:hover,
.brand-strip a:hover,
footer.minimal a:hover {
  text-decoration-color: currentColor;
}
/* Cards already act as links — never underline them. */
.tool-card,
.audience-card,
.afm-card,
.product-rich {
  text-decoration: none;
}


/* --------------------------------------------------------------------------
   12. Tinted-neutral border + selection — no flat #aaa grays.
   Principle: a flat gray on a warm cream background reads as cold.
   We use color-mix on the canonical cream/ink to derive a neutral
   that always carries 4% of the brand-orange — quietly tinted.
   Selection highlight uses the brand soft tint for cohesion.
   -------------------------------------------------------------------------- */
::selection {
  background-color: color-mix(in oklch, #c9613f 22%, transparent);
  color: var(--ds-ink, #1A1814);
}
:root[data-theme="dark"] ::selection {
  background-color: color-mix(in oklch, #c9613f 32%, transparent);
  color: var(--ds-ink, #F0E9DC);
}

/* Tinted hairline rules — replace any flat grays defaulted by the cascade. */
.section + .section,
.brand-strip,
footer.minimal {
  border-top-color: color-mix(in oklch, var(--ds-rule, #E8E2D7) 92%, #c9613f 8%);
}


/* --------------------------------------------------------------------------
   13. Sale banner countdown — defensive type sizing + offline state.
   Principle: the banner is the first thing a buyer sees. If JS fails
   the "—" placeholder must look intentional, not broken. We give it
   a min-width so layout doesn't reflow when the timer populates.
   -------------------------------------------------------------------------- */
.deskrune-countdown {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" on;
  min-width: 7.5ch;
  display: inline-block;
  text-align: center;
}


/* --------------------------------------------------------------------------
   14. Form input — readable on cream, generous touch target.
   Principle: 44px minimum touch target (WCAG 2.5.5). The signup
   email input is the primary list-growth funnel; cramped inputs
   on mobile cost conversions.
   -------------------------------------------------------------------------- */
#deskrune-signup-email {
  min-height: 44px;
  padding-block: 12px;
  padding-inline: 14px;
  font-size: 16px; /* 16px prevents iOS zoom-on-focus */
  border: 1px solid var(--ds-rule-strong, #CFC6B6);
  border-radius: 6px;
  background: var(--ds-surface, #FFFFFF);
  color: var(--ds-ink, #1A1814);
}
#deskrune-signup-email:focus-visible {
  border-color: #c9613f;
  outline: 2px solid #c9613f;
  outline-offset: 1px;
}
#deskrune-signup button[type="submit"] {
  min-height: 44px;
  padding-block: 12px;
  padding-inline: 22px;
}


/* --------------------------------------------------------------------------
   15. AFM cluster nodes — keyboard focus visibility on SVG <a>.
   Principle: SVG anchors get no default focus ring on most browsers.
   The cluster diagram is interactive and must be keyboardable.
   -------------------------------------------------------------------------- */
.afm-node:focus-visible circle {
  stroke: #c9613f;
  stroke-width: 3;
}
.afm-node {
  cursor: pointer;
}
.afm-node text {
  pointer-events: none;
}


/* --------------------------------------------------------------------------
   16. Reduce-motion override for the SVG cluster's pulsing edges.
   Principle: pulse animations on scaling SVG elements are dizzying
   for vestibular-sensitive users. Already covered by the global
   reduced-motion block above, but we name the cluster explicitly
   to be sure no future @keyframes leaks past.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .afm-cluster svg *,
  .aurora-stage,
  .hero-anim-bg {
    animation: none !important;
  }
}
