/* ============================================================================
   Karmanya — the premium layer.
   ----------------------------------------------------------------------------
   Art direction, stated so it can be argued with: Linear's restraint + an Apple
   product page's device reverence + the romance of a GitHub contribution graph,
   read as quiet dharmic editorial. Deep indigo void, saffron sparks, karma-green
   cells. One mesh, not five competing blobs. Grain and vignette.

   Deliberately NOT: rainbow SaaS gradients, a 3x3 grid of equal cards, 3D for
   its own sake, or an effect on every element. The heatmap cell is the logo
   language and gets to be the hero motif; everything else stays out of its way.

   CSS 3D throughout rather than WebGL for the device: it costs nothing at first
   paint, degrades to a flat card, and a real screenshot inside a real frame
   reads more honest than a GLB of a phone.
   ========================================================================= */

/* ---------------------------------------------------------------- hero shell */
.hero-pro {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding: clamp(56px, 8vw, 104px) 0 clamp(64px, 9vw, 128px);
}

/* The verse as an oversized background glyph. Set in Devanagari at a size that
   makes it texture rather than text — the English headline in front carries the
   meaning, this carries the mood. */
.hero-glyph {
  position: absolute;
  left: 50%;
  top: 44%;
  transform: translate(-50%, -50%);
  font-family: var(--font-display);
  font-size: clamp(84px, 15vw, 260px);
  line-height: 0.86;
  white-space: nowrap;
  color: transparent;
  background: linear-gradient(180deg, rgba(195, 180, 255, 0.13), rgba(195, 180, 255, 0.015) 72%);
  -webkit-background-clip: text;
  background-clip: text;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  letter-spacing: -0.02em;
}

.hero-grid {
  position: relative;
  z-index: 2;
  display: grid;
  gap: clamp(28px, 5vw, 64px);
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
}
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; text-align: center; }
  .hero-copy .cta-row, .hero-copy .promises { justify-content: center; }
}

.hero-copy h1 {
  margin: 12px 0 18px;
  /* 15ch was too tight for "Let go of the fruit." at display size and broke it
     across three ragged lines. The <br> already controls the intended break, so
     each line just needs room not to wrap again. */
  max-width: 20ch;
  font-size: clamp(38px, 5.6vw, 70px);
  line-height: 1.03;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
@media (max-width: 960px) { .hero-copy h1 { max-width: none; margin-inline: auto; } }

.hero-copy .lede { margin-left: 0; margin-right: 0; max-width: 46ch; }
@media (max-width: 960px) { .hero-copy .lede { margin-inline: auto; } }

.verse-line {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--font-ui);
  font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--indigo-80);
}
.verse-line::before {
  content: ""; width: 34px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--indigo-60));
}

/* ---------------------------------------------------------------- 3D device
   A perspective wrapper holds the tilt so the device's own transform stays
   available for the float animation — stacking both on one element means the
   pointer handler fights the keyframes. */
.stage {
  position: relative;
  perspective: 1400px;
  perspective-origin: 50% 40%;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: clamp(420px, 52vw, 620px);
}

.device {
  position: relative;
  width: clamp(228px, 25vw, 300px);
  aspect-ratio: 1080 / 2340;
  transform-style: preserve-3d;
  /* --rx/--ry are written by premium.js from pointer position. */
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 0.12s linear;
  will-change: transform;
}

.device-frame {
  position: absolute;
  inset: 0;
  border-radius: 13% / 6%;
  padding: 2.6%;
  background:
    linear-gradient(155deg, #3a3552 0%, #14121f 38%, #0c0a14 62%, #2a2640 100%);
  box-shadow:
    0 2px 3px rgba(255, 255, 255, 0.16) inset,
    0 -2px 4px rgba(0, 0, 0, 0.8) inset,
    0 44px 80px -30px rgba(0, 0, 0, 0.95),
    0 12px 40px -18px rgba(108, 90, 214, 0.55);
  transform-style: preserve-3d;
}

.device-screen {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 11% / 5%;
  overflow: hidden;
  background: var(--ink-900);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.9);
}
/* Every screenshot is stacked; premium.js fades the active one in. Using opacity
   rather than display keeps the crossfade smooth and the layout stable. */
