/* Stay Unseen — product site.

   Deliberately cheap to render. The previous stylesheet ran 27 keyframe
   animations, 22 blurs and 10 backdrop-filters over a full-page canvas, which
   is what made the page crawl on phones and stutter on desktop: every frame
   re-rasterised blurred layers that were never going to change meaningfully.
   Nothing here animates on its own. The only motion is a one-shot reveal per
   section and hover feedback, both opacity/transform so they stay on the
   compositor, and both dropped under prefers-reduced-motion.

   Colours are sampled from icons/icon128.png: the slate frame (#343b45), the
   steel of the eye (#6b8aa7), the violet ghost (#6d5da8), the deep blue badge
   (#405687) and its near-white highlight (#e1e9f4). The two accents are lifted
   to the extension popup's own --blue and --lav so the site, the popup and the
   icon read as one thing. */

:root {
  --bg: #191d25;
  --bg-deep: #13161d;
  --card: #20252f;
  --card-hi: #262c38;
  --line: #2f3745;
  --line-hi: #3f4a5e;
  --ink: #e9edf7;
  --muted: #a3aec9;
  --dim: #7d879f;
  --steel: #83b8d7;
  --lav: #a7a0e8;
  --indigo: #405687;
  --good: #79d8a2;
  --ramp: linear-gradient(90deg, var(--steel), var(--lav));
  --radius: 14px;
  --pad: clamp(20px, 5vw, 40px);
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter,
    "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono",
    monospace;
}

*,
*::before,
*::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  /* One static paint. No fixed attachment: on mobile that forces a repaint of
     the whole viewport on every scroll frame. The second radial, bottom-left,
     balances the top-right one and costs the same single paint. */
  background-image:
    radial-gradient(1100px 620px at 82% -8%, #252d40 0%, transparent 70%),
    radial-gradient(900px 560px at -6% 108%, #23274180 0%, transparent 72%);
  color: var(--ink);
  font: 400 17px/1.65 var(--font);
  letter-spacing: -0.006em;
}

/* The icon's ramp, as a hairline across the top of the page. */
body::before {
  content: "";
  display: block;
  height: 3px;
  background: var(--ramp);
}

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

/* Figures carry a 40px side margin by UA default, which silently narrowed both
   the hero popup and the screenshot frames. */
figure { margin: 0; }

a { color: var(--steel); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--lav); }

code {
  font: 500 0.86em/1.4 var(--mono);
  background: #ffffff0d;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 5px;
  color: #cfd8ee;
  word-break: break-word;
}

h1, h2, h3 { letter-spacing: -0.025em; line-height: 1.12; margin: 0; }

:focus-visible {
  outline: 2px solid var(--lav);
  outline-offset: 3px;
  border-radius: 6px;
}

.wrap {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 var(--pad);
}

/* --- header ---------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  /* Opaque, not blurred: a sticky backdrop-filter re-rasterises the strip on
     every scroll frame, and at less than full opacity the content underneath
     shows through it. */
  background: var(--bg-deep);
  border-bottom: 1px solid var(--line);
}

/* Scroll progress: a 2px strip, scaleX'd by script inside one rAF per frame.
   Pure transform, never repainted, and dropped entirely under
   prefers-reduced-motion. */
.progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  overflow: hidden;
  pointer-events: none;
}

