/* Dittoday landing — standalone dark product page (ref: hilium.app).
   The reference's real language: transparent cards separated by hairline
   dividers, a floating pill nav that condenses on scroll, glassy buttons
   with glints, word-by-word blur reveals, a floating hero mock, and lots
   of air between sections. Scoped here; loads reset.css + fonts.css only.
   Apple devices render SF via -apple-system and never touch Inter. */

:root {
  --d-font: -apple-system, BlinkMacSystemFont, "SF Pro", "Inter", "Segoe UI", sans-serif;

  --d-bg: #080808;
  --d-line: #1a1a1a;
  --d-text: #e6e6e6;
  --d-muted: #808080;
  --d-faint: #4d4d4d;

  /* Five steps, nothing between them. Roles, not sizes: anything that needs
     a size picks the step that matches its job. Line height follows the step —
     1.15 for the two display sizes, 1.3 for lead, 1.5 for reading text. */
  --d-display: 48px;   /* hero headline (34 on narrow screens) */
  --d-title: 32px;     /* closing headline, policy title */
  --d-lead: 19px;      /* hero subtitle, feature title, policy headings */
  --d-body: 17px;      /* running text, the wordmark */
  --d-caption: 15px;   /* feature copy, nav links, footer */

  --d-maxw: 1200px;
  /* the column everything reads in — feature grid and footer share it */
  --d-col: 760px;

  /* Vertical rhythm. Four steps, and every vertical gap on the page comes from
     one of them, so the whole scale can be retuned per breakpoint in one place
     (see the narrow-screen block at the bottom of this file). */
  --d-gap-section: 200px;   /* between major blocks */
  --d-gap-row: 88px;        /* between feature rows */
  --d-hero-top: 116px;      /* hero, under the fixed nav */
  --d-footer-pad: 64px;
  --d-nav-h: 52px;
  --d-ease: cubic-bezier(0.4, 0, 0.2, 1);
}

/* No `scroll-behavior: smooth` here on purpose. It applies to *every* scroll
   the browser performs, including restoring position on back/forward and
   jumping to a #hash on load — those get animated, and any wheel touch while
   the animation runs leaves the page parked somewhere in between. Anchor
   clicks are smoothed in scripts/dittoday.js instead, where it is only the
   clicks. */
html {
  color-scheme: dark; /* native scrollbars and controls render dark */
  scrollbar-width: thin;
  scrollbar-color: #252525 #080808;
}

body {
  background: var(--d-bg);
  color: var(--d-text);
  font-family: var(--d-font);
  font-size: var(--d-body);
  line-height: 1.5;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

.d-wrap {
  max-width: var(--d-maxw);
  margin: 0 auto;
  padding: 0 24px;
}

/* the nav floats over the page, so any anchor landing has to clear it */
:target {
  scroll-margin-top: calc(var(--d-nav-h) + 32px);
}

/* the air between major blocks — one step of the vertical scale */
.d-spacer {
  height: var(--d-gap-section);
}

/* ─── Floating pill nav ────────────────────────────────────── */

.d-nav {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  width: 300px;
  max-width: calc(100% - 32px);
  height: var(--d-nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Right side is tighter than the left on purpose: the last link is a pill
     of its own, so its gap to the edge should equal the gap above and below it
     (9px). The brand on the left is a round icon and keeps the wider 16px. */
  padding: 0 9px 0 16px;
  border-radius: 100px;
  background: transparent;
  transition:
    background 0.4s var(--d-ease),
    backdrop-filter 0.4s var(--d-ease),
    width 0.4s var(--d-ease);
}

.d-nav.scrolled {
  width: 210px;
  background: rgba(33, 33, 33, 0.4);
  backdrop-filter: blur(60px);
  -webkit-backdrop-filter: blur(60px);
}

.d-nav__brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--d-body);
  font-weight: 600;
}

.d-nav__brand svg {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
}

/* the wordmark collapses when the nav condenses, like the reference */
.d-nav__brand span {
  transition:
    opacity 0.3s var(--d-ease),
    transform 0.3s var(--d-ease);
}

.d-nav.scrolled .d-nav__brand span {
  opacity: 0;
  transform: scale(0.3);
  width: 0;
  overflow: hidden;
}

