/* ==========================================================================
   Hero (home and download)
   ========================================================================== */

/* Clipped sideways only: the bloom is wider than a phone. Not isolated,
   and no z-index on .hero-atmosphere: the light bloom multiplies onto the
   ambient field, which it can only reach if no stacking context sits
   between them (every stacking context is an isolated group). */
.hero {
  position: relative;
  padding: clamp(40px, 7vw, 88px) 0 clamp(56px, 8vw, 96px);
  text-align: center;
  overflow-x: clip;
}

.hero-atmosphere {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}
.hero-bloom,
.hero-effect { z-index: -1; }
.hero-effect {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* Particles fade out at the bottom instead of being cut off there. */
  -webkit-mask-image: linear-gradient(black calc(100% - 120px), transparent);
          mask-image: linear-gradient(black calc(100% - 120px), transparent);
}

/* The boot splash's bloom, centred on the device cluster, s = its short
   side. The box is 2s square so none of the three circles is cut by its
   edge (the largest reaches 0.95s from the centre); the centre sits where
   a 2s by s box 40px off the hero's bottom would put it. The mask fades it
   out over the hero's last 120px: left to spill, it sat under the next
   section's eyebrow (4.49:1 at 768). Static, never pointer driven. */
.hero-bloom {
  --s: min(62vw, 720px);
  position: absolute;
  left: 50%;
  bottom: calc(40px - var(--s) * .5);
  width: calc(var(--s) * 2);
  height: calc(var(--s) * 2);
  translate: -50% 0;
  -webkit-mask-image: linear-gradient(to top, transparent calc(var(--s) * .5 - 40px), black calc(var(--s) * .5 + 80px));
          mask-image: linear-gradient(to top, transparent calc(var(--s) * .5 - 40px), black calc(var(--s) * .5 + 80px));
  background:
    radial-gradient(calc(var(--s) * .55) calc(var(--s) * .55) at 50% 50%, color-mix(in srgb, var(--violet) 40%, transparent), color-mix(in srgb, var(--violet) 13%, transparent) 50%, transparent 100%),
    radial-gradient(calc(var(--s) * .55) calc(var(--s) * .55) at calc(50% - var(--s) * .34) calc(50% - var(--s) * .40), color-mix(in srgb, var(--blue) 18%, transparent), transparent 100%),
    radial-gradient(calc(var(--s) * .60) calc(var(--s) * .60) at calc(50% + var(--s) * .30) calc(50% + var(--s) * .34), color-mix(in srgb, var(--teal) 24%, transparent), transparent 100%);
}
/* Light: the dark recipe at .55, drawn opaque toward white and multiplied
   onto the field. A translucent gradient over a light ground bands in
   rings (its alpha is stored in 8 bits and never dithered, and each alpha
   step there moves the ground a whole level); opaque gradients are
   dithered, and white is multiply's identity, so the box has no edge. */
:root[data-theme='light'] .hero-bloom {
  mix-blend-mode: multiply;
  background:
    radial-gradient(calc(var(--s) * .55) calc(var(--s) * .55) at 50% 50%, color-mix(in srgb, var(--violet) 22%, white), color-mix(in srgb, var(--violet) 7.15%, white) 50%, white 100%),
    radial-gradient(calc(var(--s) * .55) calc(var(--s) * .55) at calc(50% - var(--s) * .34) calc(50% - var(--s) * .40), color-mix(in srgb, var(--blue) 9.9%, white), white 100%),
    radial-gradient(calc(var(--s) * .60) calc(var(--s) * .60) at calc(50% + var(--s) * .30) calc(50% + var(--s) * .34), color-mix(in srgb, var(--teal) 13.2%, white), white 100%);
  background-blend-mode: multiply;
}

.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* A logotype: static full-strength gradient, halo bound to the glyphs.
   drop-shadow, not text-shadow, because clipped text has no fill for a
   text-shadow to sit behind. */
.hero-wordmark {
  margin: 0;
  font: 800 var(--step-display)/.95 var(--font);
  letter-spacing: var(--track-display);
  background: var(--wordmark-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 4px 20px rgb(0 0 0 / .34)) drop-shadow(0 1px 7px rgb(0 0 0 / .28));
}
:root[data-theme='light'] .hero-wordmark { filter: drop-shadow(0 3px 14px rgb(0 0 0 / .18)); }