.progress i {
  display: block;
  height: 100%;
  background: var(--ramp);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

.header-in {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 62px;
  padding: 8px var(--pad);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 650;
  font-size: 16px;
  color: var(--ink);
  text-decoration: none;
  margin-right: auto;
}

.brand img { width: 30px; height: 30px; border-radius: 9px; }

.nav {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.nav a {
  color: var(--muted);
  font-size: 14.5px;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 8px;
  transition: color 0.15s, background-color 0.15s;
}

.nav a:hover { color: var(--ink); background: #ffffff0f; }

.badge {
  flex: none;
  font: 500 12px/1 var(--mono);
  color: var(--muted);
  border: 1px solid var(--line-hi);
  border-radius: 999px;
  padding: 6px 11px;
  white-space: nowrap;
}

/* --- hero ----------------------------------------------------------------- */

/* padding-block, not a padding shorthand: these all sit on .wrap, whose
   horizontal padding is what keeps the text off the edge of a phone. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 356px;
  gap: clamp(28px, 5vw, 64px);
  align-items: start;
  padding-block: clamp(40px, 7vw, 84px) clamp(36px, 6vw, 72px);
}

/* The live status pill the popup itself shows: a green dot that breathes and
   the site-aware line. The pulse is a box-shadow ring on a 7px dot — the only
   recurring animation on the page, and it is a few hundred pixels. */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 18px;
  font: 500 12.5px/1 var(--mono);
  letter-spacing: 0.02em;
  color: var(--steel);
  border: 1px solid #34405a;
  background: #20283a;
  border-radius: 999px;
  padding: 8px 14px 8px 11px;
}

.pill-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 0 #79d8a266;
  animation: pill-breathe 2.4s ease-in-out infinite;
}

@keyframes pill-breathe {
  0%, 100% { box-shadow: 0 0 0 3px #79d8a23d; }
  50% { box-shadow: 0 0 0 7px #79d8a21a; }
}

h1 { font-size: clamp(2.5rem, 6.4vw, 4rem); font-weight: 700; }

h1 span {
  display: block;
  background: var(--ramp);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lede {
  margin: 22px 0 0;
  font-size: clamp(1.05rem, 2.1vw, 1.2rem);
  color: var(--muted);
  max-width: 34em;
}

.lede strong { color: var(--ink); font-weight: 600; }

.cta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 30px 0 0;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 17px;
  border: 1px solid var(--line-hi);
  border-radius: 11px;
  background: var(--card);
  color: var(--ink);
  font-size: 15px;
  font-weight: 550;
  text-decoration: none;
  transition: transform 0.15s, border-color 0.15s, background-color 0.15s;
}

.btn:hover {
  color: var(--ink);
  background: var(--card-hi);
  border-color: var(--lav);
  transform: translateY(-2px);
}

/* Browser icons: brand SVGs, so they keep their own colours at any state.
   Fixed box + flex:none keeps the labels from shifting on load. */
.btn img { width: 18px; height: 18px; flex: none; }

.btn-primary { background: #26304a; border-color: #4a5a86; }
.btn-primary:hover { background: #2c3855; }

/* Hero stats: the honest numbers, counted up once on first view. Tabular
   figures keep the digits from jittering as they tick. */
.stats {
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, auto));
  gap: 10px 26px;
}

.stats li { display: flex; align-items: baseline; gap: 9px; }

.stats b {
  font: 700 1.55rem/1 var(--font);
  font-variant-numeric: tabular-nums;
  background: var(--ramp);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stats span {
  font: 500 12px/1.45 var(--mono);
  color: var(--dim);
  max-width: 9em;
}

/* The popup image is the real popup at 356 css px, so it is shown at exactly
   that width and never upscaled. <picture> is inline by default, which would let
   the grid item collapse around it -- block keeps it sizing like a plain img. */
.hero-shot { position: relative; }

/* Static glow behind the shot: one radial, painted once. It sits under the
   image, so the float animation (transform-only, on the image) never
   repaints it. */
.hero-shot::before {
  content: "";
  position: absolute;
  inset: -12% -18%;
  background:
    radial-gradient(46% 38% at 60% 30%, #3d4a7a66, transparent 70%),
    radial-gradient(40% 34% at 40% 78%, #5a4f9659, transparent 72%);
  z-index: -1;
}

.hero-shot picture { display: block; }

.hero-shot img {
  width: 100%;
  max-width: 356px;
  border-radius: var(--radius);
  box-shadow: 0 18px 44px #0009;
  /* Transform-only drift on a single composited layer. Slow enough to read
     as ambient, and off entirely under prefers-reduced-motion. */
  animation: hero-drift 7s ease-in-out infinite;
}

@keyframes hero-drift {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-9px); }
}

.hero-shot figcaption {
  margin: 14px 0 0;
  font: 500 12px/1.5 var(--mono);
  color: var(--dim);
  max-width: 356px;
}

/* --- sections ------------------------------------------------------------- */

/* scroll-margin because the header is sticky: without it a jump from the nav
   lands with the section heading hidden underneath. 95px is the wrapped two-row
   header on a phone; on desktop it is one 63px row and the rest is slack. */
.section {
  padding-block: clamp(44px, 7vw, 78px);
  border-top: 1px solid var(--line);
  scroll-margin-top: 95px;
}

/* The icon's ramp as the divider: a static 1px gradient line sitting exactly
   on the existing border, over the first 40% of the rail. */
.section::before {
  content: "";
  display: block;
  width: 38%;
  max-width: 380px;
  height: 1px;
  margin: 0 0 -1px;
  background: var(--ramp);
  opacity: 0.55;
}

.sec-head { max-width: 46em; margin-bottom: clamp(26px, 4vw, 40px); }

.kicker {
  margin: 0 0 14px;
  font: 500 12px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

h2 { font-size: clamp(1.7rem, 3.6vw, 2.4rem); font-weight: 650; }

h2 em {
  font-style: normal;
  background: var(--ramp);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.sec-lede { margin: 16px 0 0; color: var(--muted); }

h3 { font-size: 1.16rem; font-weight: 620; }

/* --- cards ---------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  transition: transform 0.16s, border-color 0.16s, background-color 0.16s;
}

.card:hover {
  transform: translateY(-3px);
  border-color: var(--line-hi);
  background: var(--card-hi);
}

/* The icon square picks up the accent on hover: border-color and a shadow,
   both cheap state changes, no repaint of the card itself. */
.card:hover .card-icon {
  border-color: var(--lav);
  box-shadow: 0 0 0 4px #a7a0e81a;
}

.card:hover .card-icon svg { stroke: var(--lav); }

.card p { margin: 10px 0 0; color: var(--muted); font-size: 15.5px; }

.card-icon {
  width: 38px;
  height: 38px;
  margin-bottom: 16px;
  border-radius: 11px;
  background: #ffffff0a;
  border: 1px solid var(--line-hi);
  display: grid;
  place-items: center;
}

.card-icon svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--steel);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 16px;
}

.tag {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 9px;
}

.num {
  font: 600 12px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--lav);
  margin: 0 0 12px;
}

/* --- interactive demo -------------------------------------------------------
   Pure CSS: the checkbox is display:none, and sibling selectors drive every
   state. No script, no repaints while idle; the only motion is the three
   typing dots, and only while the extension is "off" in the demo. */

#demoSwitch, #storySwitch { position: absolute; opacity: 0; pointer-events: none; }

/* Two demos side by side; a single stacked column once the grid gets narrow.
   Each .demo is a column: header, body, caption. The body grows to fill the
   shared row height, so the chat side centers its content when the story
   side is taller, instead of leaving a stubby card. */
.demo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 16px;
  align-items: stretch;
}

.demo {
  position: relative;
  display: flex;
  flex-direction: column;
  max-width: 560px;
  width: 100%;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  padding: 18px 20px 20px;
}

.demo-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}

.demo-name { font-weight: 620; font-size: 15px; }

.demo-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}

