/* Lounge — loungeapp.io
   House kit lifted from the app's Blue Note palette (ui/Theme.kt), so site and app read as one. */

:root {
  /* The page is already dark. Declaring it stops browsers with force-dark enabled
     (Brave and Chrome both offer it) from running their own darkening pass over a
     design that does not need one, which muddies text that was fine to begin with. */
  color-scheme: dark;

  --ground:       #0A0D13;
  --plate:        #131924;
  --hairline:     rgba(227, 232, 239, 0.07);
  --text:         #E3E8EF;
  --text-strong:  #F2F5F9;
  --muted:        #C3CBD6;
  --secondary:    #8591A2;
  --tertiary:     #5D6878;
  --teal:         #6CC4C1;
  --on-accent:    #06201F;
  --orchid:       #C98BDB;
  --neon:         #FF4FA3;

  --display: Syne, "Trebuchet MS", system-ui, sans-serif;
  --body: "IBM Plex Sans", "Segoe UI", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter: 20px;
  --phone-scale: 0.62;            /* 448 * 0.62 = 278, inside a 320px screen less gutters */
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 { margin: 0; font-family: var(--display); text-wrap: balance; letter-spacing: -0.02em; }
p { margin: 0; text-wrap: pretty; }
a { color: var(--teal); text-decoration: none; }
a:hover { color: #93E4E0; }
em { font-style: normal; color: var(--secondary); }
strong { color: var(--text-strong); font-weight: 600; }

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

.eyebrow {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--tertiary);
}
.eyebrow.teal { color: var(--teal); }
.eyebrow.neon { color: var(--neon); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 26px; border-radius: 12px; background: var(--teal); color: var(--on-accent);
  font-size: 16px; font-weight: 600; min-height: 48px;
}
.btn:hover { background: #7ed3d0; color: var(--on-accent); }
.btn-quiet {
  font-size: 15px; color: var(--muted);
  border-bottom: 1px solid rgba(227,232,239,0.22); padding-bottom: 2px;
}
.btn-quiet:hover { color: var(--text-strong); }
.placeholder { font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; color: var(--tertiary); }

/* ---------- nav ---------- */
.nav { border-bottom: 1px solid var(--hairline); position: relative; z-index: 3; }
.nav .wrap { display: flex; align-items: center; justify-content: space-between; padding-top: 18px; padding-bottom: 18px; }
.brand { display: flex; align-items: center; gap: 11px; }
.brand span { font-family: var(--display); font-size: 21px; font-weight: 700; color: var(--text-strong); }
/* Below 900 the section anchors are hidden: the page is a single scroll and the
   footer repeats every one of them. The call to action is not optional, so it
   stays at every width rather than the whole nav disappearing on a phone. */
.nav-links { display: flex; align-items: center; gap: 30px; }
.nav-links a:not(.btn) { display: none; font-size: 15px; color: var(--muted); }
.nav-links a:not(.btn):hover { color: var(--text-strong); }
.nav .btn { padding: 10px 20px; font-size: 15px; min-height: 0; }

/* ---------- hero ---------- */
.hero { position: relative; padding: 56px 0 64px; overflow: hidden; }
.hero::before, .hero::after { content: ""; position: absolute; pointer-events: none; }
.hero::before {
  top: -200px; left: -160px; width: 760px; height: 640px;
  background: radial-gradient(closest-side, rgba(108,196,193,0.16), rgba(108,196,193,0));
}
.hero::after {
  top: 120px; right: -260px; width: 700px; height: 700px;
  background: radial-gradient(closest-side, rgba(255,79,163,0.14), rgba(255,79,163,0));
}
.hero .wrap { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 48px; align-items: center; }
.hero-copy { display: flex; flex-direction: column; gap: 22px; align-items: flex-start; }
.hero h1 { font-size: clamp(38px, 7.4vw, 58px); line-height: 1.04; font-weight: 800; letter-spacing: -0.03em; color: var(--text-strong); }
/* Two statements, so it breaks where the sentence does rather than wherever the
   column happens to run out. Matches the social card, which sets it the same way. */
.hero h1 span { display: block; }
.hero-sub { font-size: clamp(16px, 2.4vw, 19px); line-height: 1.6; color: var(--muted); max-width: 30em; }
.cta-row { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding-top: 4px; }
.stats { display: flex; flex-wrap: wrap; gap: clamp(18px, 5vw, 40px) clamp(20px, 5vw, 40px); width: 100%; max-width: 520px; padding-top: 24px; margin-top: 16px; border-top: 1px solid var(--hairline); }
.stat { display: flex; flex-direction: column; gap: 4px; }
.stat b { font-family: var(--mono); font-size: clamp(18px, 4vw, 26px); font-weight: 500; color: var(--text-strong); white-space: nowrap; }
.stat span { font-size: 13px; color: var(--tertiary); }

/* ---------- section scaffolding ---------- */
.section { padding: 0 0 72px; }
.section-head { display: flex; flex-direction: column; gap: 14px; max-width: 700px; margin-bottom: 40px; }
.section-head h2 { font-size: clamp(28px, 5.2vw, 44px); line-height: 1.12; font-weight: 700; color: var(--text-strong); }
.section-head p { font-size: clamp(16px, 2.2vw, 18px); color: var(--muted); }

.grid-3 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; }
.grid-2 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; }
.features { display: grid; grid-template-columns: minmax(0, 1fr); gap: 36px 40px; }

.card { display: flex; flex-direction: column; gap: 16px; padding: 30px; background: var(--plate); border: 1px solid var(--hairline); border-radius: 16px; }
.card h3 { font-size: 22px; font-weight: 700; color: var(--text-strong); }
.card p { font-size: 15.5px; line-height: 1.65; color: var(--muted); }

.feature { display: flex; flex-direction: column; gap: 12px; }
.feature h3 { font-size: 20px; font-weight: 700; color: var(--text-strong); }
.feature p { font-size: 15px; line-height: 1.65; color: var(--muted); }

/* the wide iPhone plate */
.plate-wide { display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; padding: 30px; background: var(--plate); border: 1px solid var(--hairline); border-radius: 16px; }
.plate-wide h3 { font-size: 20px; font-weight: 700; color: var(--text-strong); }
.plate-wide .lede { font-size: 15px; line-height: 1.65; color: var(--secondary); }
.plate-wide p { font-size: 15px; line-height: 1.65; color: var(--muted); }
.sub { display: flex; flex-direction: column; gap: 9px; }

/* honest RCS block */
.honest { display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; padding: 34px 30px; background: var(--plate); border: 1px solid var(--hairline); border-radius: 16px; align-items: start; }
.honest h3 { font-size: clamp(22px, 3.6vw, 30px); line-height: 1.2; font-weight: 700; color: var(--text-strong); }
.honest p { font-size: 16px; line-height: 1.7; color: var(--muted); }
.honest .stack { display: flex; flex-direction: column; gap: 16px; }

