/* Tarsi landing page.
   Palette mirrors src/constants/theme.ts so the site and the app agree. */

@font-face {
  font-family: 'OpenRunde';
  src: url('assets/fonts/OpenRunde-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'OpenRunde';
  src: url('assets/fonts/OpenRunde-Medium.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'OpenRunde';
  src: url('assets/fonts/OpenRunde-Semibold.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'OpenRunde';
  src: url('assets/fonts/OpenRunde-Bold.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

:root {
  /* SF Pro Rounded where the OS has it (`ui-rounded` on Apple platforms),
     OpenRunde — the app's bundled rounded face — everywhere else. */
  --font-rounded: ui-rounded, 'SF Pro Rounded', -apple-system-rounded, 'OpenRunde',
    system-ui, -apple-system, 'Segoe UI', sans-serif;

  --bg: #f8faf9;
  --card: #ffffff;
  --primary: #508a59;
  --primary-soft: rgba(80, 138, 89, 0.1);
  --on-primary: #ffffff;
  --text: #111827;
  --text-secondary: #6b7280;
  --text-muted: #9ca3af;
  --shadow: 0 18px 40px -24px rgba(17, 24, 39, 0.28);
  --shadow-soft: 0 10px 24px -18px rgba(17, 24, 39, 0.35);

  --radius-card: 28px;
  --page-gutter: 24px;
  --page-width: 1080px;
}

/* Light only — the page ignores the OS dark preference on purpose, so
   `color-scheme` keeps form controls and scrollbars light to match. */
html {
  color-scheme: light;
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-rounded);
  font-weight: 500;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

img {
  max-width: 100%;
  height: auto;
}

/* Cards carry no borders — shape comes from the squircle clip path applied by
   squircle.js, with border-radius as the fallback until (or unless) that
   module runs. */
.card {
  border: 0;
  border-radius: var(--radius-card);
}

.has-squircles .card {
  border-radius: 0;
}

/* Scroll reveal ------------------------------------------------------------ */

/* Only active once reveal.js has added `has-reveal`, so the page is never
   left invisible when the script does not run. */
.has-reveal .reveal {
  opacity: 0;
  filter: blur(10px);
  transform: translateY(16px);
  transition:
    opacity 0.32s ease,
    filter 0.32s ease,
    transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--reveal-delay, 0s);
}

.has-reveal .reveal.is-visible {
  opacity: 1;
  filter: blur(0);
  transform: none;
}

/* Header ------------------------------------------------------------------ */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 22px var(--page-gutter);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

/* The icon art has its own tight baked-in corners, so the squircle clip on the
   image cuts inside them and gives the shape the rest of the page uses. The
   shadow lives on the wrapper as a `drop-shadow` — a `box-shadow` would trace
   the square bounding box, and a filter on the image itself would be clipped
   away along with the corners. */
.brand-mark {
  display: inline-flex;
  filter: drop-shadow(0 4px 10px rgba(17, 24, 39, 0.22));
}

.brand-mark img {
  display: block;
  width: 36px;
  height: 36px;
  border-radius: 9px;
}

.has-squircles .brand-mark img {
  border-radius: 0;
}

.brand-name {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
}

.nav-link {
  padding: 8px 14px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-secondary);
  border-radius: 14px;
  transition: color 0.18s ease, background 0.18s ease;
}

.nav-link:hover,
.nav-link[aria-current='page'] {
  color: var(--text);
  background: var(--primary-soft);
}

/* The one nav item that is an action rather than a destination. */
/* Black rather than green: the same treatment as the store buttons, so the one
   action in the header does not read as another green nav item. */
.nav-cta {
  margin-left: 6px;
  padding: 9px 18px;
  background: #0b0f0e;
  color: #ffffff;
  box-shadow: var(--shadow-soft);
  transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.nav-cta:hover,
.nav-cta[aria-current='page'] {
  background: #0b0f0e;
  color: #ffffff;
  transform: translateY(-1px);
}

.nav-cta[aria-current='page'] {
  transform: none;
}


/* The official store badges, sized to match the web app's AppDownloadBadges.
   They are supplied artwork, so they keep their own shape and are never
   clipped or restyled. */
.store-badge {
  display: inline-flex;
  align-items: center;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.store-badge img {
  display: block;
  width: 138px;
  height: auto;
}

.store-badge-play img {
  width: 156px;
}

.store-badge:hover {
  transform: translateY(-2px);
}

.store-badge:active {
  transform: translateY(0);
  opacity: 0.9;
}

/* Hero -------------------------------------------------------------------- */

main {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--page-gutter) 64px;
}

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  align-items: center;
  gap: 32px;
  padding: 40px 0 72px;
}

.eyebrow strong {
  font-weight: 800;
}

.eyebrow {
  margin: 0 0 14px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--primary);
}

.hero h1 {
  font-size: clamp(40px, 6.4vw, 66px);
}

.lede {
  margin: 18px 0 0;
  max-width: 34ch;
  font-size: clamp(17px, 1.6vw, 19px);
  color: var(--text-secondary);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
}

.cta-row-center {
  justify-content: center;
}

.social-proof {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 26px 0 0;
  font-size: 16px;
  font-weight: 500;
  color: var(--text-secondary);
}

.social-proof strong {
  display: inline-block;
  font-weight: 700;
  color: var(--primary);
  transition:
    opacity 0.6s ease,
    filter 0.6s ease;
}

/* Set for one frame at the start of each count, then removed so the number
   blur-fades in as it begins climbing. */
.social-proof strong.is-entering {
  opacity: 0;
  filter: blur(8px);
  transition: none;
}

/* Seeded avatars from the same generator the feedback board uses
   (`src/utils/feedback-avatar.ts`). */
.avatar-stack {
  display: inline-flex;
  flex: none;
}

.avatar-stack img {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--primary-soft);
  box-shadow: 0 0 0 3px var(--bg);
}

.avatar-stack img + img {
  margin-left: -12px;
}

.credit {
  margin: 14px 0 0;
  font-size: 15px;
  color: var(--text-muted);
}

.credit a {
  font-weight: 600;
  color: var(--text-secondary);
}

.credit a:hover {
  color: var(--primary);
}

.hero-art {
  position: relative;
  display: flex;
  justify-content: center;
  padding-bottom: 12px;
}

.hero-art-glow {
  position: absolute;
  inset: 4% 0 8%;
  background: radial-gradient(circle at 50% 55%, var(--primary-soft), transparent 68%);
  filter: blur(6px);
}

.hero-phone {
  position: relative;
  width: min(100%, 268px);
  /* Tipped clockwise so it sits at an angle rather than square to the page. */
  transform: rotate(8deg);
  transform-origin: 50% 60%;
  filter: drop-shadow(0 30px 50px rgba(17, 24, 39, 0.24));
  transition:
    transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1),
    filter 0.5s ease;
}

/* Sits in front of the phone, overlapping its lower-left corner, and keeps
   drifting on its own. */
.hero-mascot {
  position: absolute;
  z-index: 1;
  left: 0;
  bottom: 2%;
  width: min(68%, 288px);
  animation: float 6s ease-in-out infinite;
  transition: opacity 0.45s ease;
}

/* Hovering the art column fades the mascot out so the app screen behind it is
   fully visible, and back in on the way out. Pointer devices only — on touch,
   :hover sticks after a tap and would leave the mascot hidden. */
@media (hover: hover) {
  .hero-art:hover .hero-mascot {
    opacity: 0;
  }

  /* With the mascot out of the way, the phone straightens up and comes
     forward so the app screen is the thing you are looking at. */
  .hero-art:hover .hero-phone {
    transform: rotate(0deg) scale(1.07);
    filter: drop-shadow(0 38px 60px rgba(17, 24, 39, 0.3));
  }
}

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

/* Features ---------------------------------------------------------------- */

.features {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}

.card {
  background: var(--card);
  box-shadow: var(--shadow);
}

.features .card {
  padding: 28px 26px 32px;
}

/* Mascot on the left, Rive illustration on the right, both sitting on the
   same baseline. */
.card-media {
  position: relative;
  display: flex;
  justify-content: center;
  margin-bottom: 22px;
}

/* Rive renders into this one; rive-cards.js keys the backdrop out of each
   frame onto the visible canvas. It has to stay laid out for the runtime to
   size its drawing surface, hence visibility rather than display. */
.card-rive-source {
  position: absolute;
  top: 0;
  left: 0;
  width: 168px;
  height: 168px;
  visibility: hidden;
  pointer-events: none;
}

.card-rive {
  flex: none;
  width: 168px;
  height: 168px;
  /* Held back until the runtime has drawn a frame, so the card never shows an
     empty canvas box. */
  opacity: 0;
  transition: opacity 0.3s ease;
}

.card-rive.is-ready {
  opacity: 1;
}

.features h2 {
  font-size: 21px;
}

.features p {
  margin: 10px 0 0;
  font-size: 16px;
  color: var(--text-secondary);
}

/* Screenshots -------------------------------------------------------------- */

.shots {
  margin-top: 64px;
  text-align: center;
}