.device-screen img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top center;
  opacity: 0;
  transition: opacity 0.5s var(--ease-out);
}
.device-screen img.is-active { opacity: 1; }

/* Specular sheen. Tracks the tilt, so the glass reads as glass. */
.device-glare {
  position: absolute;
  inset: 0;
  border-radius: 13% / 6%;
  pointer-events: none;
  background: linear-gradient(
    var(--glare-angle, 120deg),
    rgba(255, 255, 255, 0.16) 0%,
    rgba(255, 255, 255, 0.04) 22%,
    transparent 48%
  );
  mix-blend-mode: screen;
  z-index: 3;
}

/* The notch/camera pill, and the softer bottom bar. Small details, but their
   absence is what makes a mockup look drawn rather than photographed. */
.device-notch {
  position: absolute;
  top: 3.4%; left: 50%;
  transform: translateX(-50%);
  width: 22%; height: 1.15%;
  border-radius: 999px;
  background: #05040a;
  z-index: 4;
}

/* A round Wear mockup orbiting the phone — the watch app is a real surface and
   deserves to be shown, not just claimed in a bullet. */
.device-watch {
  position: absolute;
  /* Far enough out to clear the screen: at -4% it sat on top of the phone's own
     habit rows and nav bar, hiding the very UI the hero is showing off. It should
     read as a second device orbiting the first, not a sticker on the glass. */
  right: -22%;
  bottom: 4%;
  width: clamp(78px, 8.6vw, 104px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: linear-gradient(150deg, #3a3552, #100e19 55%, #262239);
  padding: 7px;
  box-shadow:
    0 2px 2px rgba(255, 255, 255, 0.14) inset,
    0 24px 44px -18px rgba(0, 0, 0, 0.95),
    0 6px 22px -8px rgba(245, 165, 36, 0.32);
  transform: translateZ(60px) rotate(-6deg);
  z-index: 5;
}
.device-watch-face {
  width: 100%; height: 100%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #171429, #08070f 70%);
  display: grid;
  place-content: center;
  gap: 4px;
  text-align: center;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.9);
}
.device-watch-face b {
  font-family: var(--font-display);
  font-size: clamp(15px, 1.7vw, 21px);
  line-height: 1;
  color: var(--karma-green);
}
.device-watch-face i {
  font-style: normal;
  font-size: 8.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
@media (max-width: 520px) { .device-watch { display: none; } }

/* Floating idle motion, on the wrapper so it composes with the tilt. */
.device-float { animation: float 7.5s ease-in-out infinite; transform-style: preserve-3d; }
@keyframes float {
  0%, 100% { transform: translateY(-8px); }
  50%      { transform: translateY(10px); }
}

/* ---------------------------------------------------------------- magnetic CTA */
.magnetic { will-change: transform; }

/* ---------------------------------------------------------------- bento
   Asymmetric on purpose: one wide heatmap, two narrow callouts, one quote.
   An equal 3x3 grid is what makes these sections feel like a template. */
.bento {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: minmax(150px, auto);
}
.bento > * { border-radius: var(--radius-lg); }
.b-heatmap { grid-column: span 2; grid-row: span 2; }
.b-stat    { grid-column: span 1; }
.b-tilt    { grid-column: span 1; grid-row: span 2; }
.b-quote   { grid-column: span 2; }
@media (max-width: 900px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .b-heatmap, .b-quote { grid-column: span 2; }
  .b-tilt { grid-column: span 2; grid-row: span 1; }
}
@media (max-width: 560px) {
  .bento { grid-template-columns: 1fr; }
  .b-heatmap, .b-quote, .b-tilt, .b-stat { grid-column: span 1; grid-row: span 1; }
}

.panel {
  position: relative;
  overflow: hidden;
  padding: 24px;
  background: linear-gradient(158deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.012));
  border: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(18px) saturate(1.35);
  -webkit-backdrop-filter: blur(18px) saturate(1.35);
  transition: border-color 0.3s ease, transform 0.3s var(--ease-out);
}
.panel:hover { border-color: rgba(142, 123, 239, 0.34); }
.panel h3 { margin: 0 0 6px; font-size: 17px; }
.panel p  { margin: 0; color: var(--text-dim); font-size: 14.5px; }
.panel .kicker {
  font-family: var(--font-ui);
  font-size: 11px; font-weight: 700; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--indigo-60);
  margin-bottom: 12px;
}