/* ---------- pricing ---------- */
.tier { display: flex; flex-direction: column; gap: 24px; padding: 32px; background: var(--plate); border: 1px solid var(--hairline); border-radius: 16px; }
.tier.plus { background: linear-gradient(160deg, rgba(108,196,193,0.09), var(--plate) 55%); border-color: rgba(108,196,193,0.30); }
.tier h3 { font-size: 24px; font-weight: 700; color: var(--text-strong); }
.tier .price { font-family: var(--mono); font-size: 32px; font-weight: 500; color: var(--text-strong); }
.tier .note { font-size: 15px; color: var(--secondary); }
.tier ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.tier li { display: flex; gap: 11px; align-items: flex-start; font-size: 15.5px; color: var(--muted); }
.tier li svg { margin-top: 3px; flex-shrink: 0; }
.pill { font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--on-accent); background: var(--teal); padding: 4px 9px; border-radius: 5px; }

/* ---------- closer + footer ---------- */
.closer { position: relative; padding: 72px 0; border-top: 1px solid var(--hairline); overflow: hidden; }
.closer::after {
  content: ""; position: absolute; bottom: -340px; left: 50%; transform: translateX(-50%);
  width: 1100px; height: 620px; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255,79,163,0.14), rgba(255,79,163,0));
}
.closer .wrap { position: relative; display: flex; flex-direction: column; align-items: center; gap: 24px; text-align: center; }
.closer h2 { font-size: clamp(30px, 6.4vw, 52px); line-height: 1.1; font-weight: 800; letter-spacing: -0.025em; color: var(--text-strong); max-width: 760px; }
.closer p { font-size: clamp(16px, 2.4vw, 18px); color: var(--muted); max-width: 540px; }

.footer { padding: 44px 0 40px; border-top: 1px solid var(--hairline); }
.footer-top { display: flex; flex-direction: column; gap: 32px; justify-content: space-between; }
.footer-brand { display: flex; align-items: center; gap: 11px; }
.footer-brand span { font-family: var(--display); font-size: 18px; font-weight: 700; letter-spacing: 0.06em; color: var(--muted); }
.footer-brand span i { font-style: normal; color: var(--secondary); font-weight: 600; }
.footer p { font-size: 14px; line-height: 1.6; color: var(--tertiary); max-width: 360px; }
.footer-cols { display: flex; flex-wrap: wrap; gap: 40px; }
.footer-col { display: flex; flex-direction: column; gap: 10px; }
.footer-col a { font-size: 14.5px; color: var(--muted); padding: 4px 0; margin: -4px 0; }
.footer-col .eyebrow { font-size: 10px; letter-spacing: 0.16em; }
.footer-bottom { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; margin-top: 36px; padding-top: 22px; border-top: 1px solid var(--hairline); }
.footer-bottom span { font-family: var(--mono); font-size: 12px; color: var(--tertiary); }

/* ---------- the phone mockup ---------- */
.phone-stage { display: flex; justify-content: center; position: relative; }
.phone-box { position: relative; width: calc(448px * var(--phone-scale)); height: calc(756px * var(--phone-scale)); }
.lg-phone {
  position: absolute; top: 0; left: 0; width: 420px;
  border-radius: 44px; border: 1px solid rgba(227,232,239,0.12); background: var(--ground);
  padding: 13px; box-shadow: 0 40px 90px rgba(0,0,0,0.6);
  transform-origin: top left;
  animation: lgFloat 7.5s ease-in-out infinite;
}
@keyframes lgFloat {
  0%, 100% { transform: scale(var(--phone-scale)) translateY(0); }
  50%      { transform: scale(var(--phone-scale)) translateY(-9px); }
}
.lg-curtain { animation: lgCurtain 7.5s cubic-bezier(0.4, 0, 0.3, 1) infinite; }
@keyframes lgCurtain {
  0%        { transform: translateY(115%); opacity: 0; }
  10%       { opacity: 1; }
  52%       { opacity: 1; }
  66%, 100% { transform: translateY(-115%); opacity: 0; }
}
.lg-pulse { animation: lgPulse 2.4s ease-in-out infinite; }
@keyframes lgPulse {
  0%, 100% { opacity: 1;    box-shadow: 0 0 0 3px rgba(255,79,163,0.28); }
  50%      { opacity: 0.55; box-shadow: 0 0 0 6px rgba(255,79,163,0.10); }
}
.lg-glow { animation: lgGlow 3.6s ease-in-out infinite; }
@keyframes lgGlow {
  0%, 100% { box-shadow: 0 6px 18px rgba(108,196,193,0.16); }
  50%      { box-shadow: 0 10px 30px rgba(108,196,193,0.34); }
}
.lg-wash { animation: lgWash 7.5s ease-in-out infinite; }
@keyframes lgWash { 0%, 100% { opacity: 0.85; } 50% { opacity: 1; } }

/* ---------- breakpoints ---------- */
@media (min-width: 390px) {
  :root { --phone-scale: 0.78; }  /* 349 wide; the step below covers 320px screens */
}
@media (min-width: 440px) {
  :root { --phone-scale: 0.92; }
}
@media (min-width: 600px) {
  :root { --gutter: 32px; --phone-scale: 1.1; }
  .plate-wide, .honest { padding: 34px 36px; }
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-top { flex-direction: row; align-items: flex-start; }
}
@media (min-width: 900px) {
  :root { --gutter: 48px; --phone-scale: 1.15; }
  .nav-links a:not(.btn) { display: inline; }
  .section { padding-bottom: 96px; }
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .features { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 44px 40px; }
  .plate-wide { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr) minmax(0, 1fr); gap: 40px; }
  .honest { grid-template-columns: 1fr 1.3fr; gap: 48px; padding: 44px 48px; }
  .section-head { margin-bottom: 48px; }
}
/* The hero goes two-column here, so the phone column has to leave the headline
   room to breathe. A 640px phone against a 96px gutter crushed the text column to
   ~356px at 1160-1280 - the most common laptop widths - and stacked the headline
   six words tall. The big phone and the wide gutter wait for 1440. */
@media (min-width: 1160px) {
  :root { --gutter: 56px; }
  .hero { padding: 74px 0 74px; }
  .hero .wrap { grid-template-columns: minmax(0, 1fr) 530px; gap: 48px; }
  .card { padding: 34px; }
  .tier { padding: 40px; }
}
@media (min-width: 1440px) {
  :root { --gutter: 96px; --phone-scale: 1.42; }
  .hero .wrap { grid-template-columns: minmax(0, 1fr) 640px; gap: 48px; }
}
@media (min-width: 1500px) {
  :root { --phone-scale: 1.5; }
  .hero { padding: 88px 0 84px; }
  .hero .wrap { grid-template-columns: minmax(0, 1fr) 690px; gap: 64px; }
  .section { padding-bottom: 112px; }
  .features { gap: 52px 48px; }
}
/* The headline only grows once the container has hit its max and the left
   column is genuinely wide; bumping it at 1500 strands "app" on its own line. */