/* Let the track bleed past the page gutters so partially-visible slides hint
   that there is more to scroll. */
/* A marquee, not a carousel: the strip runs on its own and starts over without
   a seam, so there is nothing to press. Full-bleed, so it runs off both edges
   rather than stopping inside the page gutter. */
.shots-viewport {
  width: 100vw;
  margin: 28px 0 0 calc(50% - 50vw);
  overflow: hidden;
}

.shots-marquee {
  display: flex;
  width: max-content;
  animation: shots-scroll 72s linear infinite;
}

/* Two identical strips. Each carries a trailing gap of its own, so one strip is
   exactly half the total width and -50% lands the copy precisely where the
   original was — without it the seam jumps by half a gap every lap. */
.shots-track {
  display: flex;
  gap: 18px;
  margin: 0;
  padding: 4px 18px 12px 0;
  list-style: none;
}

.shot {
  flex: none;
}

.shot img {
  display: block;
  width: 232px;
  height: auto;
  background: var(--card);
}

@keyframes shots-scroll {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

/* Nothing should drift on its own here. The strip holds still and can be
   scrolled by hand instead. */
@media (prefers-reduced-motion: reduce) {
  .shots-viewport {
    overflow-x: auto;
    scrollbar-width: none;
  }

  .shots-viewport::-webkit-scrollbar {
    display: none;
  }

  .shots-marquee {
    animation: none;
  }

  .shots-track[aria-hidden='true'] {
    display: none;
  }
}

/* Recognition -------------------------------------------------------------- */

.recognition {
  margin-top: 56px;
  text-align: center;
}

.section-heading {
  font-size: clamp(26px, 3.6vw, 34px);
}

.ranks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  margin-top: 28px;
}

/* The demo is a portrait phone recording, so on a wide screen it sits in its own
   column with the rank cards stacked beside it rather than marooned in the
   middle of the page with empty space either side. */
.showcase {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  align-items: center;
  gap: 48px;
  /* Narrower than the page container and centred. At full container width the
     cards' faded right half was all that reached the right margin, so the block
     read as pushed left even though its gutters were even. */
  max-width: 900px;
  margin: 40px auto 0;
}

.showcase .reel-demo {
  margin: 0;
}

/* The demo recording plays inside the same iPhone frame as the screenshots. */
.reel-demo .iphone {
  width: min(100%, 300px);
}

.showcase-side {
  text-align: left;
}

.showcase-side .section-heading {
  margin: 0;
}

.showcase-lede {
  margin: 12px 0 0;
  max-width: 44ch;
  font-size: 17px;
  color: var(--text-secondary);
}

.showcase .ranks {
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
  margin-top: 26px;
}

/* Stacked in a wide column, each card reads as a row: the number on the left,
   the placement beside it. Centred text would leave a lake down the middle. */
.showcase .rank {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 2px 22px;
  padding: 26px 28px;
  text-align: left;
  /* Fades out to the right instead of ending on an edge. Both stops share the
     card's own RGB, so it thins to nothing rather than drifting through grey.
     The shadow goes with it — it would outline a card that has no right side. */
  background: linear-gradient(
    to right,
    var(--card) 0%,
    var(--card) 48%,
    rgba(255, 255, 255, 0) 100%
  );
  box-shadow: none;
}

.showcase .rank-number {
  grid-row: 1 / span 2;
  font-size: 46px;
}

.showcase .rank-label {
  grid-column: 2;
  margin-top: 0;
  align-self: end;
}

.showcase .rank-store {
  grid-column: 2;
  align-self: start;
}

@media (max-width: 860px) {
  .showcase {
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
  }

  .showcase .reel-demo {
    margin: 0 auto;
  }

  .showcase-side {
    text-align: center;
  }

  .showcase-lede {
    margin-inline: auto;
  }

  .showcase .rank {
    justify-content: center;
    gap: 2px 18px;
  }
}

.rank {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 30px 22px;
}

.rank-number {
  font-size: 42px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--primary);
}

.rank-label {
  margin-top: 8px;
  font-size: 17px;
  font-weight: 600;
}

.rank-store {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  color: var(--text-muted);
}

/* An award-style wreath: two mirrored laurel branches framing the feature
   placements, sitting straight on the page rather than in a card. */
.featured {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 2.5vw, 28px);
  margin-top: 40px;
}

.laurel {
  flex: none;
  width: auto;
  height: 150px;
  color: var(--primary);
  opacity: 0.6;
}

.laurel-right {
  transform: scaleX(-1);
}

.featured-body {
  min-width: 0;
}

.featured-title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.store-icon {
  flex: none;
  width: auto;
  height: 15px;
}

.featured-title .store-icon {
  height: 17px;
}

.featured-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}

.pill {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 18px;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 14px;
}

.has-squircles .pill {
  border-radius: 0;
}

.pill-icon {
  flex: none;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.press {
  margin-top: 40px;
}

.press-label {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.press-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 14px;
}

.press-link {
  padding: 12px 20px;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  transition: transform 0.18s ease;
}

.press-link:hover {
  transform: translateY(-2px);
  color: var(--primary);
}

/* Leads the recognition section — sits straight on the page, no card. */
.backed {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 0 0 32px;
}

.backed-kicker {
  font-size: 16px;
  color: var(--text-muted);
}

.backed-logo {
  display: block;
  width: auto;
  height: 42px;
}

/* Closer ------------------------------------------------------------------ */

.closer {
  margin-top: 20px;
  padding: 56px 32px;
  text-align: center;
}

.closer h2 {
  font-size: clamp(28px, 4vw, 38px);
}

.closer p {
  margin: 14px auto 0;
  max-width: 44ch;
  font-size: 17px;
  color: var(--text-secondary);
}

/* Reviews ------------------------------------------------------------------ */

.reviews {
  margin-top: 64px;
  text-align: center;
}

.reviews-note {
  margin: 12px 0 0;
  font-size: 15px;
  color: var(--text-muted);
}

/* Quotes vary a lot in length, so pack them in columns rather than a grid
   that would leave every row as tall as its longest card. */
.review-grid {
  columns: 3;
  column-gap: 20px;
  margin-top: 28px;
}

.review {
  display: inline-block;
  width: 100%;
  margin: 0 0 20px;
  padding: 24px 24px 22px;
  text-align: left;
  break-inside: avoid;
}

.review-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}

.stars {
  display: flex;
  gap: 2px;
}

.review-store {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

.stars svg {
  width: 15px;
  height: 15px;
  fill: #f0a500;
}

.review blockquote {
  margin: 0;
}

.review-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.review-body {
  margin: 8px 0 0;
  font-size: 15px;
  color: var(--text-secondary);
}

.review figcaption {
  margin-top: 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}

/* Community ---------------------------------------------------------------- */

.community {
  position: relative;
  overflow: hidden;
  margin-top: 20px;
  padding: 52px 32px;
  text-align: center;
  background: #eef4fd;
  border-radius: var(--radius-card);
}

.has-squircles .community {
  border-radius: 0;
}

/* Seeded member avatars drifting behind the copy. The card's squircle clip
   trims any that reach the edge, so they can sit close to it. */
.community-avatars {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.community-avatar {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--size, 44px);
  height: var(--size, 44px);
  border-radius: 50%;
  background: #dbe7fb;
  box-shadow: 0 8px 20px -8px rgba(22, 38, 74, 0.35);
  animation: float var(--drift, 7s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}

/* Positions live here rather than inline so the phone layout can move them
   out of the way of the copy. */
.community-avatar:nth-child(1) { --x: 4%;  --y: 16%; --size: 56px; --delay: 0s;    --drift: 7s; }
.community-avatar:nth-child(2) { --x: 12%; --y: 64%; --size: 44px; --delay: -1.4s; --drift: 8s; }
.community-avatar:nth-child(3) { --x: 20%; --y: 26%; --size: 36px; --delay: -2.6s; --drift: 6.5s; }
.community-avatar:nth-child(4) { --x: 82%; --y: 20%; --size: 48px; --delay: -0.8s; --drift: 7.5s; }
.community-avatar:nth-child(5) { --x: 90%; --y: 62%; --size: 58px; --delay: -2s;   --drift: 6.8s; }
.community-avatar:nth-child(6) { --x: 74%; --y: 70%; --size: 38px; --delay: -3.2s; --drift: 8.4s; }

.community h2 {
  font-size: clamp(26px, 3.4vw, 34px);
  color: #16264a;
}

.community p {
  margin: 14px auto 0;
  max-width: 46ch;
  font-size: 17px;
  color: #4a5b7a;
}

.community-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 26px;
  padding: 14px 22px;
  font-size: 16px;
  font-weight: 600;
  background: #1877f2;
  color: #ffffff;
  border-radius: 18px;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.has-squircles .community-link {
  border-radius: 0;
}

.community-logo {
  width: 21px;
  height: 21px;
}

.community-link:hover {
  transform: translateY(-2px);
}

.community-link:active {
  transform: translateY(0);
  opacity: 0.9;
}

/* Footer ------------------------------------------------------------------ */

/* Full-bleed dark band. `main` is width-capped, so the footer sets its own
   background and constrains its contents separately. */
.site-footer {
  margin-top: 64px;
  padding: 64px var(--page-gutter) 40px;
  background: #0b0f0e;
  color: #9ca3af;
}

.footer-inner {
  max-width: var(--page-width);
  margin: 0 auto;
}

.footer-top {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 2fr);
  gap: 48px;
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.footer-mark {
  display: inline-flex;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.5));
}