.demo-toggle .track {
  display: block;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  border: 1px solid var(--lav);
  background: #1d2449;
  position: relative;
  transition: background-color 0.2s, border-color 0.2s;
}

.demo-toggle .knob {
  position: absolute;
  top: 2px;
  left: 23px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  transition: left 0.2s;
}

:is(#demoSwitch, #storySwitch):not(:checked) ~ .demo-top .demo-toggle .track {
  background: #4b566b;
  border-color: var(--line-hi);
}

:is(#demoSwitch, #storySwitch):not(:checked) ~ .demo-top .demo-toggle .knob { left: 3px; }

.demo-state { font: 600 12px/1 var(--mono); letter-spacing: 0.06em; }

:is(#demoSwitch, #storySwitch):checked ~ .demo-top .demo-on { color: var(--good); }
:is(#demoSwitch, #storySwitch):not(:checked) ~ .demo-top .demo-off { color: var(--dim); }

.demo-top .demo-state { color: var(--dim); }
:is(#demoSwitch, #storySwitch):checked ~ .demo-top .demo-off,
:is(#demoSwitch, #storySwitch):not(:checked) ~ .demo-top .demo-on { display: none; }

/* The chat body grows to the row height and distributes its content:
   their messages start at the top, your typing block sits at the bottom,
   so the conversation fills the card evenly instead of clustering short. */
.demo-chat {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 16px;
  flex: 1 1 auto;
  min-height: 0;
}

.demo-side { display: flex; flex-direction: column; }

.demo-side.them { align-items: flex-start; }

.demo-side.me {
  align-items: flex-end;
  margin-top: auto;
}

.bubble {
  background: #2a3140;
  border: 1px solid var(--line);
  border-radius: 13px 13px 13px 4px;
  padding: 9px 13px;
  font-size: 15px;
  max-width: 72%;
  margin-bottom: 6px;
}

/* Receipts: "Seen" only when the demo switch is off. */
.receipt { font-size: 12.5px; color: var(--dim); padding-left: 4px; }

#demoSwitch:checked ~ .demo-chat .receipt-seen,
#demoSwitch:not(:checked) ~ .demo-chat .receipt-delivered { display: none; }

#demoSwitch:not(:checked) ~ .demo-chat .receipt-seen { color: var(--steel); }
#demoSwitch:checked ~ .demo-chat .receipt-delivered { color: var(--good); }

/* Typing dots: visible only when off (what the other person sees). */
.typing {
  display: none;
  gap: 4px;
  background: #2a3140;
  border: 1px solid var(--line);
  border-radius: 13px 13px 4px 13px;
  padding: 10px 12px;
}

#demoSwitch:not(:checked) ~ .demo-chat .typing { display: flex; }

.typing i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted);
  animation: dot-bounce 1.2s ease-in-out infinite;
}

.typing i:nth-child(2) { animation-delay: 0.15s; }
.typing i:nth-child(3) { animation-delay: 0.3s; }

/* Transform on 7px dots: three composited dots, nothing more. */
@keyframes dot-bounce {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50% { transform: translateY(-4px); opacity: 1; }
}

.typing-hint { font: 500 12px/1 var(--mono); color: var(--dim); margin-top: 6px; }

#demoSwitch:checked ~ .demo-chat .hint-typing,
#demoSwitch:not(:checked) ~ .demo-chat .hint-hidden { display: none; }

#demoSwitch:not(:checked) ~ .demo-chat .hint-typing { color: var(--steel); }
#demoSwitch:checked ~ .demo-chat .hint-hidden { color: var(--good); }

.demo-caption {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 14.5px;
}

.demo-caption b { color: var(--ink); font-weight: 600; }

/* --- story-view demo --------------------------------------------------------
   Same pure-CSS pattern as the chat demo, one checkbox driving Mia's viewer
   list. The only recurring animation is the first story segment filling --
   a scaleX on a 3px bar. */

.demo-story {
  padding-top: 14px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.story-segs { display: flex; gap: 5px; padding: 0 2px 10px; }

.story-canvas {
  height: 140px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background:
    radial-gradient(70% 90% at 72% 108%, #d98a5f8c 0%, transparent 62%),
    linear-gradient(205deg, #2d3860 0%, #453a72 55%, #233050 100%);
}

.story-segs .seg {
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: #39415a;
  overflow: hidden;
  position: relative;
}

.story-segs .seg.on::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ramp);
  transform-origin: 0 50%;
  animation: seg-fill 6s linear infinite;
}

@keyframes seg-fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.story-head { display: flex; align-items: center; gap: 10px; padding: 0 2px 10px; }

/* Story ring: the brand ramp as a conic, hole punched by the inner disc. */
.story-ring {
  padding: 2px;
  border-radius: 50%;
  flex: none;
  background: conic-gradient(from 210deg, var(--steel), var(--lav), var(--indigo), var(--steel));
}

.story-ring i {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--card-hi);
  font: 700 13px/1 var(--font);
  font-style: normal;
  color: var(--ink);
}

.story-who b { display: block; font-size: 13.5px; font-weight: 620; }
.story-who span { font-size: 11.5px; color: var(--dim); }

.story-canvas span {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #ffffffb3;
  background: #00000040;
  padding: 6px 10px;
  border-radius: 999px;
}

.story-viewers {
  margin-top: 12px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.viewers-title {
  margin: 0 0 4px;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}

.viewers-title b { margin-left: 5px; color: var(--muted); font-weight: 600; }

#storySwitch:checked ~ .demo-story .count-off { display: none; }
#storySwitch:not(:checked) ~ .demo-story .count-on { display: none; }

.story-viewers ul {
  margin: 0;
  padding: 0;
  list-style: none;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.viewer-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; }

.viewer-row + .viewer-row { border-top: 1px solid #ffffff0a; }

.vav {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 700 11px/1 var(--font);
  color: #131722;
  flex: none;
}

.vav.a { background: var(--steel); }
.vav.b { background: var(--lav); }
.vav.you { background: var(--good); }

.viewer-row div { display: flex; flex-direction: column; gap: 1px; }
.viewer-row b { font-size: 14px; font-weight: 620; color: var(--ink); }
.viewer-row .sub { font-size: 12px; color: var(--dim); }

/* The you-row: a reported viewer when off, a ghost that never arrived when
   on. The dashed frame is the "this slot exists but you are not in it" cue. */
.you { border-radius: 10px; transition: border-color 0.2s, background-color 0.2s; }

#storySwitch:not(:checked) ~ .demo-story .you .you-unlisted { display: none; }
#storySwitch:checked ~ .demo-story .you .you-seen { display: none; }
#storySwitch:not(:checked) ~ .demo-story .you .you-seen { color: var(--steel); }

#storySwitch:checked ~ .demo-story .you {
  border: 1px dashed #79d8a266;
  background: #79d8a20d;
  padding: 8px 10px;
  margin-top: 4px;
}

#storySwitch:checked ~ .demo-story .you .you-unlisted { color: var(--good); font-weight: 600; }

/* --- changelog ------------------------------------------------------------- */

/* Version groups, site-styled: the group head sits in the site's mono voice
   and the list reads as the cards' sibling, not a <pre> blob. */
.cl-group {
  margin: 34px 0 12px;
  font: 600 12px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
}

.cl-group:first-of-type { margin-top: 0; }

.cl-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 720px;
}

.cl-list li {
  position: relative;
  padding: 12px 16px 12px 38px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: linear-gradient(160deg, var(--card), var(--bg-deep));
  font: 400 15.5px/1.5 var(--font);
  color: var(--muted);
}

.cl-list b { color: var(--ink); font-weight: 600; }

.cl-list li::before {
  content: "";
  position: absolute;
  left: 17px;
  top: 21px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--lav);
  box-shadow: 0 0 8px #a7a0e888;
}

/* The Fixed group's dots are green: these are repairs. */
.cl-group + .cl-list li::before {
  background: var(--good);
  box-shadow: 0 0 8px #79d8a288;
}

/* --- with / without ------------------------------------------------------- */

.compare { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }

.compare > div {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  background: var(--card);
}

.compare h3 { display: flex; align-items: baseline; gap: 10px; }

.compare .side {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}

.compare ul { margin: 16px 0 0; padding: 0; list-style: none; }

.compare li {
  display: flex;
  gap: 11px;
  padding: 9px 0;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 15.5px;
}

.compare li::before { content: "→"; color: var(--dim); flex: none; }

.compare .is-on { border-color: #4a5a86; background: #202839; }
.compare .is-on li::before { content: "✓"; color: var(--good); }

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

.shots { display: grid; gap: 16px; }

.shot-stage { display: grid; gap: clamp(20px, 3vw, 30px); }

/* The three shots become a slideshow only once script.js marks the block
   is-live. Without scripting the figures simply stack in the stage above,
   so nothing is lost. Stacked slides share one grid cell, so the stage is
   always as tall as the tallest slide and captions can differ in length. */
.shots.is-live .shot-stage { gap: 0; }

.shots.is-live .shot {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.35s ease, visibility 0.35s;
}

.shots.is-live .shot.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  z-index: 1;
}

.shot-frame {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-deep);
  overflow: hidden;
  transform: perspective(1400px) rotateX(0deg);
  transition: transform 0.25s ease, border-color 0.25s ease;
}

/* A small perspective lift on hover -- transform only, on one composited
   frame, and a flat fallback if a browser lacks transform-style support. */
.shot-frame:hover {
  transform: perspective(1400px) rotateX(1.6deg) translateY(-4px);
  border-color: var(--line-hi);
}

.shot-bar {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 13px;
  border-bottom: 1px solid var(--line);
  font: 500 11.5px/1 var(--mono);
  color: var(--dim);
}

.shot-bar i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-hi);
}