@media (min-width: 1700px) {
  .hero h1 { font-size: 66px; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .lg-phone, .lg-curtain, .lg-pulse, .lg-glow, .lg-wash { animation: none !important; }
  .lg-phone { transform: scale(var(--phone-scale)); }
  .lg-curtain { opacity: 0; }
}

/* ---------- privacy / legal pages ---------- */
.page-head { padding: 48px 0 32px; border-bottom: 1px solid var(--hairline); }
.page-head .inner { display: flex; flex-direction: column; gap: 16px; max-width: 780px; }
.page-head h1 { font-size: clamp(34px, 7vw, 58px); line-height: 1.06; font-weight: 800; letter-spacing: -0.03em; color: var(--text-strong); }
.page-head p { font-size: clamp(16px, 2.4vw, 19px); line-height: 1.6; color: var(--muted); }
.stamp { display: flex; flex-wrap: wrap; gap: 24px; }
.stamp span { font-family: var(--mono); font-size: 13px; color: var(--tertiary); }

.doc { display: grid; grid-template-columns: minmax(0, 1fr); gap: 40px; padding: 48px 0 80px; align-items: start; }
.toc { display: flex; flex-direction: column; gap: 12px; }
.toc a { font-size: 14.5px; color: var(--secondary); border-left: 2px solid var(--hairline); padding: 4px 0 4px 14px; margin: -4px 0; }
.toc a.on, .toc a:hover { color: var(--text-strong); border-left-color: var(--teal); }
.doc-body { display: flex; flex-direction: column; gap: 40px; max-width: 720px; }
.doc-body section { display: flex; flex-direction: column; gap: 16px; }
.doc-body h2 { font-size: clamp(22px, 3.4vw, 26px); font-weight: 700; color: var(--text-strong); }
.doc-body p { font-size: 16.5px; line-height: 1.75; color: var(--muted); }
.callout { padding: 28px 26px; background: var(--plate); border: 1px solid rgba(108,196,193,0.22); border-radius: 14px; }
.perms { display: flex; flex-direction: column; border: 1px solid var(--hairline); border-radius: 12px; overflow: hidden; margin-top: 4px; }
.perms .row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; padding: 14px 18px; border-bottom: 1px solid var(--hairline); }
.perms .row:last-child { border-bottom: 0; }
.perms .row.head { background: var(--plate); }
.perms .row.head span { font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tertiary); }
/* One permission name is 55 characters and the first column is a fixed 200px,
   so the token has to be allowed to break or it overflows the cell. */
.perms code { font-family: var(--mono); font-size: 13.5px; color: var(--teal); overflow-wrap: anywhere; }
.perms p { font-size: 15px; color: var(--muted); line-height: 1.6; }
@media (min-width: 900px) {
  .doc { grid-template-columns: 240px minmax(0, 1fr); gap: 72px; }
  .perms .row { grid-template-columns: 200px minmax(0, 1fr); gap: 24px; align-items: baseline; }
  .page-head { padding: 64px 0 36px; }
}

/* ---------- comparison table ---------- */
.compare { overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--hairline); border-radius: 16px; background: var(--plate); }
.cmp { border-collapse: collapse; width: 100%; min-width: 760px; }
.cmp th, .cmp td { text-align: left; padding: 16px 20px; border-bottom: 1px solid var(--hairline); vertical-align: top; font-size: 15px; line-height: 1.5; }
.cmp thead th { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tertiary); padding-top: 20px; padding-bottom: 14px; }
.cmp tbody th { font-weight: 500; color: var(--text-strong); width: 30%; }
.cmp td { color: var(--muted); }
.cmp tr:last-child th, .cmp tr:last-child td { border-bottom: 0; }
.cmp .us { background: rgba(108,196,193,0.07); color: var(--text-strong); font-weight: 500; }
.cmp thead .us { color: var(--teal); background: rgba(108,196,193,0.10); }
.cmp .us-first { border-top-left-radius: 16px; }
.cmp .fair { color: var(--secondary); }
.cmp .fair.us { color: var(--muted); font-weight: 400; }
.source { display: block; margin-top: 16px; font-family: var(--mono); font-size: 11.5px; line-height: 1.7; color: var(--tertiary); }
.scroll-hint { display: block; margin-top: 10px; font-size: 13px; color: var(--tertiary); }
@media (min-width: 900px) { .scroll-hint { display: none; } }