/* 42ch rather than 34: the one sentence stays on one line from tablets up. */
.hero-tagline {
  max-width: 42ch;
  margin: 18px auto 0;
  font: 400 var(--step-1)/1.45 var(--font);
  color: var(--text-soft);
  text-wrap: balance;
}

.hero .hero-actions,
.cta .hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 12px 24px;
  margin: 32px 0 0;
}
.hero .hero-actions { align-self: stretch; }
.hero .hero-actions .btn-lg { min-width: 200px; }

.hero-facts {
  margin: 20px 0 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 10px;
  font: 500 var(--step--1)/1.4 var(--font);
  color: var(--ink-2);
}
.hero .hero-facts span { margin: 0; opacity: 1; }
.hero-fact { display: inline-flex; align-items: center; gap: 5px; }
.hero-fact svg { width: 14px; height: 14px; flex: none; color: var(--ink-2); }
.hero-fact-sep { opacity: .6; }

@media (max-width: 559.98px) {
  .hero .hero-actions,
  .cta .hero-actions { flex-direction: column; gap: 16px; }
  .hero .hero-actions .btn,
  .cta .hero-actions .btn { width: 100%; max-width: 320px; }
}

@media (prefers-reduced-motion: no-preference) {
  .hero-wordmark { animation: hero-rise var(--dur-entrance) var(--ease-out) both; }
}
@keyframes hero-rise {
  from { opacity: 0; translate: 0 14px; }
}

/* --------------------------------------------------------------------------
   The device cluster: MacBook, iPad and iPhone in one locked aspect box,
   each frame a share of the stage so the cluster scales as one object.
   The shares keep the handhelds near their real size against the laptop's
   body (the MacBook frame is wider than its base).
   -------------------------------------------------------------------------- */
.hero-device-stage {
  position: relative;
  width: min(960px, 88vw);
  aspect-ratio: 760 / 460;
  margin: clamp(40px, 6vw, 72px) auto 0;
}
.hero-device {
  position: absolute;
  top: 2%;
  left: 50%;
  width: 60%;
  transform: translateX(-50%);
}
.hero-device.is-ipad {
  top: auto;
  bottom: 0;
  left: 2%;
  width: 27%;
  transform: none;
  z-index: 1;
}
.hero-device.is-iphone {
  top: auto;
  right: 3%;
  bottom: -5%;
  left: auto;
  width: 13%;
  transform: none;
  z-index: 2;
}
/* Rotation lives on the inner wrapper so the float can restate it without
   touching the positioning transform above. */
.hero-device.is-mac .hero-device-inner { transform: rotate(-1.1deg); }
.hero-device.is-ipad .hero-device-inner { transform: rotate(-7deg); }
.hero-device.is-iphone .hero-device-inner { transform: rotate(6deg); }

/* Entrance on the individual translate property, so it composes with the
   positioning transform instead of replacing it. */
@media (prefers-reduced-motion: no-preference) {
  .hero-device { animation: hero-device-in 700ms var(--ease-entrance) 100ms both; }
  .hero-device.is-ipad { animation-delay: 180ms; }
  .hero-device.is-iphone { animation-delay: 260ms; }
  .hero-device.is-mac .hero-device-inner { animation: hero-float-mac 9s ease-in-out -2s infinite alternate; }
  .hero-device.is-ipad .hero-device-inner { animation: hero-float-ipad 7.5s ease-in-out -2.6s infinite alternate; }
  .hero-device.is-iphone .hero-device-inner { animation: hero-float-iphone 6.5s ease-in-out -4.4s infinite alternate; }
}
@keyframes hero-device-in {
  from { opacity: 0; translate: 0 16px; }
}
@keyframes hero-float-mac {
  from { transform: rotate(-1.1deg) translateY(0); }
  to { transform: rotate(-1.1deg) translateY(-6px); }
}
@keyframes hero-float-ipad {
  from { transform: rotate(-7deg) translateY(0); }
  to { transform: rotate(-7deg) translateY(-6px); }
}
@keyframes hero-float-iphone {
  from { transform: rotate(6deg) translateY(0); }
  to { transform: rotate(6deg) translateY(-6px); }
}

/* ==========================================================================
   Sections
   ========================================================================== */