.footer-mark img {
  display: block;
  width: 42px;
  height: 42px;
  border-radius: 10px;
}

.has-squircles .footer-mark img {
  border-radius: 0;
}

.footer-wordmark {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #f9fafb;
}

.footer-blurb {
  margin: 16px 0 0;
  max-width: 38ch;
  font-size: 15px;
  line-height: 1.6;
  color: #6b7280;
}

.footer-stores {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 22px;
}

.footer-stores .store-badge img {
  width: 116px;
}

.footer-stores .store-badge-play img {
  width: 131px;
}

.footer-nav {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 28px 20px;
}

.footer-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 11px;
  font-size: 15px;
}

.footer-heading {
  margin: 0 0 3px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #4b5563;
}

.footer-col a {
  color: #9ca3af;
  transition: color 0.18s ease;
}

.footer-col a:hover {
  color: #ffffff;
}

.footer-web {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.footer-icon {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 48px;
  padding-top: 26px;
  border-top: 1px solid #1e2926;
  font-size: 14px;
  color: #4b5563;
}

.footer-legal,
.footer-made {
  margin: 0;
}

.footer-made a {
  font-weight: 600;
  color: #9ca3af;
  transition: color 0.18s ease;
}

.footer-made a:hover {
  color: var(--primary);
}

/* Responsive -------------------------------------------------------------- */

@media (max-width: 1100px) {
  .review-grid {
    columns: 2;
  }
}

@media (max-width: 900px) {
  .community {
    padding-top: 84px;
    padding-bottom: 84px;
  }

  .community-avatar:nth-child(1) { --x: 3%;  --y: 4%;  --size: 42px; }
  .community-avatar:nth-child(2) { --x: 4%;  --y: 84%; --size: 38px; }
  .community-avatar:nth-child(3) { --x: 40%; --y: 2%;  --size: 32px; }
  .community-avatar:nth-child(4) { --x: 78%; --y: 6%;  --size: 40px; }
  .community-avatar:nth-child(5) { --x: 80%; --y: 82%; --size: 44px; }
  .community-avatar:nth-child(6) { --x: 44%; --y: 88%; --size: 34px; }

  .features {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Keep the ranks reading as a stats row rather than three tall stacked
     cards; the odd one out spans the full width. */
  .review-grid {
    columns: 1;
  }

  .shot img {
    width: 208px;
  }

  .ranks {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }

  .ranks .rank:last-child {
    grid-column: 1 / -1;
  }

  .rank {
    padding: 22px 16px;
  }

  .rank-number {
    font-size: 36px;
  }

  .rank-label {
    margin-top: 6px;
    font-size: 16px;
  }

  /* Two laurels plus a two-up pill grid will not fit a phone, so shrink the
     branches and stack the placements. */
  .laurel {
    height: 112px;
  }

  /* Keep the eyebrow on one line so the Apple glyph stays beside it rather
     than floating next to a two-line wrap. */
  .featured-title {
    font-size: 11px;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }

  .featured-list {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  .site-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  .site-nav {
    margin-left: -14px;
  }

  .pill {
    padding: 10px 14px;
    font-size: 14px;
  }

  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
    padding-bottom: 56px;
    text-align: center;
  }

  .hero-copy {
    order: 2;
  }

  /* The phone is shown larger and cropped: roughly its bottom 30% is cut off
     and the phone fades out into the page above the cut. --hero-phone-width drives both the phone and the
     crop height (the mockup is 476×1120, so 70% of its height is width × 1.65). */
  .hero-art {
    --hero-phone-width: min(78vw, 340px);
    order: 1;
    height: calc(var(--hero-phone-width) * 1.65);
    padding-bottom: 0;
    /* Clip only the bottom edge; the phone's shadow and glow may still spill
       past the top and sides. */
    clip-path: inset(-120px -100vw 1px -100vw);
  }

  .lede {
    margin-inline: auto;
  }

  .cta-row {
    justify-content: center;
  }

  /* The line drops below the avatars, centered, when both don't fit. */
  .social-proof {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 10px;
  }

  /* Upright on small screens, with the app screen as the only focus. */
  .hero-phone {
    width: var(--hero-phone-width);
    height: auto;
    align-self: flex-start;
    transform: none;
    /* The mask below would crop the drop shadow into a visible box. */
    filter: none;
    /* Fades the phone itself into the page, well before the crop edge, so no
       sliver of it can show at the cut. */
    -webkit-mask-image: linear-gradient(to bottom, #000 48%, transparent 67%);
    mask-image: linear-gradient(to bottom, #000 48%, transparent 67%);
  }

  .hero-mascot {
    display: none;
  }

  .features .card {
    text-align: center;
  }
}

@media (max-width: 480px) {
  :root {
    --page-gutter: 16px;
  }

  .closer {
    padding: 44px 22px;
  }

  /* Trim the badges just enough to keep both on one row inside the closer. */
  .store-badge img {
    width: 130px;
  }

  .store-badge-play img {
    width: 147px;
  }

  .footer-top {
    grid-template-columns: minmax(0, 1fr);
    gap: 36px;
  }

  .footer-nav {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
    margin-top: 36px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}


/* Features page ------------------------------------------------------------ */

.page-hero {
  padding: 48px 0 12px;
  text-align: center;
}

.page-hero h1 {
  font-size: clamp(36px, 5.2vw, 56px);
}

.page-hero .eyebrow {
  margin-bottom: 12px;
}

.page-hero-lede {
  max-width: 52ch;
  margin-inline: auto;
}

.feat-block {
  margin-top: 72px;
}

.feat-intro {
  max-width: 54ch;
  margin: 0 auto 28px;
  text-align: center;
}

/* Badges and looks --------------------------------------------------------- */

.badge-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 18px;
}

.badge {
  margin: 0;
  text-align: center;
}

.badge img {
  display: block;
  width: min(100%, 132px);
  height: 118px;
  margin: 0 auto 12px;
  object-fit: contain;
  filter: drop-shadow(0 10px 18px rgba(17, 24, 39, 0.16));
}

.badge-name {
  display: block;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.badge-note {
  display: block;
  margin-top: 2px;
  font-size: 14px;
  color: var(--text-muted);
}

/* Two figures cycling through outfits. Frames are stacked and cross-faded on
   one shared keyframe, offset by --i, so no JavaScript is involved. */
.outfit-stage {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
  max-width: 720px;
  margin: 0 auto;
}

.outfit {
  position: relative;
  margin: 0;
  padding: 24px 18px;
  overflow: hidden;
  background: var(--primary-soft);
  border-radius: var(--radius-card);
}

.outfit-scenes {
  position: absolute;
  inset: 0;
}

.outfit-scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* Same cycle and offsets as the outfits, so the scene changes with them.
     Its own keyframe skips the scale, which would show the tile's edges. */
  animation: scene-cycle 12.5s ease-in-out infinite both;
  animation-delay: calc(var(--i) * 2.5s);
}

@keyframes scene-cycle {
  0% {
    opacity: 0;
  }
  3%,
  19% {
    opacity: 1;
  }
  23%,
  100% {
    opacity: 0;
  }
}

.has-squircles .outfit {
  border-radius: 0;
}

.outfit-frames {
  position: relative;
  height: 300px;
  z-index: 1;
}

.outfit-frame {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: auto;
  height: 100%;
  opacity: 0;
  transform: translateX(-50%);
  animation: outfit-cycle 12.5s ease-in-out infinite both;
  animation-delay: calc(var(--i) * 2.5s);
  filter: drop-shadow(0 14px 20px rgba(17, 24, 39, 0.2));
}

/* Five frames over one cycle: each holds for its fifth, then crosses over the
   next as it fades in, so there is never a gap with nothing on screen. */
@keyframes outfit-cycle {
  0% {
    opacity: 0;
    transform: translateX(-50%) scale(0.965);
  }
  3%,
  19% {
    opacity: 1;
    transform: translateX(-50%) scale(1);
  }
  23%,
  100% {
    opacity: 0;
    transform: translateX(-50%) scale(0.965);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Hold the first outfit and scene rather than flashing through five. */
  .outfit-frame,
  .outfit-scene {
    animation: none;
    opacity: 0;
  }

  .outfit-frame[style*='--i: 0'],
  .outfit-scene[style*='--i: 0'] {
    opacity: 1;
  }
}

.feat-rive {
  display: block;
  width: min(100%, 300px);
  height: 300px;
  margin: 0 auto 4px;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.feat-rive.is-ready {
  opacity: 1;
}

.feat-intro h2 {
  font-size: clamp(25px, 3.2vw, 33px);
}

.feat-lede {
  margin: 14px 0 0;
  font-size: 17px;
  color: var(--text-secondary);
}

.feat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
}

.feat {
  padding: 24px 22px 26px;
}

.feat-icon {
  width: 26px;
  height: 26px;
  margin-bottom: 14px;
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.feat h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.feat p {
  margin: 8px 0 0;
  font-size: 15px;
  color: var(--text-secondary);
}

/* Feature block layout variants -------------------------------------------- */

/* feat-stack is the default: illustration centred over a four-across grid. */

/* Illustration held in its own column beside the copy and a two-across grid. */
.feat-left,
.feat-right {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  grid-template-areas:
    'art intro'
    'art grid';
  align-items: center;
  gap: 14px 48px;
}

.feat-right {
  grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
  grid-template-areas:
    'intro art'
    'grid art';
}

.feat-left > .feat-rive,
.feat-right > .feat-rive {
  grid-area: art;
  width: 100%;
  margin: 0;
}

.feat-left > .feat-intro,
.feat-right > .feat-intro {
  grid-area: intro;
  max-width: none;
  margin: 0 0 4px;
  text-align: left;
}

.feat-left > .feat-grid,
.feat-right > .feat-grid {
  grid-area: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* A tinted band, to break the run of white cards on white. */
.feat-band {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  grid-template-areas:
    'art intro'
    'art grid';
  align-items: center;
  gap: 14px 44px;
  padding: 44px;
  background: linear-gradient(160deg, rgba(80, 138, 89, 0.13), rgba(80, 138, 89, 0.04));
  border-radius: var(--radius-card);
}

.has-squircles .feat-band {
  border-radius: 0;
}

.feat-band > .feat-rive {
  grid-area: art;
  width: 100%;
  margin: 0;
}

.feat-band > .feat-intro {
  grid-area: intro;
  max-width: none;
  margin: 0 0 4px;
  text-align: left;
}

.feat-band > .feat-grid {
  grid-area: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* The band already provides the surface, so its cards sit flat on it. */
.feat-band .feat {
  background: rgba(255, 255, 255, 0.72);
  box-shadow: none;
}

@media (max-width: 900px) {
  .feat-left,
  .feat-right,
  .feat-band {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      'art'
      'intro'
      'grid';
    gap: 4px;
  }

  .feat-band {
    padding: 32px 22px;
  }

  .feat-left > .feat-rive,
  .feat-right > .feat-rive,
  .feat-band > .feat-rive {
    height: 230px;
  }

  .feat-left > .feat-intro,
  .feat-right > .feat-intro,
  .feat-band > .feat-intro {
    margin: 0 auto 24px;
    text-align: center;
  }
}

/* Web app block ------------------------------------------------------------ */

.web-block {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  align-items: center;
  gap: 36px;
  margin-top: 72px;
  padding: 44px;
  background: var(--card);
  box-shadow: var(--shadow);
  border-radius: var(--radius-card);
}

.has-squircles .web-block {
  border-radius: 0;
}

.web-copy h2 {
  font-size: clamp(26px, 3.4vw, 34px);
}

.web-copy p {
  margin: 14px 0 0;
  font-size: 17px;
  color: var(--text-secondary);
}

.web-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 24px;
  padding: 13px 20px;
  font-size: 16px;
  font-weight: 600;
  background: var(--primary);
  color: var(--on-primary);
  border-radius: 18px;
  box-shadow: var(--shadow-soft);
  transition: transform 0.18s ease;
}

.has-squircles .web-link {
  border-radius: 0;
}

.web-link:hover {
  transform: translateY(-2px);
}

.web-demo {
  margin: 0;
}

.web-video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--bg);
  border-radius: 18px;
}

.has-squircles .web-video {
  border-radius: 0;
}

@media (max-width: 1100px) {
  .feat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .badge-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

}

@media (max-width: 900px) {
  .web-block {
    grid-template-columns: minmax(0, 1fr);
    padding: 32px 24px;
    text-align: center;
  }

  .feat-block {
    margin-top: 56px;
  }
}

@media (max-width: 560px) {
  .feat-grid,
  .feat-left > .feat-grid,
  .feat-right > .feat-grid,
  .feat-band > .feat-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .badge-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .feat-rive {
    height: 210px;
  }


}

/* Download ----------------------------------------------------------------- */

.download-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  margin-top: 40px;
}

.download-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 30px 28px 30px;
}

/* A tinted tile behind the platform mark, so each card opens on something with
   weight rather than a small logo floating on white. */
.download-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  margin-bottom: 20px;
  background: var(--primary-soft);
  border-radius: 16px;
}

.has-squircles .download-badge {
  border-radius: 0;
}

.download-badge img {
  width: auto;
  height: 28px;
}

.download-badge-web svg {
  width: 28px;
  height: 28px;
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.download-card h2 {
  margin: 0;
  font-size: 21px;
}

.download-card p {
  margin: 8px 0 0;
  font-size: 15px;
  color: var(--text-secondary);
}

/* The concrete facts, so a card is not one sentence and a button. The auto top
   margin drops the block to the foot of the card, so the rules above the specs
   line up across all three however long each description runs. */
.download-specs {
  display: grid;
  gap: 9px;
  width: 100%;
  margin: auto 0 0;
  padding: 20px 0 0;
  list-style: none;
  border-top: 1px solid rgba(17, 24, 39, 0.07);
  font-size: 14.5px;
  color: var(--text-secondary);
}

.download-specs li {
  position: relative;
  padding-left: 24px;
}

.download-specs li::before {
  content: '';
  position: absolute;
  left: 1px;
  top: 6px;
  width: 10px;
  height: 5.5px;
  border-left: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
  transform: rotate(-45deg);
}

/* Scoped to the card: the base `.dl-btn` rule sets `margin-top: auto` and sits
   later in this file, so an unscoped override loses and the card ends up with
   two auto margins splitting the free space between the specs and the button —
   which is what pulled the third card's divider out of line. */
.download-card .dl-btn-block {
  justify-content: center;
  width: 100%;
  margin-top: 26px;
  padding: 14px 20px;
}

.download-note {
  max-width: 54ch;
  margin: 30px auto 0;
  text-align: center;
  font-size: 15px;
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .download-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .download-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Blog --------------------------------------------------------------------- */

.post-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  margin-top: 40px;
}

.post {
  display: flex;
  flex-direction: column;
  padding: 26px 24px 24px;
}

.post-meta {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.post-cat {
  color: var(--primary);
}

.post h2 {
  margin: 12px 0 0;
  font-size: 20px;
  line-height: 1.25;
}

.post h2 a:hover {
  color: var(--primary);
}

.post-blurb {
  margin: 10px 0 0;
  font-size: 15px;
  color: var(--text-secondary);
}

.post-more {
  margin: 18px 0 0;
  padding-top: 4px;
  font-size: 15px;
  font-weight: 600;
  color: var(--primary);
}

.article {
  max-width: 68ch;
  margin: 0 auto;
}

.article-head {
  padding: 48px 0 8px;
  text-align: center;
}

.article-head h1 {
  margin: 14px 0 0;
  font-size: clamp(30px, 4.4vw, 46px);
}

.article-head .lede {
  margin: 16px auto 0;
  max-width: none;
}

.article-body {
  margin-top: 32px;
  font-size: 18px;
  color: var(--text-secondary);
}

.article-body p {
  margin: 0 0 20px;
}

.article-body p:first-child {
  font-size: 19px;
  color: var(--text);
}

.article-cta {
  margin-top: 16px;
  padding: 30px 28px;
  text-align: center;
}

.article-cta h2 {
  font-size: 22px;
}

.article-cta p {
  margin: 8px 0 0;
  font-size: 16px;
  color: var(--text-secondary);
}

.article-back {
  margin: 28px 0 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-secondary);
  text-align: center;
}

.article-back a:hover {
  color: var(--primary);
}

@media (max-width: 1100px) {
  .post-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}


@media (max-width: 560px) {
  .post-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .article-body {
    font-size: 17px;
  }
}

/* Coming soon -------------------------------------------------------------- */

.soon {
  max-width: 60ch;
  margin: 0 auto;
  padding: 72px 0 40px;
  text-align: center;
}

.soon-icon {
  width: 46px;
  height: 46px;
  margin-bottom: 20px;
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.soon h1 {
  font-size: clamp(34px, 5vw, 52px);
}

.soon-tag {
  display: inline-block;
  margin: 16px 0 0;
  padding: 7px 16px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 999px;
}

.soon-lede {
  margin: 22px auto 0;
  max-width: none;
}

.soon-follow {
  margin: 16px auto 0;
  font-size: 16px;
  color: var(--text-muted);
}

.soon-back {
  margin: 26px 0 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-secondary);
}

.soon-back a:hover {
  color: var(--primary);
}

/* Mobile menu -------------------------------------------------------------- */

/* Hidden on desktop: the nav is already laid out inline there. */
.nav-toggle {
  display: none;
  position: relative;
  z-index: 3;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 0;
  border-radius: 14px;
  background: var(--primary-soft);
  color: var(--primary);
  cursor: pointer;
}

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  position: absolute;
  left: 50%;
  width: 18px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transform: translateX(-50%);
  transition: transform 0.25s ease, opacity 0.2s ease;
}

.nav-toggle-bars {
  top: 50%;
  margin-top: -1px;
}

.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: '';
  left: 0;
  transform: none;
}

.nav-toggle-bars::before {
  top: -6px;
}

.nav-toggle-bars::after {
  top: 6px;
}

.nav-toggle[aria-expanded='true'] .nav-toggle-bars {
  background: transparent;
}

.nav-toggle[aria-expanded='true'] .nav-toggle-bars::before {
  transform: translateY(6px) rotate(45deg);
}

.nav-toggle[aria-expanded='true'] .nav-toggle-bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

@media (max-width: 900px) {
  .site-header {
    position: relative;
    z-index: 3;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }

  .nav-toggle {
    display: block;
  }

  /* The sheet is a child of the header, so lift the wordmark above it or the
     brand ends up blurred behind its own menu. */
  .brand {
    position: relative;
    z-index: 3;
  }

  /* Full-screen sheet over a blurred page. */
  .site-nav {
    position: fixed;
    inset: 0;
    z-index: 2;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 24px var(--page-gutter);
    background: rgba(248, 250, 249, 0.72);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.28s ease, visibility 0.28s ease;
  }

  .site-nav.is-open {
    opacity: 1;
    visibility: visible;
  }

  .site-nav .nav-link {
    padding: 15px 18px;
    font-size: 20px;
    text-align: center;
    border-radius: 18px;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.3s ease, transform 0.3s ease;
    transition-delay: var(--nav-delay, 0s);
  }

  .site-nav.is-open .nav-link {
    opacity: 1;
    transform: none;
  }

  /* An icon link is a flex row, so the `text-align: center` above never reaches
     its contents — the row has to centre them itself. */
  .site-nav .nav-link-icon {
    justify-content: center;
  }

  .nav-cta {
    margin-left: 0;
    margin-top: 8px;
  }

  /* Stops the page scrolling behind the open sheet. */
  body.nav-open {
    overflow: hidden;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav,
  .site-nav .nav-link,
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    transition-duration: 0.001ms;
  }
}

/* Legal pages -------------------------------------------------------------- */

.legal {
  max-width: 68ch;
  margin: 0 auto;
}

.legal-head {
  padding: 56px 0 8px;
  text-align: center;
}

.legal-head h1 {
  margin: 12px 0 0;
  font-size: clamp(34px, 4.8vw, 50px);
}

.legal-lede {
  margin: 16px auto 0;
  max-width: none;
}

.legal-body {
  margin-top: 34px;
  font-size: 17px;
  color: var(--text-secondary);
}

.legal-body p {
  margin: 0 0 20px;
}

.legal-body p:first-child {
  font-size: 18px;
  color: var(--text);
}

.legal-more {
  margin: 30px 0 0;
  padding-top: 24px;
  border-top: 1px solid var(--primary-soft);
  font-size: 15px;
  color: var(--text-muted);
}

.legal-more a {
  font-weight: 600;
  color: var(--text-secondary);
}

.legal-more a:hover {
  color: var(--primary);
}

/* Download buttons --------------------------------------------------------- */

/* One black button per platform, so the three cards read as a matched set
   rather than two supplied badges and one house style. */
.dl-btn {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  margin-top: auto;
  padding: 13px 20px;
  background: #0b0f0e;
  color: #ffffff;
  border-radius: 18px;
  box-shadow: var(--shadow-soft);
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.has-squircles .dl-btn {
  border-radius: 0;
}

.dl-btn:hover {
  transform: translateY(-2px);
}

.dl-btn:active {
  transform: translateY(0);
  opacity: 0.9;
}

.dl-btn-icon {
  flex: none;
  width: auto;
  height: 22px;
}

.dl-btn-glyph {
  width: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.dl-btn-text {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Blog images -------------------------------------------------------------- */

.post-thumb {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 18px;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--primary-soft);
  border-radius: 18px;
}

.has-squircles .post-thumb {
  border-radius: 0;
}

.post-figure {
  margin: 0 0 28px;
}

.post-figure img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--primary-soft);
  border-radius: 20px;
  box-shadow: var(--shadow);
}

.has-squircles .post-figure img {
  border-radius: 0;
}

.post-figure-hero {
  margin-top: 30px;
}

/* Images sit between article-body blocks, so the gap above them comes from the
   paragraph's own margin. */
.post-figure + .article-body {
  margin-top: 0;
}

/* Roadmap timeline --------------------------------------------------------- */

.roadmap {
  max-width: 68ch;
  margin: 0 auto;
}

.roadmap-head {
  padding: 60px 0 8px;
  text-align: center;
}

.roadmap-head h1 {
  margin: 12px 0 0;
  font-size: clamp(32px, 4.6vw, 48px);
}

.roadmap-lede {
  margin: 18px auto 0;
  max-width: none;
}

.timeline {
  position: relative;
  margin: 44px 0 0;
  padding: 0 0 0 58px;
  list-style: none;
}

/* The spine, running between the first and last markers rather than past them. */
.timeline::before {
  content: '';
  position: absolute;
  left: 19px;
  top: 42px;
  bottom: 22px;
  width: 2px;
  background: linear-gradient(to bottom, var(--primary), var(--primary-soft));
}

.tl-item {
  position: relative;
  padding-bottom: 18px;
}

.tl-item:last-child {
  padding-bottom: 0;
}

.tl-marker {
  position: absolute;
  left: -58px;
  top: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary);
  font-size: 15px;
  font-weight: 700;
  box-shadow: 0 0 0 6px var(--bg);
}