/* Cursor-tracked border spotlight, shared by every panel. */
.panel { --mx: 50%; --my: 50%; }
.panel::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(200px circle at var(--mx) var(--my), rgba(195, 180, 255, 0.6), transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
.panel:hover::after { opacity: 1; }

/* ---------------------------------------------------------------- live heatmap
   The centrepiece. Cells fill as the section scrolls into view, and light up
   karma-green by proximity to the cursor — the contribution graph as something
   you can put your hand into. */
/* The grid is laid out as the app lays it out: a gutter of weekday initials,
   a row of month names, and the cells themselves. */
.hm-frame {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 7px;
  row-gap: 5px;
  margin-top: 18px;
}
.hm-months {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  grid-auto-flow: column;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  line-height: 1;
}
.hm-months span { white-space: nowrap; }
.hm-days {
  grid-column: 1;
  grid-row: 2;
  display: grid;
  grid-template-rows: repeat(7, 1fr);
  gap: var(--hm-gap, 3px);
  font-size: 9px;
  line-height: 1;
  color: var(--text-faint);
}
.hm-days span { display: grid; place-items: center end; }

.hm {
  grid-column: 2;
  grid-row: 2;
  display: grid;
  /* auto rows, not 1fr: the row height must come from the cell's own square
     aspect rather than from a height the container has decided in advance. */
  grid-template-rows: repeat(7, auto);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--hm-gap, 3px);
}
/* Square, always. This is the one property that makes it read as the app's
   calendar boxes instead of a stretched bar chart. */
.hm-cell {
  aspect-ratio: 1;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.045);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02);
  transition: background-color 0.22s ease, transform 0.22s ease;
}
/* Days that have not happened yet. The app leaves them blank rather than
   showing them as missed, and so should this. */
.hm-cell.is-future {
  background: transparent;
  box-shadow: none;
}
/* 53 columns in a ~340px card leaves no room for a 3px gap. */
@media (max-width: 720px) {
  .hm-frame { --hm-gap: 2px; column-gap: 5px; }
  .hm-days { font-size: 8px; }
  .hm-months { font-size: 9px; }
}
.hm-legend {
  display: flex; align-items: center; gap: 8px;
  margin-top: 14px; font-size: 12px; color: var(--text-faint);
}
.hm-legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