.d-nav__links {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* The visible chip stays 34.5px so the pill keeps its proportions; the tap
   target underneath is grown to 44px, the minimum a finger can hit reliably. */
/* iOS paints its own grey rounded rectangle over any tapped link, sized to the
   element box — with the enlarged hit area below that reads as a stray box
   around the word. Suppressed here; :active below is the real feedback. */
a {
  -webkit-tap-highlight-color: transparent;
}

.d-nav__links a {
  position: relative;
  padding: 6px 12px;
  border-radius: 50px;
  font-size: var(--d-caption);
  font-weight: 500;
  white-space: nowrap;
  transition: background 0.2s ease;
}

.d-nav__links a::after {
  content: "";
  position: absolute;
  inset: -5px -2px;
}

@media (hover: hover) {
  .d-nav__links a:hover {
    background: rgba(230, 230, 230, 0.1);
  }
}

.d-nav__links a:active {
  background: rgba(230, 230, 230, 0.16);
}

/* ─── Hero ─────────────────────────────────────────────────── */

.d-hero {
  padding-top: calc(var(--d-nav-h) + var(--d-hero-top));
  text-align: center;
}

.d-hero h1 {
  max-width: 720px;
  margin: 0 auto;
  font-size: var(--d-display);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 4px rgba(8, 8, 8, 0.8);
}

/* hero entrance is STRICTLY sequenced. The title fully lands at ~1.3s
   (last word starts at 7 × 70ms and condenses for 0.8s); only then the
   subtitle rises (0.6s), and only after it the button. Shorter durations
   here so the chain stays snappy despite honest waits. */
.d-hero__sub {
  max-width: 560px;
  margin: 20px auto 0;
  font-size: var(--d-lead);
  font-weight: 500;
  line-height: 1.3;
}

.d-hero__cta {
  margin-top: 50px;
}

/* double-class selectors: the plain .reveal rule sits later in the file
   and would override these at equal specificity. No rise here — the sub
   and button condense IN PLACE out of a blur, like the title words, and
   the queue is tightened (title is readable well before its last word
   fully lands) */
.d-hero__sub.reveal,
.d-hero__cta.reveal {
  transform: none;
  filter: blur(12px);
  transition: opacity 0.6s ease, filter 0.6s ease;
}

/* the sub and the button condense together, one beat after the title */
.d-hero__sub.reveal,
.d-hero__cta.reveal {
  transition-delay: 0.9s;
}

.d-hero__sub.reveal.visible,
.d-hero__cta.reveal.visible {
  /* none, not blur(0) — a lingering filter would leave a containing block */
  filter: none;
}

/* ─── Primary button (the reference's solid white pill) ────── */

.d-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 48px;
  padding: 0 24px;
  border: 1px solid #e6e6e6;
  border-radius: 999px;
  background: #e6e6e6;
  color: #080808;
  font-size: var(--d-body);
  font-weight: 600;
  letter-spacing: -0.02em;
  white-space: nowrap;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.25);
  transition: box-shadow 0.25s ease, background 0.25s ease;
}

@media (hover: hover) {
  .d-btn:hover {
    background: #fff;
    border-color: #fff;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
  }
}

/* ─── Floating hero mock ───────────────────────────────────── */

.d-hero__media {
  margin-top: 50px;
  display: flex;
  justify-content: center;
}

@keyframes d-float {
  0%   { transform: translateY(20px); }
  50%  { transform: translateY(0); }
  100% { transform: translateY(20px); }
}

/* PLACEHOLDER frame: swap the inner .d-media for the real phone mockup /
   timelapse animation; the float + shadow stay */
.d-hero__media .d-media {
  width: min(340px, 80vw);
  aspect-ratio: 1781 / 3661;
  border-radius: 48px;
  animation: d-float 6s ease-in-out infinite;
  filter: drop-shadow(0 15px 15px rgba(0, 0, 0, 0.4));
}

.d-media {
  display: grid;
  place-items: center;
  border: 1px solid var(--d-line);
  border-radius: 20px;
  background: #0c0c0c;
  color: var(--d-faint);
  font-size: var(--d-caption);
  overflow: hidden; /* clip the clip's corners to the panel radius */
}

/* Feature clips. The phone mockup is rendered into the file itself, so the
   video is an opaque rectangle — `contain` keeps the whole frame visible and
   lets the panel's own #0c0c0c show through the letterbox instead of cropping
   the device. Render the clips on that same colour and the seam disappears. */