/* The open end of the list: hollow, so it reads as "not a step yet". */
.tl-marker-open {
  background: var(--bg);
  color: var(--text-muted);
  box-shadow:
    0 0 0 6px var(--bg),
    inset 0 0 0 2px var(--primary-soft);
}

.tl-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 18px;
  padding: 24px 26px 26px;
}

.tl-icon {
  width: 26px;
  height: 26px;
  margin-top: 3px;
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tl-card h2 {
  margin: 0;
  font-size: 20px;
}

.tl-card p {
  margin: 8px 0 0;
  font-size: 16px;
  color: var(--text-secondary);
}

/* The one being worked on now, tinted so the list has a head rather than three
   identical cards. */
.tl-next .tl-card {
  background: linear-gradient(150deg, rgba(80, 138, 89, 0.15), rgba(80, 138, 89, 0.04));
  box-shadow: none;
}

.tl-flag {
  grid-column: 1 / -1;
  margin: 0 0 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--primary);
}

.tl-next .tl-card p:not(.tl-flag) {
  color: #4b5c50;
}

/* No card — the list trails off rather than ending on another box. */
.tl-more {
  padding-top: 8px;
}

.tl-more p {
  margin: 0;
  padding: 24px 4px 0;
  font-size: 16px;
  color: var(--text-muted);
}