.section { padding: calc(var(--section-gap) / 2) 0; }
.section-tight { padding: clamp(36px, 5vw, 56px) 0; }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 6vw, 80px);
  align-items: start;
}
.split.reverse > :first-child { order: 2; }
.split-idea { grid-template-columns: minmax(0, 1fr) 300px; }
.split .section-head { margin-bottom: 0; }
@media (max-width: 899.98px) {
  .split,
  .split-idea { grid-template-columns: minmax(0, 1fr); }
  .split.reverse > :first-child { order: 0; }
}

.section-link { margin: 24px 0 0; }
.section-head .section-link { margin-top: 24px; }

/* The idea: three statements as rows of one group, not tiles. */
.idea-rows { margin-top: 28px; }
.idea-rows .group-row { align-items: flex-start; padding: 16px; }
.idea-rows .group-row-body { gap: 4px; }
.idea-rows .group-row-title {
  margin: 0;
  font: 700 1.0625rem/1.3 var(--font);
  letter-spacing: -0.01em;
}
.idea-rows .group-row-sub {
  margin: 0;
  font: 400 var(--step-0s)/1.55 var(--font);
  color: var(--ink-2);
}

/* A device or screen standing on the field with a plain caption. */
.device-figure,
.feature-shot {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.device-figure-frame { width: 280px; max-width: 100%; }
.device-figure figcaption,
.feature-shot figcaption {
  max-width: 32ch;
  margin-top: 20px;
}
/* Clear of the frame's drop shadow (28px low, 36px blur): in the light
   theme the label measured 3.7:1 at 20px, 4.45 at 48px (void), 4.67 here. */
.device-figure figcaption { margin-top: 56px; }
.device-figure figcaption .card-label,
.feature-shot figcaption .card-label,
.device-plate .card-label { margin: 0 0 4px; }
.device-figure figcaption p,
.feature-shot figcaption p {
  margin: 0;
  font: 400 var(--step--1)/1.45 var(--font);
  color: var(--ink-2);
}

.checklist {
  display: grid;
  gap: 12px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}
.checklist li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  font: 400 var(--step-0s)/1.5 var(--font);
  color: var(--text-soft);
}
.checklist svg {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  color: var(--eyebrow-ink);
}

/* Ten across needs about 510px; the split column is narrower than that
   between 900 and 1160, so it keeps five by two there. */
.swatch-row { margin-top: 24px; }
.swatch-row .swatches {
  display: grid;
  grid-template-columns: repeat(5, 40px);
  gap: 14px 16px;
}
@media (min-width: 560px) and (max-width: 899.98px), (min-width: 1160px) {
  .swatch-row .swatches { grid-template-columns: repeat(10, 40px); column-gap: 12px; }
}

/* Latest: head left, "All posts" right, posts as one group. */
.latest-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px 24px;
  margin-bottom: clamp(24px, 3vw, 32px);
}
.latest-head .section-head { margin: 0; }
.latest-list .group-row-body { gap: 3px; }
@media (max-width: 759.98px) {
  .latest-desc {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}

/* Closing: unboxed and centred. */
.cta {
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
}
.cta h2 {
  margin: 0;
  font: 700 var(--step-2)/1.15 var(--font);
  letter-spacing: var(--track-h2);
  color: var(--text);
}
.cta > p {
  max-width: 52ch;
  margin: 14px auto 0;
  font: 400 var(--step-0l)/1.55 var(--font);
  color: var(--text-soft);
}
.cta .hero-actions { margin-top: 28px; }
.cta .cta-community {
  margin: 18px 0 0;
  font: 400 var(--step-0s)/1.5 var(--font);
  color: var(--ink-2);
}
.cta .cta-community .text-link { margin-left: 4px; vertical-align: bottom; }
.cta .cta-community .discord-icon { width: 16px; height: 16px; }

/* ==========================================================================
   List pages (download, sources): one column on the field
   ========================================================================== */

.shell-page { max-width: calc(var(--col-page) + 64px); }

.hero-page {
  padding: var(--page-top) 0 8px;
  text-align: left;
}
/* The title block is short: the snow and rain field runs 140px past it
   and fades out there, so particles fall rather than blink out. */
.hero-page .hero-atmosphere { bottom: -140px; }
.hero-page .section-head,
.page-top .section-head:first-child { margin-bottom: 0; }
.page-body { padding: 0 0 calc(var(--section-gap) / 2); }
.page-top { padding: var(--page-top) 0 calc(var(--section-gap) / 2); }
.page-top .section-head + .banner { margin-top: 28px; }

.platform-block { margin-top: clamp(40px, 6vw, 56px); }

.platform-row { align-items: flex-start; padding: 16px; }
.platform-row .group-row-body { gap: 6px; }
.platform-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
}
.platform-row .group-row-title {
  margin: 0;
  font: 700 1.0625rem/1.3 var(--font);
  letter-spacing: -0.01em;
}
.platform-row .group-row-sub {
  margin: 0;
  font: 400 var(--step-0s)/1.55 var(--font);
  color: var(--ink-2);
}
.platform-row .group-row-trail { align-self: center; }
.platform-row .field-hint { margin: 0; }
.platform-tags { margin: 4px 0 0; padding: 0; list-style: none; }
.platform-action { margin-top: 8px; }
/* The badge drops under the text on phones, in line with the title. */
@media (max-width: 599.98px) {
  .platform-row { flex-wrap: wrap; }
  .platform-row .group-row-trail { flex-basis: 100%; padding-left: 43px; }
}