/* ---------- beta request form ---------- */
.request { display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; padding: 34px 30px; background: var(--plate); border: 1px solid rgba(108,196,193,0.22); border-radius: 16px; align-items: start; }
.request h3 { font-size: clamp(22px, 3.6vw, 30px); line-height: 1.2; font-weight: 700; color: var(--text-strong); }
.request .note { font-size: 15px; line-height: 1.6; color: var(--secondary); }
.form { display: flex; flex-direction: column; gap: 16px; }
.field { display: flex; flex-direction: column; gap: 7px; }
.field label { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tertiary); }
.field input {
  font-family: var(--body); font-size: 16px; color: var(--text-strong);
  background: var(--ground); border: 1px solid var(--hairline); border-radius: 10px;
  padding: 13px 15px; min-height: 48px; width: 100%;
}
.field input::placeholder { color: var(--tertiary); }
.field input:focus { border-color: var(--teal); }
.field input:focus:not(:focus-visible) { outline: none; }
.field input:user-invalid { border-color: #E38B8B; }
.field .hint { font-size: 13px; color: var(--tertiary); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form .btn { align-self: flex-start; }
.form .btn[disabled] { opacity: 0.55; }
.status { font-size: 15px; line-height: 1.6; min-height: 24px; }
.status.ok { color: var(--teal); }
.status.bad { color: #E38B8B; }
@media (min-width: 900px) { .request { grid-template-columns: 1fr 1.1fr; gap: 56px; padding: 44px 48px; } }

/* ---------- theme gallery ---------- */
.themes-rail { display: flex; gap: 18px; overflow-x: auto; -webkit-overflow-scrolling: touch; padding: 4px 0 14px; scroll-snap-type: x proximity; }
.themes-rail::-webkit-scrollbar { height: 6px; }
.themes-rail::-webkit-scrollbar-thumb { background: rgba(227,232,239,0.14); border-radius: 3px; }
.theme-card { flex: 0 0 248px; display: flex; flex-direction: column; gap: 12px; scroll-snap-align: start; }
.theme-shot { border-radius: 16px; overflow: hidden; border: 1px solid var(--hairline); }
.theme-head { padding: 14px 14px 12px; }
.theme-title { font-family: var(--display); font-size: 21px; font-weight: 700; letter-spacing: 0.3px; -webkit-background-clip: text; background-clip: text; color: transparent; }
.theme-chip { display: inline-block; margin-top: 8px; padding: 3px 8px; border-radius: 8px; font-family: var(--mono); font-size: 9.5px; }
.theme-row { display: flex; flex-direction: column; gap: 3px; margin: 0 8px 8px; padding: 10px 12px; border-radius: 12px; }
.theme-row b { font-size: 12.5px; font-weight: 600; }
.theme-row span { font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.theme-meta { display: flex; flex-direction: column; gap: 3px; padding-left: 2px; }
.theme-meta b { font-size: 15px; font-weight: 600; color: var(--text-strong); }
.theme-meta span { font-size: 13px; color: var(--secondary); }
.theme-mode { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tertiary); }

/* ---------- focus and skip link ---------- */

/* Every interactive element gets a ring the dark palette cannot swallow.
   :focus-visible, so a mouse click does not leave one sitting there. */
:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
  border-radius: 3px;
}
main:focus-visible { outline: none; }

/* Off-screen until tabbed to, so a keyboard user is not walked through the
   whole nav on every page before reaching anything. */
.skip {
  position: fixed; top: 0; left: 50%; z-index: 200;
  transform: translate(-50%, -130%);
  background: var(--teal); color: var(--on-accent);
  font-family: var(--body); font-size: 14px; font-weight: 600;
  padding: 11px 20px; border-radius: 0 0 12px 12px; text-decoration: none;
  transition: transform 0.16s ease;
}
.skip:focus { transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) { .skip { transition: none; } }

/* Plus is unlocked for testers during the beta. That is good news, not a caveat,
   so it reads in the accent rather than in the muted note colour. */
.beta-note { color: var(--teal); }

/* ---------- the seven send buttons ---------- */

/* Rebuilt from the app's SendButton.kt so the motion matches rather than merely rhymes.
   Two timings govern everything: the ambient "breath" runs 2400ms each way (4.8s round
   trip) and a send burst is 780ms. Every burst quantity starts and ends at zero — the
   app's own rule, because ending a burst anywhere but where it started teleports
   whatever the burst was moving. The bright end of each animation is the accent lit up,
   not a fixed neon, which is why a theme's own colours carry through. */

:root { --sb-hot: #AEDEDD; }   /* the accent lifted 45% toward white, as the app computes it */

.send-rail {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr));
  gap: 30px 14px; margin-top: 4px;
}
.sb { display: flex; flex-direction: column; align-items: center; gap: 14px; margin: 0; text-align: center; }
.sb-stage { position: relative; width: 100px; height: 80px; display: grid; place-items: center; }
.sb-btn {
  position: relative; width: 52px; height: 52px; display: grid; place-items: center;
  padding: 0; border: 0; background: none; cursor: pointer; border-radius: 16px;
  transition: transform 0.12s ease;
}
.sb-btn:active { transform: scale(0.92); }
.sb-arrow {
  position: relative; z-index: 5; width: 22px; height: 22px;
  fill: none; stroke: var(--on-accent); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.sb-tile { position: absolute; z-index: 2; width: 52px; height: 52px; border-radius: 16px; background: var(--teal); }
.sb-aura { position: absolute; z-index: 1; left: 50%; top: 50%; transform: translate(-50%, -50%); pointer-events: none; }
.sb-burst { position: absolute; z-index: 4; left: 50%; top: 50%; opacity: 0; pointer-events: none; }
.sb-name { font-family: var(--display); font-size: 16px; font-weight: 700; color: var(--text-strong); }
.sb-tier {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 999px; margin-left: 8px; vertical-align: 2px;
  color: var(--tertiary); border: 1px solid var(--hairline);
}
.sb-tier.is-plus { color: var(--teal); border-color: rgba(108,196,193,0.34); background: rgba(108,196,193,0.10); }
.sb-desc { display: block; margin-top: 6px; font-size: 14px; line-height: 1.5; color: var(--secondary); }
@media (min-width: 600px) { .send-rail { grid-template-columns: repeat(auto-fit, minmax(186px, 1fr)); gap: 34px 20px; } }
.sb-hint { font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tertiary); margin-top: 26px; }

/* Classic — "Stays where it is." It genuinely does; that is the whole point of it. */

/* Pulse — "Breathes while you have something to send." */
.sb-pulse .sb-tile { border-radius: 20px 20px 11px 11px; animation: sbBreath 4.8s ease-in-out infinite; }
.sb-pulse .sb-aura {
  width: 96px; height: 96px; border-radius: 50%;
  background: radial-gradient(circle, rgba(108,196,193,0.38) 0%, rgba(201,139,219,0.17) 46%, transparent 70%);
  animation: sbAura 4.8s ease-in-out infinite;
}
@keyframes sbBreath { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.045); } }
@keyframes sbAura {
  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.82; }
  50%      { transform: translate(-50%, -50%) scale(1.16); opacity: 1; }
}
.sb-pulse.is-firing .sb-aura { animation: sbAuraFire 0.78s linear; }
@keyframes sbAuraFire {
  0%   { transform: translate(-50%, -50%) scale(1);    opacity: 0.82; }
  35%  { transform: translate(-50%, -50%) scale(1.52); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1);    opacity: 0.82; }
}

/* Ripple — "Rings spread across the message box." A disc, because the silhouette has to
   tell the styles apart before anything moves. */
.sb-ripple .sb-tile { border-radius: 50%; }
.sb-ripple .sb-rest-a, .sb-ripple .sb-rest-b {
  position: absolute; left: 50%; top: 50%; border-radius: 50%; transform: translate(-50%, -50%);
}
.sb-ripple .sb-rest-a { width: 59px; height: 59px; border: 1.4px solid rgba(108,196,193,0.40); }
.sb-ripple .sb-rest-b { width: 68px; height: 68px; border: 1px solid rgba(201,139,219,0.16); animation: sbRest 4.8s ease-in-out infinite; }
@keyframes sbRest {
  0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: 0.7; }
  50%      { transform: translate(-50%, -50%) scale(1.06); opacity: 1; }
}
.sb-ripple .sb-burst { width: 52px; height: 52px; margin: -26px 0 0 -26px; }
.sb-ripple .sb-burst i {
  position: absolute; left: 50%; top: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 50%; border: 3px solid var(--teal); opacity: 0;
}
.sb-ripple .sb-burst i:nth-child(1) { border-color: var(--sb-hot); }
.sb-ripple .sb-burst i:nth-child(2) { border-color: var(--teal); }
.sb-ripple .sb-burst i:nth-child(3), .sb-ripple .sb-burst i:nth-child(4) { border-color: var(--orchid); }
.sb-ripple.is-firing .sb-burst { opacity: 1; }
.sb-ripple.is-firing .sb-burst i { animation: sbRipple 0.78s linear; }
/* The four rings are staggered 0.12 apart as in the app, but each is shortened so the
   last one still lands on 780ms rather than being cut off when the burst class comes off. */