.tl-more .tl-marker {
  top: 14px;
}

.roadmap-closer {
  margin-top: 44px;
  padding: 44px 32px 46px;
  text-align: center;
}

.roadmap-closer h2 {
  margin: 0;
  font-size: clamp(24px, 3.4vw, 30px);
}

.roadmap-closer p {
  margin: 14px auto 0;
  max-width: 46ch;
  font-size: 17px;
  color: var(--text-secondary);
}

/* The second action is the quieter one — same shape, none of the weight. */
.dl-btn-quiet {
  background: var(--bg);
  color: var(--text);
  box-shadow: none;
}

@media (max-width: 560px) {
  .timeline {
    padding-left: 46px;
  }

  .timeline::before {
    left: 15px;
  }

  .tl-marker {
    left: -46px;
    width: 32px;
    height: 32px;
    font-size: 14px;
  }

  .tl-card {
    gap: 14px;
    padding: 22px 20px 24px;
  }

  .roadmap-closer {
    padding: 36px 22px 38px;
  }
}

/* Nav items that carry an icon ---------------------------------------------- */

.nav-link-icon {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.nav-icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Tarsi Cloud page --------------------------------------------------------- */

/* Hero sky ----------------------------------------------------------------- */

.cloud-hero {
  padding: 84px 0 72px;
}

.cloud-hero-inner {
  position: relative;
  z-index: 1;
}

.cloud-hero h1 {
  font-size: clamp(42px, 7vw, 76px);
}

.page-cloud .feat-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* The Cloud AI block gives a column to the screenshot, so its cards pair up
   rather than inheriting the three-across grid the rest of the page uses. */
.page-cloud .cloud-ai > .feat-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.cloud-hero .page-hero-lede {
  color: #33566b;
}

/* Five clouds drifting across a sky behind the title. Adapted to move with
   `transform` rather than `margin-left`, so it composites instead of forcing
   layout on every frame; each cloud carries its own scale in --s so they can
   share one keyframe. */
/* The page itself keeps the site background; the sky is a band at the top that
   dissolves into it, so there is no line where blue stops and the rest of the
   site starts. `--sky-h` is shared by the gradient and the cloud layer, so the
   two always fade out together. */
.page-cloud {
  position: relative;
  --sky-h: 820px;
  background: var(--bg);
}

.page-cloud::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  z-index: 0;
  height: var(--sky-h);
  /* Both ends of the fade share one RGB, so it thins out instead of drifting
     through grey on the way to transparent. */
  background: linear-gradient(
    to bottom,
    #c6d9e8 0%,
    #d5e4ee 34%,
    rgba(222, 234, 241, 0.62) 66%,
    rgba(222, 234, 241, 0) 100%
  );
  pointer-events: none;
}