/* Apple's artwork: placement and a focus ring shape only, never restyled. */
.app-store-badge {
  display: inline-block;
  line-height: 0;
  border-radius: var(--r-inline);
}
.app-store-badge img { display: block; width: auto; height: 40px; }

/* Sources' closing prose sits beside 760px cards and the copy pill, not
   reading.css's 720px measure: match the page's own column instead. The
   compound selector outranks reading.css's plain .prose so this wins
   regardless of load order (reading.css loads after marketing.css). */
.prose.prose-wide { max-width: var(--col-page); }

/* Real ordered steps with etched badges, not decorative numerals. */
.prose ol.steps {
  counter-reset: step;
  margin: 0;
  padding: 0;
  list-style: none;
}
.prose ol.steps > li {
  position: relative;
  margin: 0 0 14px;
  padding-left: 40px;
  counter-increment: step;
}
.prose ol.steps > li::before {
  content: counter(step);
  position: absolute;
  top: 0;
  left: 0;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
  font: 700 var(--step--1)/1 var(--font);
  color: var(--text);
}
.first-run .prose { margin-top: 0; }

/* The copy pill, shared by download and sources ([data-copy] in site.js). */
.repo-box {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  margin: 24px 0 0;
  padding: 6px 6px 6px 18px;
  border-radius: var(--r-group);
  background: var(--mat-neutral);
  box-shadow: var(--glass-rim);
}
.repo-url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font: 500 .9375rem/1 var(--mono);
  color: var(--text);
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* 14px on phones: the production URL then fits beside "Copy URL" at 390. */
@media (max-width: 479.98px) {
  .repo-url { font-size: .875rem; }
}
.repo-box .btn { flex: none; }
.repo-box .btn.is-copied,
.repo-box .btn.is-copied:hover { color: var(--status-safe-ink); }
.repo-box + .repo-hint { margin-top: 10px; }
/* A command someone is about to paste into a terminal has to be readable in
   full, not cut off with an ellipsis the way a URL can be, so it wraps. */
.field-hint code { font-family: var(--mono); font-size: .92em; }
.repo-box-command { margin-top: 12px; padding-block: 10px; }
.repo-box-command .repo-url {
  overflow: visible;
  white-space: normal;
  overflow-wrap: anywhere;
  text-overflow: clip;
  font-size: .8125rem;
  line-height: 1.5;
}

.download-trio { margin-top: clamp(48px, 7vw, 72px); }

/* Sources */
.sources-head { margin-top: clamp(40px, 6vw, 56px); }

.source-card {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 6px 14px;
  padding: 18px 20px;
  border-radius: var(--r-group);
  background: var(--mat-neutral);
  box-shadow: var(--glass-rim);
  color: var(--text);
}
.source-card-body { min-width: 0; }
.source-card header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
}
.source-card h3 {
  margin: 0 4px 0 0;
  font: 700 1.0625rem/1.3 var(--font);
  letter-spacing: -0.01em;
  color: var(--text);
}
.source-card p {
  margin: 8px 0 0;
  font: 400 var(--step-0s)/1.55 var(--font);
  color: var(--ink-2);
}

/* Capability caps: the pill shape, a tick per thing the source can do. */
.cap-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}
.cap {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font: 600 var(--step--2)/1.5 var(--font);
  color: var(--text-soft);
  white-space: nowrap;
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
}
.cap svg { flex: none; width: 12px; height: 12px; color: var(--status-safe-ink); }

.source-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 12px;
}