.sb-ripple.is-firing .sb-burst i:nth-child(2) { animation-delay: 0.094s; animation-duration: 0.686s; }
.sb-ripple.is-firing .sb-burst i:nth-child(3) { animation-delay: 0.188s; animation-duration: 0.592s; }
.sb-ripple.is-firing .sb-burst i:nth-child(4) { animation-delay: 0.281s; animation-duration: 0.499s; }
@keyframes sbRipple {
  0%   { transform: scale(0.5);  opacity: 0.85; border-width: 4px; }
  100% { transform: scale(2.05); opacity: 0;    border-width: 0.8px; }
}

/* Halo — "A neon ring that cracks with lightning." No fill at all: a ring with nothing
   in it, so the arrow sits on the page rather than on a tile. It is a neon tube, so it
   needs the bloom a tube throws, not a hairline circle. */
.sb-halo .sb-tile { background: transparent; }
.sb-halo .sb-arrow { stroke: var(--text-strong); }
.sb-halo .sb-haze {
  position: absolute; left: 50%; top: 50%; width: 88px; height: 88px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(108,196,193,0.42) 0%, rgba(201,139,219,0.22) 42%, rgba(108,196,193,0) 72%);
  animation: sbAura 4.8s ease-in-out infinite;
}
.sb-halo .sb-ring, .sb-halo .sb-arc {
  position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; border-radius: 50%;
}
.sb-halo .sb-ring {
  background: conic-gradient(var(--teal), var(--orchid), #FFFFFF, var(--sb-hot), var(--orchid), var(--teal));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.6px), #000 calc(100% - 3.6px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3.6px), #000 calc(100% - 3.6px));
  filter: drop-shadow(0 0 7px rgba(108,196,193,0.95)) drop-shadow(0 0 16px rgba(201,139,219,0.55));
  animation: sbSpin180 4.8s ease-in-out infinite;
}
.sb-halo .sb-arc {
  background: conic-gradient(#FFFFFF 0deg 40deg, transparent 40deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.4px), #000 calc(100% - 2.4px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.4px), #000 calc(100% - 2.4px));
  filter: drop-shadow(0 0 5px rgba(255,255,255,0.9));
  animation: sbSpin360 4.8s ease-in-out infinite;
}
@keyframes sbSpin180 { 0%, 100% { transform: translate(-50%, -50%) rotate(0deg); } 50% { transform: translate(-50%, -50%) rotate(180deg); } }
@keyframes sbSpin360 { 0%, 100% { transform: translate(-50%, -50%) rotate(0deg); } 50% { transform: translate(-50%, -50%) rotate(360deg); } }
.sb-halo .sb-burst { width: 220px; height: 220px; margin: -110px 0 0 -110px; }
.sb-halo .sb-bolts { width: 220px; height: 220px; overflow: visible; }
/* Measured off the device: the bolts reach about four times the button's radius, they
   are thick rather than hairline, and they are a white core inside a coloured glow. */
.sb-halo .sb-bolts .bolt-group path {
  stroke: #FFFFFF; stroke-width: 2.4; fill: none; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 3px rgba(233,199,240,1)) drop-shadow(0 0 7px rgba(201,139,219,0.9));
}
.sb-halo .sb-bolts .flash { fill: rgba(255,255,255,0.9); filter: blur(9px); }
.sb-halo .sb-bolts .chase-ring { fill: none; stroke: rgba(233,199,240,0.55); stroke-width: 1.6; }
.sb-halo .sb-bolts .spark { fill: rgba(255,255,255,0.85); }
.sb-halo.is-firing .sb-burst { opacity: 1; }
/* The app grows the bolts fast then eases out (spread = 1-(1-t)^2), so the group scales
   on the same curve rather than linearly. */
.sb-halo.is-firing .bolt-group { animation: sbBoltGrow 0.78s cubic-bezier(0, 0.62, 0.36, 1); }
.sb-halo.is-firing .flash      { animation: sbFlashOut 0.78s ease-out; }
.sb-halo.is-firing .chase-ring { animation: sbChaseRing 0.78s cubic-bezier(0, 0.62, 0.36, 1); }
.sb-halo.is-firing .spark      { animation: sbSparkOut 0.78s ease-out; }
@keyframes sbBoltGrow {
  0%   { transform: scale(0.16); opacity: 1; }
  55%  { opacity: 0.95; }
  100% { transform: scale(1);    opacity: 0; }
}
@keyframes sbFlashOut {
  0%   { transform: scale(1.5); opacity: 1; }
  100% { transform: scale(0.5); opacity: 0; }
}
@keyframes sbChaseRing {
  0%   { transform: scale(0.24); opacity: 0.9; }
  100% { transform: scale(1.5);  opacity: 0; }
}
@keyframes sbSparkOut {
  0%   { transform: scale(0.3); opacity: 1; }
  100% { transform: scale(1.2); opacity: 0; }
}
.sb-halo .sb-bolts .flash, .sb-halo .sb-bolts .chase-ring,
.sb-halo .sb-bolts .bolt-group, .sb-halo .sb-bolts .spark { transform-origin: 110px 110px; }
.sb-halo.is-firing .sb-ring { animation: sbHaloFlash 0.78s linear; }
.sb-halo.is-firing .sb-haze { animation: sbHazeFlash 0.78s linear; }
@keyframes sbHaloFlash {
  0%   { transform: translate(-50%, -50%) scale(1.22); filter: brightness(3) drop-shadow(0 0 18px rgba(255,255,255,1)); }
  100% { transform: translate(-50%, -50%) scale(1);    filter: brightness(1) drop-shadow(0 0 7px rgba(108,196,193,0.95)); }
}
@keyframes sbHazeFlash {
  0%   { transform: translate(-50%, -50%) scale(1.6); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1);   opacity: 0.82; }
}

/* Aurora — "Light through glass, and a curtain that rains back down." A pane stood on
   end, 40 by 52, with colour moving through it. */
.sb-aurora .sb-tile {
  width: 40px; height: 52px; border-radius: 13px; overflow: hidden;
  background: linear-gradient(180deg, var(--teal) 0%, var(--orchid) 38%, var(--sb-hot) 62%, var(--teal) 100%);
  background-size: 100% 280%;
  animation: sbDrift 4.8s ease-in-out infinite;
  box-shadow: 0 0 18px rgba(108,196,193,0.22);
}
@keyframes sbDrift { 0%, 100% { background-position: 0% 0%; } 50% { background-position: 0% 100%; } }
.sb-aurora .sb-sheet {
  position: absolute; z-index: 3; left: 50%; top: 50%; width: 40px; height: 52px; margin: -26px 0 0 -20px;
  border-radius: 13px; opacity: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.85), rgba(174,222,221,0.35) 45%, transparent 75%);
}
.sb-aurora.is-firing .sb-sheet { animation: sbSheet 0.78s cubic-bezier(0.2, 0.7, 0.3, 1); }
.sb-aurora.is-firing .sb-tile { animation: sbDrift 4.8s ease-in-out infinite, sbFlood 0.78s linear; }
@keyframes sbSheet {
  0%   { opacity: 0.95; transform: translateY(0) scaleY(1); }
  100% { opacity: 0;    transform: translateY(-46px) scaleY(0.55); }
}
@keyframes sbFlood { 0%, 100% { filter: brightness(1); } 30% { filter: brightness(1.9); } }