.page-cloud .site-footer {
  margin-top: 0;
}

/* The clouds live in the blue band and scroll away with it. The mask carries
   them off gradually, so the lowest ones thin out instead of being cut in half
   at the edge of the sky. */
.cloud-sky {
  position: absolute;
  inset: 0 0 auto;
  z-index: 0;
  height: var(--sky-h);
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 48%, transparent 92%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 48%, transparent 92%);
}

/* Everything else sits above the sky. */
.page-cloud > header,
.page-cloud > main,
.page-cloud > footer {
  position: relative;
  z-index: 1;
}

/* The header has to outrank them, not just the sky: the mobile nav sheet is a
   z-index inside the header's own stacking context, so with the header level
   with <main> the sheet was painting behind the page content. */
.page-cloud > header {
  z-index: 3;
}

.cloud {
  position: absolute;
  width: 200px;
  height: 60px;
  background: #fff;
  border-radius: 200px;
  animation: moveclouds var(--d, 20s) linear infinite;
}

.cloud::before,
.cloud::after {
  content: '';
  position: absolute;
  background: #fff;
  width: 100px;
  height: 80px;
  top: -15px;
  left: 10px;
  border-radius: 100px;
  transform: rotate(30deg);
}

.cloud::after {
  width: 120px;
  height: 120px;
  top: -55px;
  left: auto;
  right: 15px;
}

.x1 {
  --s: 1;
  --d: 34s;
  top: 16%;
  left: 8%;
  animation-delay: -4s;
}

.x2 {
  --s: 0.6;
  --d: 44s;
  top: 6%;
  left: 44%;
  opacity: 0.6;
  animation-delay: -26s;
}

.x3 {
  --s: 0.8;
  --d: 38s;
  top: 44%;
  left: 2%;
  opacity: 0.8;
  animation-delay: -15s;
}

.x4 {
  --s: 0.75;
  --d: 30s;
  top: 62%;
  left: 70%;
  opacity: 0.75;
  animation-delay: -21s;
}

.x5 {
  --s: 0.85;
  --d: 40s;
  top: 30%;
  left: 60%;
  opacity: 0.8;
  animation-delay: -33s;
}

.x6 {
  --s: 0.7;
  --d: 46s;
  top: 74%;
  left: 24%;
  opacity: 0.65;
  animation-delay: -12s;
}

.x7 {
  --s: 0.95;
  --d: 36s;
  top: 88%;
  left: 52%;
  opacity: 0.75;
  animation-delay: -28s;
}

@keyframes moveclouds {
  from {
    transform: translateX(46vw) scale(var(--s, 1));
  }
  to {
    transform: translateX(-52vw) scale(var(--s, 1));
  }
}

@media (prefers-reduced-motion: reduce) {
  .cloud {
    animation: none;
  }
}

@media (max-width: 1100px) {
  .page-cloud .feat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .page-cloud .feat-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 700px) {
  .cloud-hero {
    padding: 56px 0 48px;
  }
}

.cloud-price {
  margin-top: 64px;
  text-align: center;
}

.cloud-price-head {
  max-width: 58ch;
  margin: 0 auto;
}

.cloud-price h2 {
  font-size: clamp(26px, 3.4vw, 34px);
}

.cloud-price-lede {
  margin: 16px auto 0;
  font-size: 17px;
  color: var(--text-secondary);
}

/* Two plans side by side. There are no numbers here on purpose — the stores own
   the prices — so the tiles earn their keep by drawing the line between what is
   bought once and what is rented. */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: stretch;
  gap: 20px;
  max-width: 860px;
  margin: 36px auto 0;
  text-align: left;
}

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 32px 30px 34px;
}

.plan h3 {
  margin: 0;
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.plan-kind {
  margin: 5px 0 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--primary);
}

.plan-lede {
  margin: 14px 0 0;
  font-size: 16px;
  color: var(--text-secondary);
}

/* Pinned to the corner rather than stacked above the title: in the flow it
   would push this plan's heading down out of line with the other one's. */
.plan-flag {
  position: absolute;
  top: 26px;
  right: 26px;
  margin: 0;
  padding: 6px 13px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--primary);
  background: rgba(255, 255, 255, 0.8);
  border-radius: 999px;
}

/* The tint marks the one this page is about, without a border to do it. */
.plan-featured {
  background: linear-gradient(158deg, rgba(80, 138, 89, 0.16), rgba(80, 138, 89, 0.05));
  box-shadow: 0 22px 44px -28px rgba(80, 138, 89, 0.6);
}

.plan-points {
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 11px;
  font-size: 16px;
  color: var(--text-secondary);
}

.plan-points li {
  position: relative;
  padding-left: 27px;
}

.plan-points li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 7px;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
  transform: rotate(-45deg);
}

.cloud-price-note {
  max-width: 54ch;
  margin: 28px auto 0;
  font-size: 15px;
  color: var(--text-muted);
}

.cloud-price .cta-row {
  margin-top: 24px;
}

.cloud-id {
  margin-top: 64px;
}

.id-table-wrap {
  margin-top: 28px;
  padding: 8px 10px;
  overflow-x: auto;
}

.id-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
}

.id-table th,
.id-table td {
  padding: 14px 16px;
  text-align: left;
}

.id-table thead th {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.id-table tbody th {
  font-weight: 500;
  color: var(--text);
}

.id-table tbody tr + tr th,
.id-table tbody tr + tr td {
  border-top: 1px solid var(--divider, #f3f4f6);
}

.id-table td {
  width: 132px;
  color: var(--text-secondary);
}

.id-table .id-cloud {
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 600;
}

.id-yes {
  font-size: 18px;
  font-weight: 700;
  color: var(--primary);
}

.id-no {
  color: var(--text-muted);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 700px) {
  .plan-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }

  .plan {
    padding: 28px 24px 30px;
  }

  .id-table {
    font-size: 15px;
  }

  .id-table th,
  .id-table td {
    padding: 12px 10px;
  }

  .id-table td {
    width: 92px;
  }
}

/* Tarsi ID card ------------------------------------------------------------ */

.idcard-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.95fr);
  align-items: center;
  gap: 48px;
  margin-top: 72px;
}

.idcard-copy h2 {
  font-size: clamp(26px, 3.4vw, 34px);
}

.idcard-lede {
  margin: 16px 0 0;
  font-size: 17px;
  color: var(--text-secondary);
}

.idcard-points {
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  font-size: 16px;
  color: var(--text-secondary);
}

.idcard-points li {
  position: relative;
  padding: 7px 0 7px 26px;
}

.idcard-points li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 14px;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
  transform: rotate(-45deg);
}

.idcard-stage {
  display: flex;
  justify-content: center;
  perspective: 1000px;
}

/* ID-1 proportions, the same as the card in the app. */
.idcard {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: min(100%, 380px);
  aspect-ratio: 1.586;
  padding: 22px;
  overflow: hidden;
  background:
    radial-gradient(120% 140% at 12% 0%, rgba(255, 255, 255, 0.22) 0%, transparent 55%),
    linear-gradient(155deg, #5d9d67 0%, #3f7548 58%, #2f5c38 100%);
  border-radius: 22px;
  box-shadow:
    0 26px 44px -20px rgba(15, 42, 31, 0.55),
    inset 0 0 0 1px rgba(255, 255, 255, 0.22);
  animation: idcard-float 7s ease-in-out infinite;
}

.has-squircles .idcard {
  border-radius: 0;
}

/* A slow diagonal highlight, so the black reads as a finish rather than a flat
   fill. */
.idcard-sheen {
  position: absolute;
  inset: -40% -10%;
  background: linear-gradient(
    104deg,
    transparent 38%,
    rgba(255, 255, 255, 0.11) 47%,
    rgba(255, 255, 255, 0.02) 53%,
    transparent 62%
  );
  pointer-events: none;
}

@keyframes idcard-float {
  0%,
  100% {
    transform: translateY(0) rotateX(2.5deg) rotateZ(-0.6deg);
  }
  50% {
    transform: translateY(-10px) rotateX(-2.5deg) rotateZ(0.6deg);
  }
}

.idcard-top {
  position: relative;
  display: flex;
  align-items: center;
}

.idcard-logo {
  display: block;
  width: 50px;
  height: 50px;
  border-radius: 13px;
}

.has-squircles .idcard-logo {
  border-radius: 0;
}

.idcard-handle {
  position: relative;
  margin: 0;
  font-size: clamp(28px, 4.4vw, 34px);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: #ffffff;
}

.idcard-url {
  position: relative;
  margin: 4px 0 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.72);
}