/* The store shots are 1280px wide, so on a phone the text inside them is far
   too small to read -- the image is a link to the full-size file, and the bar
   says so, since a title tooltip would never show up on a phone. */
.shot-open { margin-left: auto; color: var(--steel); }
.shot-frame a { display: block; }
.shot-frame a:hover { background: #ffffff08; }

.shot figcaption { margin: 12px 0 0; color: var(--muted); font-size: 15px; }
.shot figcaption b { color: var(--ink); font-weight: 600; }

/* Slideshow controls, hidden until the block is live. Round arrow buttons
   and pill dots, sized for a touch target even on a phone. */
.shot-nav { display: none; }

.shots.is-live .shot-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

.shot-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--line-hi);
  border-radius: 50%;
  background: var(--card);
  color: var(--muted);
  cursor: pointer;
  transition: transform 0.15s, border-color 0.15s, color 0.15s, background-color 0.15s;
}

.shot-btn:hover {
  color: var(--ink);
  border-color: var(--lav);
  background: var(--card-hi);
  transform: translateY(-2px);
}

.shot-btn svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.shot-dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line-hi);
  cursor: pointer;
  transition: background-color 0.16s, transform 0.16s;
}

.shot-dot:hover { background: var(--dim); }

.shot-dot[aria-current="true"] {
  background: var(--steel);
  transform: scale(1.3);
}