/* Orbit — "Satellites slung out as it sends, then recaptured." A small body in a ring
   tilted -0.38rad, with a satellite at each end of it. The satellites are positioned by
   generated keyframes rather than a motion path: offset-path resolves its origin from
   the element's static position, which put them 84px outside the ring. */
.sb-orbit .sb-tile { width: 32px; height: 32px; border-radius: 50%; }
.sb-orbit .sb-plane { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
.sb-orbit .sb-ellipse {
  position: absolute; left: 50%; top: 50%; width: 90px; height: 36px; margin: -18px 0 0 -45px;
  border: 1px solid rgba(201,139,219,0.50); border-radius: 50%;
  transform: rotate(-21.8deg);
  box-shadow: 0 0 14px -4px rgba(201,139,219,0.5);
}
.sb-orbit .sat {
  position: absolute; left: 0; top: 0; width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border-radius: 50%; background: var(--sb-hot);
  box-shadow: 0 0 9px rgba(174,222,221,0.95);
  animation: sbOrbit 4.8s linear infinite;
}
.sb-orbit .sat-b { animation-delay: -2.4s; background: var(--orchid); box-shadow: 0 0 9px rgba(201,139,219,0.95); }
@keyframes sbOrbit {
  0.0000% { transform: translate(41.79px, -16.69px); }
  2.0833% { transform: translate(42.30px, -14.37px); }
  4.1667% { transform: translate(42.09px, -11.80px); }
  6.2500% { transform: translate(41.16px, -9.02px); }
  8.3333% { transform: translate(39.53px, -6.10px); }
  10.4167% { transform: translate(37.22px, -3.07px); }
  12.5000% { transform: translate(34.27px, 0.02px); }
  14.5833% { transform: translate(30.74px, 3.10px); }
  16.6667% { transform: translate(26.68px, 6.13px); }
  18.7500% { transform: translate(22.16px, 9.06px); }
  20.8333% { transform: translate(17.27px, 11.83px); }
  22.9167% { transform: translate(12.07px, 14.39px); }
  25.0000% { transform: translate(6.68px, 16.72px); }
  27.0833% { transform: translate(1.16px, 18.75px); }
  29.1667% { transform: translate(-4.37px, 20.47px); }
  31.2500% { transform: translate(-9.82px, 21.83px); }
  33.3333% { transform: translate(-15.11px, 22.82px); }
  35.4167% { transform: translate(-20.14px, 23.42px); }
  37.5000% { transform: translate(-24.83px, 23.62px); }
  39.5833% { transform: translate(-29.09px, 23.42px); }
  41.6667% { transform: translate(-32.85px, 22.81px); }
  43.7500% { transform: translate(-36.05px, 21.82px); }
  45.8333% { transform: translate(-38.64px, 20.45px); }
  47.9167% { transform: translate(-40.56px, 18.73px); }
  50.0000% { transform: translate(-41.79px, 16.69px); }
  52.0833% { transform: translate(-42.30px, 14.37px); }
  54.1667% { transform: translate(-42.09px, 11.80px); }
  56.2500% { transform: translate(-41.16px, 9.02px); }
  58.3333% { transform: translate(-39.53px, 6.10px); }
  60.4167% { transform: translate(-37.22px, 3.07px); }
  62.5000% { transform: translate(-34.27px, -0.02px); }
  64.5833% { transform: translate(-30.74px, -3.10px); }
  66.6667% { transform: translate(-26.68px, -6.13px); }
  68.7500% { transform: translate(-22.16px, -9.06px); }
  70.8333% { transform: translate(-17.27px, -11.83px); }
  72.9167% { transform: translate(-12.07px, -14.39px); }
  75.0000% { transform: translate(-6.68px, -16.72px); }
  77.0833% { transform: translate(-1.16px, -18.75px); }
  79.1667% { transform: translate(4.37px, -20.47px); }
  81.2500% { transform: translate(9.82px, -21.83px); }
  83.3333% { transform: translate(15.11px, -22.82px); }
  85.4167% { transform: translate(20.14px, -23.42px); }
  87.5000% { transform: translate(24.83px, -23.62px); }
  89.5833% { transform: translate(29.09px, -23.42px); }
  91.6667% { transform: translate(32.85px, -22.81px); }
  93.7500% { transform: translate(36.05px, -21.82px); }
  95.8333% { transform: translate(38.64px, -20.45px); }
  97.9167% { transform: translate(40.56px, -18.73px); }
  100.0000% { transform: translate(41.79px, -16.69px); }
}
/* The glow brightens on a send rather than the transform changing: the satellites are
   already driven by transform, and two animations cannot share one property. */
.sb-orbit.is-firing .sat { animation: sbOrbit 4.8s linear infinite, sbSatFire 0.78s ease-out; }
@keyframes sbSatFire {
  0%   { box-shadow: 0 0 24px 6px rgba(255,255,255,0.95); filter: brightness(2.4); }
  100% { box-shadow: 0 0 9px rgba(174,222,221,0.95);      filter: brightness(1); }
}
.sb-orbit .sb-throw {
  position: absolute; left: 50%; top: 50%; width: 90px; height: 36px; margin: -18px 0 0 -45px;
  border: 1px solid rgba(201,139,219,0.75); border-radius: 50%; opacity: 0;
}
/* "the ring is thrown off in three" — each leaves on its own tilt, which is what makes
   it read as rings shed rather than one ring simply scaled up. */
.sb-orbit.is-firing .sb-throw { animation: sbThrow 0.78s cubic-bezier(0.1, 0.6, 0.35, 1); }
.sb-orbit.is-firing .t1 { animation-delay: 0s;     animation-duration: 0.78s; }
.sb-orbit.is-firing .t2 { animation-delay: 0.07s;  animation-duration: 0.71s; }
.sb-orbit.is-firing .t3 { animation-delay: 0.14s;  animation-duration: 0.64s; }
.sb-orbit .t1 { transform: rotate(-21.8deg); }
.sb-orbit .t2 { transform: rotate(-4deg); }
.sb-orbit .t3 { transform: rotate(-38deg); }
@keyframes sbThrow {
  0%   { opacity: 0.95; }
  100% { opacity: 0; }
}
.sb-orbit.is-firing .t1 { animation-name: sbThrow1; }
.sb-orbit.is-firing .t2 { animation-name: sbThrow2; }
.sb-orbit.is-firing .t3 { animation-name: sbThrow3; }
@keyframes sbThrow1 {
  0%   { transform: rotate(-21.8deg) scale(1);   opacity: 0.95; border-color: #FFFFFF; }
  100% { transform: rotate(-46deg)   scale(2.6); opacity: 0; }
}
@keyframes sbThrow2 {
  0%   { transform: rotate(-4deg)  scale(1);   opacity: 0.85; border-color: #FFFFFF; }
  100% { transform: rotate(26deg)  scale(2.9); opacity: 0; }
}
@keyframes sbThrow3 {
  0%   { transform: rotate(-38deg) scale(1);   opacity: 0.8; border-color: var(--sb-hot); }
  100% { transform: rotate(-74deg) scale(3.2); opacity: 0; }
}
/* The core blooms as it goes. */
.sb-orbit.is-firing .sb-tile { animation: sbCoreBloom 0.78s ease-out; }
@keyframes sbCoreBloom {
  0%   { box-shadow: 0 0 34px 12px rgba(174,222,221,0.85); filter: brightness(1.8); }
  100% { box-shadow: 0 0 0 0 rgba(174,222,221,0);          filter: brightness(1); }
}

/* Marquee — "A lit sign whose bulbs run the edge of the screen." Landscape, 62 by 38.
   The sign is filled with the accent and the bulbs are punched into it dark, the way the
   app draws it: drawPath(sign, accent) then bulbs in onAccent, lit towards hot as the
   chase passes. Twenty bulbs on an inset path, three lit at a time. */
.sb-marquee .sb-btn { width: 62px; height: 38px; }
.sb-marquee .sb-tile {
  width: 62px; height: 38px; border-radius: 10px;
  background: var(--teal); border: 0;
}
.sb-marquee .sb-sign-wrap { position: absolute; z-index: 3; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
.sb-marquee .sb-sign { position: absolute; left: 50%; top: 50%; width: 62px; height: 38px; margin: -19px 0 0 -31px; overflow: visible; }
/* The unlit bulbs, and the painted inner rule a sign has. */
.sb-marquee .sb-sign .bulbs {
  fill: none; stroke: rgba(6,32,31,0.42); stroke-width: 3.8;
  stroke-linecap: round; stroke-dasharray: 0.01 7.685;
}
.sb-marquee .sb-sign .rule { fill: none; stroke: rgba(6,32,31,0.16); stroke-width: 1; }
.sb-marquee .mq-chase {
  position: absolute; left: 0; top: 0; width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px;
  border-radius: 50%; background: #EAFBFA;
  box-shadow: 0 0 7px 2px rgba(174,222,221,0.95);
  animation: sbChase 4.8s linear infinite;
}
.sb-marquee .mq-chase-2 { animation-delay: -0.20s; opacity: 0.72; }
.sb-marquee .mq-chase-3 { animation-delay: -0.40s; opacity: 0.45; }
@keyframes sbChase {
  0.0000% { transform: translate(-20.50px, -14.50px); }
  1.7857% { transform: translate(-17.76px, -14.50px); }
  3.5714% { transform: translate(-15.01px, -14.50px); }
  5.3571% { transform: translate(-12.27px, -14.50px); }
  7.1429% { transform: translate(-9.52px, -14.50px); }
  8.9286% { transform: translate(-6.78px, -14.50px); }
  10.7143% { transform: translate(-4.03px, -14.50px); }
  12.5000% { transform: translate(-1.29px, -14.50px); }
  14.2857% { transform: translate(1.46px, -14.50px); }
  16.0714% { transform: translate(4.20px, -14.50px); }
  17.8571% { transform: translate(6.95px, -14.50px); }
  19.6429% { transform: translate(9.69px, -14.50px); }
  21.4286% { transform: translate(12.44px, -14.50px); }
  23.2143% { transform: translate(15.18px, -14.50px); }
  25.0000% { transform: translate(17.92px, -14.50px); }
  26.7857% { transform: translate(20.67px, -14.50px); }
  28.5714% { transform: translate(23.30px, -13.81px); }
  30.3571% { transform: translate(25.36px, -12.02px); }
  32.1429% { transform: translate(26.41px, -9.52px); }
  33.9286% { transform: translate(26.50px, -6.78px); }
  35.7143% { transform: translate(26.50px, -4.03px); }
  37.5000% { transform: translate(26.50px, -1.29px); }
  39.2857% { transform: translate(26.50px, 1.46px); }
  41.0714% { transform: translate(26.50px, 4.20px); }
  42.8571% { transform: translate(26.50px, 6.95px); }
  44.6429% { transform: translate(26.38px, 9.68px); }
  46.4286% { transform: translate(25.25px, 12.16px); }
  48.2143% { transform: translate(23.15px, 13.88px); }
  50.0000% { transform: translate(20.50px, 14.50px); }
  51.7857% { transform: translate(17.76px, 14.50px); }
  53.5714% { transform: translate(15.01px, 14.50px); }
  55.3571% { transform: translate(12.27px, 14.50px); }
  57.1429% { transform: translate(9.52px, 14.50px); }
  58.9286% { transform: translate(6.78px, 14.50px); }
  60.7143% { transform: translate(4.03px, 14.50px); }
  62.5000% { transform: translate(1.29px, 14.50px); }
  64.2857% { transform: translate(-1.46px, 14.50px); }
  66.0714% { transform: translate(-4.20px, 14.50px); }
  67.8571% { transform: translate(-6.95px, 14.50px); }
  69.6429% { transform: translate(-9.69px, 14.50px); }
  71.4286% { transform: translate(-12.44px, 14.50px); }
  73.2143% { transform: translate(-15.18px, 14.50px); }
  75.0000% { transform: translate(-17.92px, 14.50px); }
  76.7857% { transform: translate(-20.67px, 14.50px); }
  78.5714% { transform: translate(-23.30px, 13.81px); }
  80.3571% { transform: translate(-25.36px, 12.02px); }
  82.1429% { transform: translate(-26.41px, 9.52px); }
  83.9286% { transform: translate(-26.50px, 6.78px); }
  85.7143% { transform: translate(-26.50px, 4.03px); }
  87.5000% { transform: translate(-26.50px, 1.29px); }
  89.2857% { transform: translate(-26.50px, -1.46px); }
  91.0714% { transform: translate(-26.50px, -4.20px); }
  92.8571% { transform: translate(-26.50px, -6.95px); }
  94.6429% { transform: translate(-26.38px, -9.68px); }
  96.4286% { transform: translate(-25.25px, -12.16px); }
  98.2143% { transform: translate(-23.15px, -13.88px); }
  100.0000% { transform: translate(-20.50px, -14.50px); }
}
/* Two halos pushed off the sign, not three — `for (i in 0 until 2)`. */
.sb-marquee .mq-ring {
  position: absolute; left: 50%; top: 50%; width: 76px; height: 52px; margin: -26px 0 0 -38px;
  border: 1.4px solid var(--sb-hot); border-radius: 16px; opacity: 0;
}
.sb-marquee .mq-ring.r3 { display: none; }
.sb-marquee.is-firing .mq-ring { animation: sbMqRing 0.78s cubic-bezier(0.1, 0.6, 0.35, 1); }
.sb-marquee.is-firing .r2 { animation-delay: 0.17s; animation-duration: 0.61s; border-color: var(--orchid); }
@keyframes sbMqRing {
  0%   { transform: scale(1);   opacity: 0.6; }
  100% { transform: scale(2.6); opacity: 0; }
}
/* The kick a sign gives when it comes on is a buzz, not a swell. */
.sb-marquee.is-firing .sb-tile { animation: sbBuzz 0.78s linear, sbSignBloom 0.78s ease-out; }
@keyframes sbBuzz {
  0%, 14%, 100% { transform: translate(0, 0); }
  3%  { transform: translate(-1px, -0.6px); }
  6%  { transform: translate(1px, 0.6px); }
  9%  { transform: translate(-1px, 0.6px); }
  12% { transform: translate(1px, -0.6px); }
}
@keyframes sbSignBloom {
  0%   { box-shadow: 0 0 34px 10px rgba(174,222,221,0.85); filter: brightness(1.5); }
  100% { box-shadow: 0 0 0 0 rgba(174,222,221,0);          filter: brightness(1); }
}
/* "Every bulb on at once, a beat after the sprint" — in at 0.22, out by the end. */
.sb-marquee.is-firing .bulbs { animation: sbBulbs 0.78s linear; }
@keyframes sbBulbs {
  0%, 22%  { stroke: rgba(6,32,31,0.42); stroke-width: 3.8; }
  34%      { stroke: #EAFBFA; stroke-width: 4.8; }
  100%     { stroke: rgba(6,32,31,0.42); stroke-width: 3.8; }
}
.sb-marquee.is-firing .mq-chase { animation: sbChase 0.39s linear 2; }

/* The phone's "remove animations" setting is honoured in the app; the browser's is here. */
@media (prefers-reduced-motion: reduce) {
  .sb *, .sb *::before, .sb *::after { animation: none !important; transition: none !important; }
}

/* ---------- finish ---------- */

/* The headline and the figures pick up the same gradient the phone's own "Messages"
   title uses, so the page and the product look like one thing. Guarded: without
   background-clip the text would simply vanish. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero h1, .stat b, .tier .price {
    background-image: linear-gradient(104deg, var(--text-strong) 0%, var(--text-strong) 38%, #F7B3D7 72%, #9FE3E0 100%);
    background-size: 220% 100%;
    -webkit-background-clip: text; background-clip: text;
    color: transparent; -webkit-text-fill-color: transparent;
    animation: sheen 16s ease-in-out infinite;
  }
  .stat b, .tier .price { background-size: 160% 100%; animation-duration: 20s; }
}
@keyframes sheen { 0%, 100% { background-position: 0% 0; } 50% { background-position: 100% 0; } }

/* The two lights behind the hero drift, so the top of the page is never quite still. */
.hero::before { animation: driftA 26s ease-in-out infinite; }
.hero::after  { animation: driftB 31s ease-in-out infinite; }
@keyframes driftA {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(38px, 26px, 0) scale(1.09); }
}
@keyframes driftB {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-44px, -30px, 0) scale(1.12); }
}

/* Cards lift towards the reader, and the accent picks out the edge. */
.card, .tier, .plate-wide, .honest {
  transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.3, 1), border-color 0.32s ease, box-shadow 0.32s ease;
}
.card:hover, .plate-wide:hover, .honest:hover {
  transform: translateY(-4px);
  border-color: rgba(108, 196, 193, 0.30);
  box-shadow: 0 22px 46px -26px rgba(0, 0, 0, 0.95), 0 0 34px -18px rgba(108, 196, 193, 0.35);
}
.tier:hover { transform: translateY(-4px); box-shadow: 0 22px 46px -26px rgba(0, 0, 0, 0.95); }
.tier.plus:hover { border-color: rgba(108, 196, 193, 0.52); box-shadow: 0 22px 46px -26px rgba(0, 0, 0, 0.95), 0 0 40px -18px rgba(108, 196, 193, 0.45); }
.theme-card { transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.3, 1); }
.theme-card:hover { transform: translateY(-5px) scale(1.012); }
.sb-btn:hover { filter: brightness(1.12); }