@media (prefers-reduced-motion: reduce) {
  .idcard {
    animation: none;
  }
}

@media (max-width: 900px) {
  .idcard-block {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
    text-align: center;
  }

  .idcard-points {
    display: inline-block;
    text-align: left;
  }
}

/* Video reels -------------------------------------------------------------- */

/* Both clips sit in the recognition run: the phone walkthrough above the
   backing line, the teaser film above the press links. They are started and
   stopped by `video.js` as they scroll in and out of view. */
.reel {
  display: flex;
  justify-content: center;
  margin: 0 auto;
}

.reel video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--bg);
  border-radius: 24px;
  box-shadow: 0 30px 54px -26px rgba(17, 24, 39, 0.42);
}

.has-squircles .reel video {
  border-radius: 0;
}

.reel-demo {
  margin-bottom: 44px;
}

.reel-demo video {
  width: min(100%, 300px);
}

.reel-teaser {
  margin: 56px auto 48px;
}

.reel-teaser video {
  width: min(100%, 840px);
}

@media (max-width: 700px) {
  .reel-demo {
    margin-bottom: 34px;
  }

  .reel-demo video {
    width: min(100%, 262px);
  }

  .reel-demo .iphone {
    width: min(100%, 276px);
  }

  .reel-teaser {
    margin: 40px auto 34px;
  }
}

/* App screenshots ---------------------------------------------------------- */

/* Screenshots are 9:16, so they ride the art column of a side-by-side block
   rather than a full-width row, where a portrait phone would sit tiny and
   marooned in the middle of the page. */
.shot-frame {
  margin: 0;
}

/* Each screenshot sits in a CSS iPhone: a dark body, the screen inset by the
   bezel, and the Dynamic Island. Everything is a percentage of the phone's
   width, so it scales with the column. Corner radii are written per axis
   (width / height) so they stay circular on a tall phone. */
.iphone {
  --iphone-edge: 0 0 0 1px #8a8a90, 0 0 0 2.5px #3b3b40, inset 0 0 0 1px rgba(255, 255, 255, 0.09);
  --iphone-shadow:
    0 2px 4px rgba(15, 23, 42, 0.18),
    0 14px 28px -10px rgba(15, 23, 42, 0.28),
    0 44px 80px -34px rgba(15, 23, 42, 0.5);
  position: relative;
  display: block;
  width: 100%;
  padding: 2.4%;
  background: #050506;
  border-radius: 14.8% / 7%;
  box-shadow: var(--iphone-edge), var(--iphone-shadow);
  /* Tilt and scale live on the phone, never on the <figure>: the figure is what
     reveal.js animates, and `.reveal.is-visible { transform: none }` outranks
     anything set here, which would flatten a tilted shot mid-reveal. */
  transform-origin: 50% 60%;
  transition:
    transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow 0.5s ease;
}

.iphone img,
.iphone video {
  display: block;
  width: 100%;
  height: auto;
  background: #000;
  border-radius: 13% / 6%;
  box-shadow: none;
}

/* The recording (640 x 1302) plus the status-bar strip below makes a screen a
   touch taller than the screenshots, so the vertical radii keep the corners
   circular for that ratio. */
.iphone-video {
  border-radius: 14.8% / 7.04%;
}

.reel-demo .iphone-video video {
  width: 100%;
  border-radius: 13% / 6.4%;
}

.has-squircles .iphone video {
  border-radius: 13% / 6.4%;
}

/* The demo recording is cropped just below the status bar, so the app's
   header would touch the top of the glass. The screen adds that strip back in
   the recording's own background colour, with the Dynamic Island on it. */
.iphone-screen {
  position: relative;
  padding-top: 12.5%;
  background: #f6f9f8;
  border-radius: 13% / 6%;
  overflow: hidden;
}

.iphone .iphone-screen video,
.has-squircles .iphone .iphone-screen video {
  border-radius: 0;
}

/* Centred in the strip: margins resolve against width, like the padding. */
.iphone-screen .iphone-island {
  top: 0;
  margin-top: 2.2%;
  z-index: 1;
}

/* Side buttons in the titanium colour: power on the right; Action button and
   the two volume keys on the left, drawn as one strip with gaps. */
.iphone::before,
.iphone::after {
  content: '';
  position: absolute;
  width: 2.5px;
  border-radius: 2px;
}

.iphone::before {
  top: 25%;
  right: -4.5px;
  height: 11%;
  background: linear-gradient(to right, #4a4a50, #9a9aa0);
}

.iphone::after {
  top: 16%;
  left: -4.5px;
  height: 22%;
  background: linear-gradient(
    to bottom,
    #7a7a80 0%,
    #7a7a80 15%,
    transparent 15%,
    transparent 30%,
    #7a7a80 30%,
    #7a7a80 62%,
    transparent 62%,
    transparent 68%,
    #7a7a80 68%,
    #7a7a80 100%
  );
}

.iphone-island {
  position: absolute;
  top: 2.4%;
  left: 50%;
  width: 29%;
  aspect-ratio: 3.4 / 1;
  border-radius: 999px;
  background: #000;
  transform: translateX(-50%);
}

.feat-shot-led > .feat-shot-lead {
  grid-area: art;
  margin: 0;
}

.feat-shot-led > figure.feat-shot-lead {
  display: flex;
  justify-content: center;
}

.feat-shot-led > figure.feat-shot-lead .iphone {
  width: min(100%, 300px);
}

/* Two screenshots share one column by overlapping, so neither has to shrink to
   half-width to fit beside the other. */
.shot-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
}

/* The fan offsets are custom properties so the hover state can reuse them
   without restating the numbers at every breakpoint. */
.shot-pair .shot-frame {
  grid-area: 1 / 1;
  width: min(100%, 236px);
  --shot-x: 33%;
  --shot-y: 16px;
}

.shot-pair .shot-frame:first-child .iphone {
  transform: translate(calc(var(--shot-x) * -1), calc(var(--shot-y) * -1)) rotate(-5deg);
}

.shot-pair .shot-frame:last-child .iphone {
  transform: translate(var(--shot-x), var(--shot-y)) rotate(5deg);
}

/* The pair needs a wider column than a single phone does. */
.shot-led-pair {
  grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
}

@media (max-width: 900px) {
  .feat-shot-led > figure.feat-shot-lead .iphone {
    width: min(100%, 260px);
  }

  .shot-led-pair {
    grid-template-columns: minmax(0, 1fr);
  }

  .shot-pair {
    margin-bottom: 30px;
  }
}

/* Narrow screens have no room for the full fan, so the pair tightens rather
   than pushing the page into a horizontal scroll. */
@media (max-width: 520px) {
  .shot-pair .shot-frame {
    width: min(100%, 198px);
    --shot-x: 28%;
    --shot-y: 12px;
  }
}

/* Pointer devices only — on touch, :hover sticks after a tap and would leave a
   screenshot stuck mid-grow. The shadow deepens for everyone who can hover; the
   movement is held back from anyone who asked for less of it. */
@media (hover: hover) {
  .shot-frame:hover .iphone {
    box-shadow:
      var(--iphone-edge),
      0 3px 6px rgba(15, 23, 42, 0.18),
      0 20px 36px -12px rgba(15, 23, 42, 0.3),
      0 56px 96px -36px rgba(15, 23, 42, 0.55);
  }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  /* A lone screenshot sits square to the page, so hovering leans it and brings
     it forward. It leans away from the copy beside it. */
  .feat-left.feat-shot-led > figure.feat-shot-lead:hover .iphone {
    transform: rotate(-3.5deg) scale(1.06);
  }

  .feat-right.feat-shot-led > figure.feat-shot-lead:hover .iphone {
    transform: rotate(3.5deg) scale(1.06);
  }

  /* The pair is already fanned, so the one under the cursor straightens up and
     lifts clear of its neighbour instead — it keeps its offset, or it would
     grow straight into the other phone. */
  .shot-pair .shot-frame:hover {
    z-index: 1;
  }

  .shot-pair .shot-frame:first-child:hover .iphone {
    transform: translate(calc(var(--shot-x) * -1), calc(var(--shot-y) * -1)) rotate(0deg) scale(1.07);
  }

  .shot-pair .shot-frame:last-child:hover .iphone {
    transform: translate(var(--shot-x), var(--shot-y)) rotate(0deg) scale(1.07);
  }
}

/* Guide course ------------------------------------------------------------- */

.course-page {
  max-width: 1200px;
}

.course-hero {
  padding-bottom: 8px;
  text-align: left;
}

.course-hero .page-hero-lede {
  margin-inline: 0;
}

.course {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  align-items: start;
  gap: 28px;
  margin-top: 40px;
}

.course-nav {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.course-progress {
  padding: 18px 20px;
  background: var(--card);
  box-shadow: var(--shadow-soft);
}

.course-progress-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.course-progress-label,
.course-progress-count {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
}

.course-progress-count {
  color: var(--primary);
}

.course-bar {
  height: 10px;
  margin-top: 12px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.07);
  overflow: hidden;
}