/* --- lists, table, note -------------------------------------------------- */

.checks { margin: 0; padding: 0; list-style: none; }

.checks li {
  position: relative;
  padding: 11px 0 11px 30px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 16px;
}

.checks li:first-child { border-top: 0; }
.checks li b { color: var(--ink); font-weight: 600; }

.checks li::before {
  content: "✓";
  position: absolute;
  left: 2px;
  top: 11px;
  color: var(--good);
  font-size: 14px;
}

.checks.is-limits li::before { content: "—"; color: var(--dim); }

.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: clamp(20px, 4vw, 40px); align-items: start; }

.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }

table { width: 100%; border-collapse: collapse; font-size: 15px; }

caption {
  text-align: left;
  padding: 14px 16px;
  font: 500 11.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
  border-bottom: 1px solid var(--line);
}

th, td { text-align: left; padding: 12px 16px; border-top: 1px solid var(--line); vertical-align: top; }
th { color: var(--ink); font-weight: 600; font-size: 14px; }
td { color: var(--muted); }
thead th { border-top: 0; }

.note {
  margin: 18px 0 0;
  padding: 20px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--lav);
  border-radius: var(--radius);
  background: var(--card);
}

.note strong { display: block; margin-bottom: 8px; }
.note p { margin: 0; color: var(--muted); font-size: 15.5px; }