/* ---------------------------------------------------------------- counter */
.counter {
  font-family: var(--font-display);
  font-size: clamp(34px, 4.6vw, 52px);
  line-height: 1;
  letter-spacing: -0.02em;
  background: linear-gradient(120deg, var(--indigo-80), var(--saffron));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- tilt card */
.tilt-inner {
  transform-style: preserve-3d;
  transform: rotateX(var(--trx, 0deg)) rotateY(var(--try, 0deg));
  transition: transform 0.14s linear;
  height: 100%;
  display: flex; flex-direction: column; justify-content: space-between;
}
.tilt-badge {
  align-self: flex-start;
  transform: translateZ(38px);
  padding: 9px 15px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600;
  color: var(--saffron);
  background: rgba(245, 165, 36, 0.11);
  border: 1px solid rgba(245, 165, 36, 0.3);
  box-shadow: 0 10px 30px -12px rgba(245, 165, 36, 0.5);
}
.tilt-num {
  transform: translateZ(22px);
  font-family: var(--font-display);
  font-size: clamp(40px, 5.6vw, 68px);
  line-height: 0.95;
  color: var(--text);
}

/* ---------------------------------------------------------------- quote */
.b-quote { display: flex; flex-direction: column; justify-content: center; }
.b-quote blockquote {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(18px, 2.2vw, 25px);
  line-height: 1.35;
  letter-spacing: -0.015em;
  color: var(--text);
}
.b-quote cite { display: block; margin-top: 14px; font-style: normal; font-size: 13px; color: var(--text-faint); }

/* ---------------------------------------------------------------- feature switcher
   Hovering (or focusing) a feature row changes the screen inside the hero-style
   device beside it. Keyboard-reachable, because a hover-only interaction hides
   content from anyone not using a mouse. */
.switch-grid {
  display: grid; gap: clamp(26px, 4vw, 56px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  align-items: center;
}
@media (max-width: 900px) { .switch-grid { grid-template-columns: 1fr; } }

.switch-list { display: flex; flex-direction: column; gap: 6px; }
.switch-item {
  display: block; width: 100%; text-align: left;
  padding: 18px 20px; border-radius: var(--radius);
  background: transparent; border: 1px solid transparent;
  color: inherit; font: inherit; cursor: pointer;
  transition: background 0.28s ease, border-color 0.28s ease, transform 0.28s var(--ease-out);
}
.switch-item h3 { margin: 0 0 4px; font-size: 17px; color: var(--text-dim); transition: color 0.28s ease; }
.switch-item p  { margin: 0; font-size: 14.5px; color: var(--text-faint); max-height: 0; overflow: hidden; opacity: 0;
                  transition: max-height 0.4s var(--ease-out), opacity 0.3s ease, margin 0.3s ease; }
.switch-item[aria-selected="true"] {
  background: linear-gradient(120deg, rgba(142, 123, 239, 0.11), rgba(142, 123, 239, 0.03));
  border-color: rgba(142, 123, 239, 0.28);
}
.switch-item[aria-selected="true"] h3 { color: var(--text); }
.switch-item[aria-selected="true"] p { max-height: 6em; opacity: 1; margin-top: 6px; }
.switch-item:focus-visible { outline: 2px solid var(--indigo-80); outline-offset: 2px; }

/* ---------------------------------------------------------------- custom cursor
   Desktop pointer only, and never over text inputs. The lagged ring is the
   whole effect; a big blob following the mouse is just in the way. */
.cursor-dot, .cursor-ring {
  position: fixed; top: 0; left: 0;
  pointer-events: none; z-index: 90;
  border-radius: 50%;
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.cursor-dot  { width: 6px;  height: 6px;  background: var(--indigo-80); }
.cursor-ring { width: 34px; height: 34px; border: 1px solid rgba(195, 180, 255, 0.45); }
body.has-cursor .cursor-dot, body.has-cursor .cursor-ring { opacity: 1; }
body.cursor-hot .cursor-ring { width: 54px; height: 54px; border-color: rgba(245, 165, 36, 0.6); }

/* ---------------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .device-float { animation: none; }
  .device, .tilt-inner { transform: none !important; transition: none; }
  .cursor-dot, .cursor-ring { display: none; }
  .hm-cell { transition: none; }
  .switch-item p { max-height: 6em; opacity: 1; margin-top: 6px; }
}

/* ---------------------------------------------------------------- rhythm
   site.css sets a generous section padding that suited the shorter page. With
   the bento and switcher added, consecutive sections left gaps large enough to
   read as missing content rather than breathing room. */
#components, #surfaces, #promise, #faq { padding-top: clamp(44px, 6vw, 78px); padding-bottom: clamp(44px, 6vw, 78px); }
#components .bento { margin-top: 32px; }

/* ---------------------------------------------------------------- hero alignment
   site.css centres .hero for the old single-column layout. In the two-column
   arrangement that leaves the copy centred inside its own column beside the
   device, which reads as accidental rather than asymmetric. Left-align the copy
   at desktop; the single-column mobile layout keeps centring, where it is right. */
@media (min-width: 961px) {
  .hero-pro { text-align: left; }
  .hero-copy .cta-row, .hero-copy .promises { justify-content: flex-start; }
}

/* The watch now sits outside the phone, so the stage must not clip it. */
.stage { overflow: visible; }
@media (min-width: 961px) { .hero-grid { gap: clamp(28px, 5vw, 48px); } }

/* ============================================================================
   Chapters — scroll-driven feature sections with overlapping devices.
   ----------------------------------------------------------------------------
   Three ideas here, all in service of depth rather than novelty:

   1. Each chapter holds *two* devices, and they genuinely overlap. Two mockups
      sitting side by side with a gap between them is just a product shot done
      twice; the overlap is what creates a foreground and a background, and it
      has to be a real intersection (~14% of the stage) to read as one.
   2. Which device is elevated alternates chapter to chapter, and the elevated
      one is always the larger one — a small device in front of a big one
      contradicts the perspective and the whole effect collapses. So `--flip`
      swaps their *positions*, not their sizes.
   3. A large outlined word sits behind the pair and scrolls at a slower rate.
      It is deliberately pushed toward the outer edge so it is not entirely
      eclipsed by the devices: a background layer you cannot see is not a
      background layer, it is a wasted paint.

   Every offset is a percentage of the stage, so the composition holds at every
   width rather than only at the one it was authored on.
   ========================================================================= */
/* The background word deliberately bleeds past the stage; clipping it here is
   what keeps that from becoming a horizontal scrollbar at narrow widths. */
.chapters { position: relative; overflow: hidden; }

.chapter {
  position: relative;
  display: grid;
  /* The stage gets the larger share: two overlapping phones need the room, and
     the copy reads better at ~44ch than stretched across half a 1120px page. */
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(20px, 3.5vw, 56px);
  align-items: center;
  padding: clamp(56px, 9vh, 112px) 0;

  /* Geometry, swapped wholesale by --flip below. */
  --big-left: 3%;
  --small-left: 42%;
  --word-right: -10%;
  --tilt-big: -8deg;
  --tilt-small: 7deg;
}

/* Alternate the side. `order` rather than `direction` so the DOM order stays
   copy-then-image, which is also the order a screen reader should meet them. */
.chapter--flip .ch-copy { order: 2; }
.chapter--flip .ch-stage { order: 1; }
.chapter--flip {
  --big-left: 45%;
  --word-right: auto;
  --small-left: 4%;
  --word-left: -10%;
  --tilt-big: 8deg;
  --tilt-small: -7deg;
}

.ch-copy { position: relative; z-index: 4; max-width: 44ch; }
.ch-copy h3 {
  font-family: var(--font-serif);
  font-size: clamp(1.8rem, 3.2vw, 2.7rem);
  line-height: 1.07;
  letter-spacing: -0.018em;
  margin: 10px 0 14px;
  text-wrap: balance;
}
.ch-copy > p { color: var(--text-dim); font-size: 1.01rem; line-height: 1.66; }

/* The detail list. Each row is one concrete mechanic, because "powerful
   insights" persuades nobody and "long-press any past day" persuades anyone who
   has ever missed a day. */
.ch-points { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 11px; }
.ch-points li {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 11px;
  align-items: start;
  font-size: 0.93rem;
  color: var(--text-dim);
  line-height: 1.55;
}
/* A heatmap cell, not a bullet or a tick. The cell is the logo language, so it
   is the mark that should repeat down the page. */
.ch-points li::before {
  content: "";
  width: 9px; height: 9px;
  margin-top: 6px;
  border-radius: 2.5px;
  background: var(--cell, var(--indigo-60));
  box-shadow: 0 0 12px -1px var(--cell, var(--indigo-60));
}

/* --------------------------------------------------------------- the stage */
.ch-stage {
  position: relative;
  perspective: 1500px;
  perspective-origin: 50% 42%;
  /* Tall enough for the taller of the two devices plus its caption. The pair is
     sized in % of the stage width, so this has to track viewport width too. */
  min-height: clamp(430px, 44vw, 620px);
}

/* The word behind everything. `-webkit-text-stroke` gives a true outline that
   follows the glyph shapes and scales with the font; a border or an SVG would
   not. */
.ch-word {
  position: absolute;
  /* Anchored to whichever edge faces away from the copy, and bled 10% past it.
     Sitting high means the top third clears the rear device, so part of the
     word is always legible no matter how the pair overlaps. */
  top: 1%;
  left: var(--word-left, auto);
  right: var(--word-right, auto);
  font-family: var(--font-serif);
  font-size: clamp(5rem, 14.5vw, 13rem);
  line-height: 0.8;
  letter-spacing: -0.045em;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(195, 180, 255, 0.3);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}

/* The pair. `.pd-big` is the subject and always in front; `.pd-small` sits
   behind and lower, so the silhouette is a stepped diagonal rather than two
   rectangles of equal weight. */
.pd { position: absolute; transform-style: preserve-3d; }
.pd .device { width: 100%; }

.pd-big {
  left: var(--big-left);
  top: 1%;
  width: 51%;
  z-index: 3;
}
.pd-small {
  left: var(--small-left);
  top: 19%;
  width: 43%;
  z-index: 2;
  opacity: 0.86;
}

/* A resting tilt so the pair is not two flat rectangles, angled toward the copy
   column. The float animation is not applied here — three pairs of drifting
   phones down one page is restless, and the parallax already supplies motion. */
.pd-big .device { transform: rotateY(var(--tilt-big)) rotateX(1.5deg); }
.pd-small .device { transform: rotateY(var(--tilt-small)) rotateX(1.5deg); }

/* A caption naming what you are looking at. Without it the second screen is
   just texture. */
.pd-tag {
  position: absolute;
  left: 50%;
  bottom: -32px;
  transform: translateX(-50%);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  background: rgba(12, 10, 20, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  padding: 5px 12px;
  backdrop-filter: blur(8px);
  white-space: nowrap;
}
/* The rear device's caption would collide with the front device's body. Pin it
   to its own outer edge instead of centring it. */
.pd-small .pd-tag { left: auto; right: 0; transform: none; }

@media (max-width: 900px) {
  .chapter {
    grid-template-columns: 1fr;
    /* Enough clearance that the front phone's top glow does not graze the last
       line of copy. */
    gap: 30px;
    padding: clamp(44px, 7vh, 74px) 0;
  }
  .chapter--flip .ch-copy,
  .chapter--flip .ch-stage { order: initial; }
  .ch-copy { max-width: none; }

  /* Absolute positioning is the wrong tool once the layout stacks. Percentage
     offsets that read as an overlap in a 590px stage spread the pair apart in
     an 834px one, and a stage whose height has to be guessed with min-height
     either clips the phones or leaves a hole under them.
     Flex instead: the overlap is a negative margin, and the stage is exactly as
     tall as the taller phone at every width. The px cap matters too — 54% of a
     tablet-width stage is a 450px-wide phone, which is larger than the real
     thing and reads as a mistake. */
  .ch-stage {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    /* An explicit width, not max-width plus auto margins: auto inline margins
       stop a grid item stretching, which leaves its width indefinite, which
       makes the phones' percentage widths resolve against nothing and collapse
       the whole stage to zero. `justify-self` does the centring instead. */
    width: min(100%, 470px);
    justify-self: center;
    min-height: 0;
    perspective: 1200px;
  }
  /* `left`/`top` still offset a relatively-positioned box, so the desktop
     percentages have to be cleared explicitly or they push the rear phone clear
     of the stage and turn the overlap into a 122px gap. */
  .pd { position: relative; left: auto; top: auto; }
  .pd-big { width: 54%; }
  .pd-small { width: 45%; margin-left: -13%; margin-top: 9%; }

  /* Two overlapping phones already fill a 390px stage edge to edge. There is no
     room left for the word to be legible, and a cramped outline behind them
     reads as a rendering fault rather than as depth. Drop it. */
  .ch-word { display: none; }
  .pd-tag { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Parallax is GSAP-driven and motion.js already disables it wholesale. The
     resting tilt is static, but flattening it removes the last cue that the
     page wants to move. */
  .pd-big .device, .pd-small .device { transform: none; }
}

/* ---------------------------------------------------------------- hero weekly mock
   Drawn in HTML so the hero can show a populated week (specific habits, ~20%
   open cells) without waiting on a new emulator capture. */
.wk {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 1.6%;
  padding: 7% 5% 4%;
  background: #0c0a12;
  color: #ece8f8;
  font-family: var(--font-sans, system-ui);
}
.wk-top { display: flex; align-items: baseline; justify-content: space-between; }
.wk-top strong { display: block; font-size: 11px; letter-spacing: -0.03em; }
.wk-top span { display: block; font-size: 7px; color: #9a93b3; margin-top: 1px; }
.wk-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  font-size: 6.5px;
  color: #7a7494;
  text-align: center;
  border-bottom: 1px solid rgba(255,255,255,.06);
  padding-bottom: 3%;
}
.wk-tabs b {
  color: #c4b4ff;
  font-weight: 600;
  box-shadow: 0 2px 0 #6c5ad6;
  padding-bottom: 4%;
}
.wk-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2%;
}
.wk-days span {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 6px;
  color: #8a84a4;
  border-radius: 999px;
  padding: 8% 0;
}
.wk-days em { font-style: normal; font-size: 5.5px; }
.wk-days .is-done { color: #c4b4ff; box-shadow: inset 0 0 0 1px rgba(196,180,255,.35); }
.wk-days .is-today { color: #4ade80; box-shadow: inset 0 0 0 1.5px #4ade80; }
.wk-habit {
  background: #161322;
  border-radius: 10px;
  padding: 3.2% 3.6% 2.8%;
}
.wk-hh { display: flex; align-items: center; gap: 6px; }
.wk-hh i { font-style: normal; font-size: 10px; width: 16px; text-align: center; }
.wk-hh div { flex: 1; min-width: 0; }
.wk-hh b { display: block; font-size: 7.5px; font-weight: 600; letter-spacing: -0.02em; }
.wk-hh small { display: block; font-size: 6px; color: #8a84a4; }
.wk-hh em {
  width: 13px; height: 13px; border-radius: 50%;
  border: 1.5px solid #3a3552;
  flex: none;
}
.wk-hh em.on { background: var(--h, #6c5ad6); border-color: transparent; }
.wk-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3%;
  margin-top: 6%;
}
.wk-row i {
  aspect-ratio: 1;
  border-radius: 50%;
  background: #2a2640;
}
.wk-row i.on { background: var(--h, #6c5ad6); }

.device-chip {
  position: absolute;
  left: -18%;
  top: 11%;
  z-index: 6;
  background: rgba(12, 10, 20, 0.88);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 14px;
  padding: 8px 12px 9px;
  backdrop-filter: blur(10px);
  box-shadow: 0 12px 28px -14px rgba(0,0,0,.8);
  transform: rotate(-4deg);
}
.device-chip b {
  display: block;
  font-family: var(--font-display);
  font-size: 15px;
  line-height: 1;
  color: var(--karma-green);
}
.device-chip span {
  display: block;
  margin-top: 3px;
  font-size: 8px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
@media (max-width: 720px) { .device-chip { display: none; } }

.ch-word--stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  white-space: normal;
  line-height: 0.76;
}
.ch-word--long {
  font-size: clamp(2.6rem, 8.2vw, 7.4rem);
  letter-spacing: -0.06em;
}

/* Experimental callouts — hidden on small screens so they cannot overflow. */
.anno-host { position: relative; }
.anno-svg {
  position: absolute;
  inset: 8% 4% 18% 4%;
  width: auto; height: auto;
  pointer-events: none;
  z-index: 2;
  overflow: visible;
}
.anno-svg--stage { inset: 0; }
.anno-path {
  fill: none;
  stroke: rgba(245, 165, 36, 0.72);
  stroke-width: 0.55;
  stroke-dasharray: 1.2 1.4;
  stroke-linecap: round;
}
.anno-card {
  position: absolute;
  left: var(--ax, 56%);
  top: var(--ay, 4%);
  width: min(220px, 42%);
  z-index: 3;
  pointer-events: none;
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-dim);
  background: rgba(10, 8, 16, 0.78);
  border: 1px solid rgba(245, 165, 36, 0.28);
  border-radius: 10px;
  padding: 8px 10px;
}
.anno-card b {
  display: block;
  color: var(--saffron);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 3px;
}
@media (max-width: 900px) {
  .anno-svg, .anno-card { display: none; }
}

.kit-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1.4fr 0.9fr;
  margin-top: 36px;
}
.kit-widgets { grid-column: 1; grid-row: span 2; }
.kit-wear, .kit-templates { grid-column: 2; }
@media (max-width: 800px) {
  .kit-grid { grid-template-columns: 1fr; }
  .kit-widgets, .kit-wear, .kit-templates { grid-column: auto; grid-row: auto; }
}

.home-board {
  display: grid;
  gap: 10px;
  margin-top: 16px;
  padding: 14px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 80% 0%, rgba(108,90,214,.18), transparent 50%),
    #12101a;
}
.wid {
  background: #1a1724;
  border-radius: 14px;
  padding: 10px 12px 12px;
}
.wid header { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.wid header b { font-size: 13px; }
.wid header small { font-size: 11px; color: var(--text-faint); }
.wid-grid {
  display: grid;
  grid-template-columns: repeat(16, minmax(0, 1fr));
  gap: 3px;
  margin-top: 8px;
}
.wid-grid i {
  aspect-ratio: 1;
  border-radius: 2px;
  background: color-mix(in srgb, var(--c) 16%, #2a2640);
}
.wid-grid i.on { background: var(--c); }

.wear-hero { display: grid; place-items: center; padding: 18px 0 8px; }
.wear-body {
  width: min(168px, 70%);
  position: relative;
}
.wear-lugs {
  position: absolute;
  left: 18%; right: 18%;
  top: -10%; bottom: -10%;
  border-radius: 18px;
  background: linear-gradient(#2a2640, #14121f);
  z-index: 0;
}
.wear-bezel {
  position: relative;
  z-index: 1;
  aspect-ratio: 1;
  border-radius: 50%;
  padding: 9px;
  background: conic-gradient(from 210deg, #4a4560, #1a1724 40%, #3a3552 70%, #4a4560);
  box-shadow: 0 16px 32px -18px #000;
}
.wear-face {
  height: 100%;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 30%, #1c1830, #08070f 70%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 14%;
}
.wear-face small { font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); }
.wear-face b { font-family: var(--font-display); font-size: 26px; color: var(--karma-green); line-height: 1.05; margin: 4px 0 8px; }
.wear-face ul { list-style: none; margin: 0; padding: 0; font-size: 10px; color: #c8c2dc; }
.wear-face li + li { margin-top: 2px; }
.wear-face li.done { color: var(--karma-green); }

.tpl-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}
.tpl-grid span {
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.08);
}

@media (prefers-reduced-motion: reduce) {
  .quote-rail-track { animation: none !important; }
}