.course-bar-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: var(--primary);
  transition: width 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.course-nav-toggle {
  display: none;
}

.course-outline {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.course-module-title {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 0 4px 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.course-module-count {
  color: var(--text-muted);
}

.course-lessons {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.course-lesson {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 6px;
  border-radius: 14px;
  transition: background 0.18s ease;
}

.course-lesson:hover {
  background: rgba(17, 24, 39, 0.04);
}

.course-lesson.is-current {
  background: var(--primary-soft);
}

.course-check {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
}

.course-check span {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 2px solid #d1d5db;
  border-radius: 50%;
  background: var(--card);
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}

.course-check svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: #ffffff;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}

.course-check:hover span {
  border-color: var(--primary);
}

.course-check:active span {
  transform: scale(0.9);
}

.course-lesson.is-done .course-check span {
  border-color: var(--primary);
  background: var(--primary);
}

.course-lesson.is-done .course-check svg {
  opacity: 1;
}

.course-check:focus-visible,
.course-lesson-link:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.course-lesson-link {
  display: grid;
  flex: 1;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 6px 6px 6px 2px;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
}

.course-lesson-num {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.course-lesson-time {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.course-lesson.is-current .course-lesson-title {
  color: var(--primary);
}

.course-lesson.is-done:not(.is-current) .course-lesson-title {
  color: var(--text-secondary);
}

.course-cert-link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 18px;
  background: rgba(17, 24, 39, 0.04);
  color: var(--text-secondary);
  transition: background 0.18s ease, transform 0.18s ease;
}

.course-cert-link:hover {
  transform: translateY(-1px);
}

.course-cert-link.is-unlocked {
  background: #0b0f0e;
  color: #ffffff;
}

.course-cert-link.is-current:not(.is-unlocked) {
  background: var(--primary-soft);
}

.course-cert-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--card);
}

.course-cert-link.is-unlocked .course-cert-icon {
  background: var(--primary);
}

.course-cert-icon svg,
.course-cert-hero-icon svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.course-cert-copy {
  display: flex;
  flex-direction: column;
  font-size: 13px;
  line-height: 1.35;
}

.course-cert-copy strong {
  font-size: 15px;
  color: inherit;
}

.course-cert-link:not(.is-unlocked) .course-cert-copy strong {
  color: var(--text);
}

.course-storage-note {
  margin: 0 4px;
  font-size: 12px;
  color: var(--text-muted);
}

.course-reset {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: underline;
  cursor: pointer;
}

.course-noscript a {
  color: var(--primary);
  text-decoration: underline;
}

/* The lesson itself. */
.course-lesson-view {
  padding: 28px;
  background: var(--card);
  box-shadow: var(--shadow);
  border-radius: var(--radius-card);
  animation: course-in 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
}

@keyframes course-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

.course-kicker {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--primary);
}

.course-title {
  margin-top: 8px;
  font-size: clamp(26px, 3vw, 34px);
}

.course-media {
  margin-top: 20px;
}

.course-player {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  border-radius: 18px;
  overflow: hidden;
}

.course-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.course-play {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: rgba(17, 24, 39, 0.78);
  transform: translate(-50%, -50%);
  transition: transform 0.2s ease, background 0.2s ease;
}

.course-play svg {
  width: 30px;
  height: 30px;
  margin-left: 4px;
  fill: #ffffff;
}

.course-player:hover .course-play,
.course-player:focus-visible .course-play {
  background: var(--primary);
  transform: translate(-50%, -50%) scale(1.08);
}

.course-duration {
  position: absolute;
  right: 12px;
  bottom: 12px;
  padding: 3px 9px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 700;
  color: #ffffff;
  background: rgba(17, 24, 39, 0.78);
}

.course-frame {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 18px;
}

.course-blurb {
  margin: 18px 0 0;
  max-width: 60ch;
  font-size: 17px;
  color: var(--text-secondary);
}

.course-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid rgba(17, 24, 39, 0.07);
}

.course-done {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 20px;
  border: 0;
  border-radius: 16px;
  background: var(--primary);
  color: var(--on-primary);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow-soft);
  transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.course-done:hover {
  transform: translateY(-1px);
}

.course-done:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.course-done > span:first-child:not(:only-child) svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.course-done > span:first-child:not(:only-child) {
  display: grid;
}

.course-done.is-done {
  background: var(--primary-soft);
  color: var(--primary);
  box-shadow: none;
}

.course-done.is-download {
  background: #0b0f0e;
}

.course-steps {
  display: flex;
  gap: 8px;
}

.course-step {
  padding: 11px 16px;
  border-radius: 14px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-secondary);
  background: rgba(17, 24, 39, 0.05);
  transition: background 0.18s ease, color 0.18s ease;
}

.course-step:hover {
  background: rgba(17, 24, 39, 0.09);
  color: var(--text);
}

.course-step-next.is-ready {
  background: #0b0f0e;
  color: #ffffff;
}

/* Certificate. */
.course-cert-view {
  text-align: center;
}

.course-cert-view .course-blurb {
  margin-inline: auto;
}

.course-cert-view .course-actions {
  justify-content: center;
}

.course-cert-hero-icon {
  display: inline-grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin-bottom: 14px;
  border-radius: 20px;
  background: var(--primary);
  color: #ffffff;
}

.course-cert-hero-icon.is-locked {
  background: rgba(17, 24, 39, 0.06);
  color: var(--text-secondary);
}

.course-cert-hero-icon svg {
  width: 30px;
  height: 30px;
}

.course-name-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
}

.course-name-label {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-secondary);
}

.course-name-input {
  width: min(100%, 420px);
  padding: 14px 16px;
  border: 2px solid rgba(17, 24, 39, 0.1);
  border-radius: 16px;
  background: var(--bg);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  text-align: center;
  color: var(--text);
  transition: border-color 0.18s ease, background 0.18s ease;
}

.course-name-input:focus {
  outline: none;
  border-color: var(--primary);
  background: var(--card);
}

/* The certificate floats on a 3D stage: square paper corners, a slow bob,
   a soft shadow on the "floor" that breathes with it, and a pointer tilt. */
.course-cert-stage {
  position: relative;
  margin: 8px auto 34px;
  padding: 18px 12px 40px;
  perspective: 1400px;
}

.course-cert-stage::after {
  content: '';
  position: absolute;
  left: 14%;
  right: 14%;
  bottom: 6px;
  height: 26px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(17, 24, 39, 0.28), rgba(17, 24, 39, 0));
  filter: blur(6px);
  animation: course-cert-floor 6s ease-in-out infinite;
}

.course-cert-float {
  transform-style: preserve-3d;
  animation: course-cert-float 6s ease-in-out infinite;
}

.course-cert-card {
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  position: relative;
  transform: rotateX(calc(8deg + var(--tilt-x))) rotateY(calc(-6deg + var(--tilt-y))) rotateZ(-0.6deg);
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
  box-shadow:
    0 1px 0 rgba(17, 24, 39, 0.04),
    0 18px 30px -12px rgba(17, 24, 39, 0.25),
    0 50px 70px -30px rgba(17, 24, 39, 0.35);
}

.course-cert-card.is-tilting {
  transition-duration: 0.12s;
}

.course-cert-canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2000 / 1414;
  border-radius: 0;
  background: var(--bg);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.course-cert-canvas.is-ready {
  opacity: 1;
}

.course-cert-shine {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    circle at var(--shine-x, 30%) var(--shine-y, 20%),
    rgba(255, 255, 255, 0.45),
    rgba(255, 255, 255, 0) 45%
  );
  mix-blend-mode: soft-light;
  opacity: 0.7;
}

@keyframes course-cert-float {
  0%,
  100% {
    transform: translateY(0) rotateZ(0deg);
  }
  50% {
    transform: translateY(-14px) rotateZ(0.8deg);
  }
}

@keyframes course-cert-floor {
  0%,
  100% {
    transform: scaleX(1);
    opacity: 1;
  }
  50% {
    transform: scaleX(0.86);
    opacity: 0.65;
  }
}

@media (prefers-reduced-motion: reduce) {
  .course-cert-float,
  .course-cert-stage::after {
    animation: none;
  }
}

@media (max-width: 900px) {
  .course {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    margin-top: 28px;
  }

  .course-nav-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    margin-top: 14px;
    padding: 10px;
    border: 0;
    border-radius: 12px;
    background: rgba(17, 24, 39, 0.05);
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-secondary);
    cursor: pointer;
  }

  .course-nav-toggle svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.4;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform 0.2s ease;
  }

  .course-nav-toggle[aria-expanded='true'] svg {
    transform: rotate(180deg);
  }

  .course-outline {
    display: none;
  }

  .course-outline.is-open {
    display: flex;
  }

  .course-storage-note {
    order: 3;
  }

  .course-lesson-view {
    padding: 18px;
  }

  .course-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .course-done {
    justify-content: center;
  }

  .course-steps {
    justify-content: space-between;
  }

  .course-step {
    flex: 1;
    text-align: center;
  }
}