.steps { margin: clamp(24px, 4vw, 34px) 0 0; padding: 0 0 0 26px; color: var(--muted); }
.steps li { margin: 0 0 12px; padding-left: 6px; }
.steps li::marker { color: var(--lav); font-variant-numeric: tabular-nums; }
.steps b { color: var(--ink); font-weight: 600; }

.fineprint { margin: 26px 0 0; color: var(--dim); font-size: 14.5px; max-width: 60em; }
.fineprint b { color: var(--muted); font-weight: 600; }

/* --- footer -------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--bg-deep);
  padding: 34px 0;
  color: var(--dim);
  font-size: 14.5px;
}

.footer-in { display: flex; flex-wrap: wrap; gap: 10px 26px; justify-content: space-between; }

/* --- prose (privacy page) ------------------------------------------------ */

.prose { max-width: 42em; padding-block: clamp(34px, 6vw, 64px); }
.prose h1 { font-size: clamp(2.1rem, 5vw, 3rem); }
.prose h2 { font-size: 1.4rem; margin: 44px 0 0; }
.prose p, .prose li { color: var(--muted); }
.prose p { margin: 16px 0 0; }
.prose ul { margin: 16px 0 0; padding-left: 22px; }
.prose li { margin-bottom: 10px; }
.prose .updated { font: 500 12.5px/1.6 var(--mono); color: var(--dim); }
.prose .table-wrap { margin-top: 20px; }

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

/* Set by script.js on the elements it is about to observe, so a no-JS or
   failed-script page renders everything visible rather than blank. */
.js .reveal { opacity: 0; transform: translateY(14px); }

.js .reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* --- narrow -------------------------------------------------------------- */

@media (max-width: 900px) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  /* A plain max-width, not justify-self: start -- fit-content sizing around an
     image with a percentage width collapses the figure to about 225px. */
  .hero-shot { max-width: 356px; }
}

@media (max-width: 720px) {
  body { font-size: 16px; }
  .header-in { flex-wrap: wrap; min-height: 0; gap: 10px 14px; }
  .brand { margin-right: auto; }
  .badge { order: 2; }
  /* One row that swipes sideways rather than two rows pushing the hero down.
     The bar itself is hidden; the fade of the last item is the affordance. */
  .nav {
    order: 3;
    width: 100%;
    margin: 0 calc(var(--pad) * -1) 2px;
    padding: 0 var(--pad);
    overflow-x: auto;
    flex-wrap: nowrap;
    scrollbar-width: none;
  }
  .nav::-webkit-scrollbar { display: none; }
  .nav a { white-space: nowrap; }
  .cta .btn { flex: 1 1 100%; justify-content: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 0.01ms !important; }
  .js .reveal { opacity: 1; transform: none; }
  /* Every recurring animation added for engagement is ambient, never
     informational: breathing dot, hero drift, demo dots, story segment. All
     off here. */
  .pill-dot, .hero-shot img, .typing i, .story-segs .seg.on::after { animation: none; }
  .progress { display: none; }
}