.d-clip {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Autoplay refused (Low Power Mode / Reduce Motion): scripts/dittoday.js flags
   the panel so the frozen poster reads as "tap to play" rather than as a bug. */
.d-media.is-blocked {
  cursor: pointer;
}

.d-media.is-blocked::after {
  content: "";
  grid-area: 1 / 1;      /* same cell as the clip, centred by place-items */
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(230, 230, 230, 0.9) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8 5v14l11-7z' fill='%230c0c0c'/%3E%3C/svg%3E") center / 24px no-repeat;
}

/* ─── Features: small clips, staggered across an 8-column grid ─ */

/* Narrow first: one feature per row, clip above its caption. */
.d-grid {
  display: grid;
  gap: var(--d-gap-row);
}

/* A 19px title does not need 1.6 leading — and at 1.4 the space it left below
   itself matched the paragraph's own line spacing, so title and text read as
   one undifferentiated block. Tighter heading, tighter body, and an explicit
   gap between them that is larger than the body's leading. */
.d-feat h3 {
  font-size: var(--d-lead);
  font-weight: 600;
  line-height: 1.3;
}

.d-feat p {
  margin-top: 8px;
  font-size: var(--d-caption);
  color: var(--d-muted);
  line-height: 1.5;
}

/* The panel is a 4:3 rectangle — a quarter shorter than a square would be —
   and the clip is sized off that height, staying square and centred inside it.
   Height drives the clip; nothing is cropped. */
.d-feat .d-media {
  --d-clip-pad: 32px;
  aspect-ratio: 4 / 3;
  padding: var(--d-clip-pad) 0;
  border: 0;
  border-radius: 16px;
  margin-bottom: 20px;
}

/* Sized off the panel's width, not `height: 100%` — a percentage height here
   resolves as indefinite, the clip keeps its own square, and `overflow: hidden`
   on the panel then cuts the bottom off. 75% is the panel's 4:3 inverted, i.e.
   its height; minus the padding twice leaves the square breathing above and
   below. Change the panel ratio and 75% changes with it. */
.d-feat .d-clip {
  width: calc(75% - var(--d-clip-pad) * 2);
  height: auto;
  aspect-ratio: 1 / 1;
}

/* Every clip is a square crop of half a phone, so one edge is a hard cut
   through the device. A 32px mask fades that edge out; which edge depends on
   the half that was kept, hence data-fade on each feature in the markup. */
.d-feat[data-fade="bottom"] .d-clip {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
}

.d-feat[data-fade="top"] .d-clip {
  -webkit-mask-image: linear-gradient(to top, #000 calc(100% - 32px), transparent);
          mask-image: linear-gradient(to top, #000 calc(100% - 32px), transparent);
}

/* The reference's tablet layout, kept at every width above 640: one feature
   per row, clip and caption side by side, and the clip changing sides row to
   row. Capping the grid at 760px is what keeps the clips small — widen this
   one number and every clip grows with it. The caption is bottom-aligned to
   the clip, so copy of different lengths grows upward and the clips stay on
   their line. */
@media (min-width: 640px) {
  .d-grid {
    max-width: var(--d-col);
    margin-inline: auto;
    gap: var(--d-gap-row);
  }

  .d-feat {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: end;
    gap: 24px;
  }

  .d-feat:nth-child(even) .d-media {
    order: 2;
  }

  .d-feat .d-media {
    margin-bottom: 0;
  }

  .d-feat__text {
    padding-bottom: 4px;
  }
}

/* ─── Closing ──────────────────────────────────────────────── */

.d-closing {
  text-align: center;
}

/* The headline assembles word by word — ten words at 70ms apart, the last one
   condensing for 0.8s, so it finishes around 1.4s. The button waits that out
   instead of arriving while the sentence is still forming, and condenses out
   of the same blur as the words above it rather than plainly fading in. */
.d-closing .reveal {
  filter: blur(12px);
  transition: opacity 0.6s ease, filter 0.6s ease;
  transition-delay: 1.2s;
}

.d-closing .reveal.visible {
  /* none, not blur(0) — a lingering filter would leave a containing block */
  filter: none;
}

.d-closing h2 {
  max-width: 640px;
  margin: 0 auto 40px;
  font-size: var(--d-title);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* ─── Footer ───────────────────────────────────────────────── */

.d-footer {
  margin-top: var(--d-gap-section);
  /* ends on the page colour, not above it — otherwise the last band of the
   footer sits lighter than everything around it and the seam shows */
  background: linear-gradient(to bottom, #000 0%, #060606 12%, #080808 25%, #0f0f0f 70%, #080808 100%);
  padding: var(--d-footer-pad) 0;
}

.d-footer .d-wrap {
  max-width: var(--d-col);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-size: var(--d-caption);
  line-height: 1.4;
  color: var(--d-faint);
}

.d-footer a {
  color: var(--d-muted);
  transition: color 0.2s ease;
}

@media (hover: hover) {
  .d-footer a:hover {
    color: var(--d-text);
  }
}

/* ─── Policy page ──────────────────────────────────────────── */

.d-policy {
  max-width: 560px;
  margin: 0 auto;
  padding: calc(var(--d-nav-h) + 96px) 24px 0;
}

.d-policy h1 {
  font-size: var(--d-title);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.d-policy__date {
  display: block;
  margin: 8px 0 48px;
  font-size: var(--d-caption);
  color: var(--d-muted);
}

.d-policy h2 {
  margin: 48px 0 12px;
  font-size: var(--d-lead);
  font-weight: 600;
  line-height: 1.3;
}

.d-policy p {
  margin-bottom: 16px;
}

.d-policy ul {
  list-style: disc;
  padding-left: 20px;
  margin-bottom: 16px;
  display: grid;
  gap: 8px;
}

.d-policy strong {
  font-weight: 600;
  color: var(--d-text);
}

.d-policy p,
.d-policy li {
  color: var(--d-muted);
}

.d-policy a {
  color: var(--d-text);
  text-decoration: underline;
  text-decoration-color: var(--d-faint);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.2s ease;
}

@media (hover: hover) {
  .d-policy a:hover {
    text-decoration-color: var(--d-text);
  }
}

/* ─── Reveals ──────────────────────────────────────────────── */

/* blocks fade into view, in place (scripts/dittoday.js flips .visible).
   No rise: a 100px travel read as the whole page sliding upward, and it was
   worst exactly when you were reading something else on screen. */
.reveal {
  opacity: 0;
  transition: opacity 0.6s ease;
}

/* Blocks that were already scrolled past when the page loaded (a refresh
   halfway down) are marked by scripts/dittoday.js and appear with no
   animation at all — they must read as having always been there. */
.reveal.no-anim,
.blur-reveal.no-anim,
.blur-reveal.no-anim .w {
  transition: none;
}

.reveal.visible {
  opacity: 1;
}

/* the feature blocks fade a touch slower than the hero — they are large and
   arrive one at a time, so a longer curve reads as calm rather than laggy */
.d-grid .reveal {
  transition-duration: 0.9s;
}

/* headline words condense out of a blur, one beat apart (--i inline) */
.blur-reveal .w {
  display: inline-block;
  filter: blur(12px);
  opacity: 0;
  transform: translateY(20px);
  transition:
    filter 0.8s cubic-bezier(0.25, 0.4, 0.25, 1),
    opacity 0.8s cubic-bezier(0.25, 0.4, 0.25, 1),
    transform 0.8s cubic-bezier(0.25, 0.4, 0.25, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.blur-reveal.visible .w {
  filter: blur(0);
  opacity: 1;
  transform: translateY(0);
}

/* ─── Mobile ───────────────────────────────────────────────── */

@media (max-width: 809px) {
  .d-hero h1 {
    font-size: 34px;
  }
}

/* Below 640 the features stop sitting side by side and stack, so the vertical
   scale steps down with them. Everything vertical reads from these four, so
   this block is the only place a phone's spacing is tuned — no gap is left
   hard-coded further up. */
@media (max-width: 639px) {
  :root {
    --d-gap-section: 112px;
    --d-gap-row: 56px;
    --d-hero-top: 72px;
    --d-footer-pad: 48px;
  }

  .d-hero__cta {
    margin-top: 36px;
  }

  /* On a phone the panel is the full column, so a 4:3 box would leave the clip
     stranded in the middle with wide gutters. Let the panel take its height
     from the clip instead and give the clip the column minus its padding. */
  .d-feat .d-media {
    aspect-ratio: auto;
  }

  .d-feat .d-clip {
    width: calc(100% - var(--d-clip-pad) * 2);
  }

  .d-closing h2 {
    margin-bottom: 32px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}