/* A little film grain over the whole page: it keeps the large flat panels from banding
   and gives the dark ground some tooth. Non-interactive, so it never catches a click. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 9998; pointer-events: none;
  opacity: 0.030; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Scroll reveal. Only ever applied when reveal.js has confirmed it can finish the job. */
.js-reveal .section-head, .js-reveal .card, .js-reveal .tier, .js-reveal .plate-wide,
.js-reveal .honest, .js-reveal .theme-card, .js-reveal .sb, .js-reveal .compare, .js-reveal .request {
  opacity: 0; transform: translateY(16px);
  transition: opacity 0.62s ease, transform 0.62s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.js-reveal .is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .hero::before, .hero::after, .hero h1, .stat b, .tier .price { animation: none !important; }
  .card, .tier, .plate-wide, .honest, .theme-card { transition: none !important; }
  .card:hover, .tier:hover, .plate-wide:hover, .honest:hover, .theme-card:hover { transform: none !important; }
}

/* Plus features are badged in the feature grid the same way the app badges them in its
   own picker. The vault and auto-reply are paid in full — decided in Paywalled Features —
   and a reader should learn that here rather than after installing. */
.plus-tag {
  display: inline-block; vertical-align: 3px; margin-left: 10px;
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 999px;
  color: var(--teal); border: 1px solid rgba(108,196,193,0.34); background: rgba(108,196,193,0.10);
}
