/* ==========================================================================
   Lectavi, the marketing site.

   The visual system is the APP's, lifted rather than reinterpreted: the same
   tokens, the same faces, the same motion curve, the same violet tinted
   shadows. Somebody who downloads after reading this page should recognise
   the thing that opens.

   The product's own rule survives from the app and governs the page: what a
   lecturer SAID is set in mono and carries a timestamp; what Lectavi WROTE is
   set in serif and never does.
   ========================================================================== */

:root {
  /* Brand. Violet rather than blue, because blue is the colour every
     productivity tool already owns. */
  --color-brand: #6c4df6;
  --color-brand-soft: #8b72ff;
  --color-brand-deep: #5638dc;
  --color-brand-wash: #f6f4ff;

  /* Surfaces, and a neutral ramp biased violet so the greys sit underneath the
     brand rather than beside it. */
  --color-surface: #ffffff;
  --color-raised: #fafafd;
  --color-sunk: #f4f3f8;
  --color-line: #e7e5ef;
  --color-line-soft: #f0eff5;
  --color-faint: #a8a4bb;
  --color-muted: #6b6880;
  --color-ink: #14121f;

  /* Dividing one whole into parts: the grading table on the class page. */
  --grade-1: #6c4df6;
  --grade-2: #00a5c4;
  --grade-3: #e8892b;
  --grade-4: #11a86f;

  --color-good: #14b47a;
  /*
   * A green that can carry small text, and a ground for it.
   *
   * --color-good above is a status dot, and at 2.68:1 on white it is right
   * for a filled shape and wrong for anything anybody has to read. Measured
   * rather than eyeballed: this pair is 4.83:1, which an 11px bold pill
   * needs, since only 14px bold counts as large text.
   */
  --color-good-deep: #0b7a52;
  --color-good-wash: #e6f7f0;
  --color-flag: #e8a33d;
  --color-halt: #e5484d;

  --r-dot: 2px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-full: 999px;

  /* Light falls the same way on every surface here: a hairline ring, a close
     shadow, and a wide violet tinted one further out. */
  --shadow-sm:
    0 0 0 1px rgba(20, 18, 31, 0.025),
    0 1px 2px rgba(20, 18, 31, 0.04),
    0 2px 6px -2px rgba(108, 77, 246, 0.07);
  --shadow-md:
    0 0 0 1px rgba(20, 18, 31, 0.03),
    0 2px 4px -1px rgba(20, 18, 31, 0.05),
    0 8px 20px -6px rgba(108, 77, 246, 0.16);
  --shadow-lg:
    0 0 0 1px rgba(20, 18, 31, 0.035),
    0 8px 16px -6px rgba(20, 18, 31, 0.07),
    0 24px 48px -14px rgba(108, 77, 246, 0.24);

  /* Two speeds and one curve, so everything moves like the same object. The
     spring is reserved for the primary action and for the logo's last beat. */
  --t-fast: 140ms;
  --t: 240ms;
  --t-slow: 420ms;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --font-ui: 'Plus Jakarta Sans', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', 'Cascadia Mono', Consolas, ui-monospace, monospace;
  --font-serif: Georgia, 'Iowan Old Style', 'Times New Roman', serif;

  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

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

/* ---- the surfaces the browser draws, which belong to no design system ---- */

::selection { background: var(--color-brand-wash); color: var(--color-brand-deep); }

:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 3px;
  border-radius: var(--r-dot);
}

:root { accent-color: var(--color-brand); }
input, textarea { caret-color: var(--color-brand); }

html { scrollbar-color: var(--color-line) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--color-line);
  border: 3px solid var(--color-surface);
  border-radius: var(--r-full);
}
::-webkit-scrollbar-thumb:hover { background: var(--color-faint); }

a { color: inherit; text-underline-offset: 0.18em; text-decoration-thickness: 1px; }

/* Every number here is a measurement, so they all line up in a column. */
td, th, .price, .stamp, .clock, .live { font-variant-numeric: tabular-nums; }

img, svg { display: block; max-width: 100%; }

/* ---- measure ------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 48px);
}

.prose { max-width: 62ch; }

/*
 * Space, which is most of what separates a page that reads as calm from one
 * that reads as cramped.
 *
 * Roughly doubled. The previous clamp topped out at 128px, and a section break
 * of 128px on a 1440px screen is a paragraph gap, not a change of subject.
 * Tied to viewport height as well as width, because what makes a section feel
 * like its own screen is how much of the screen it has.
 */
section { padding-block: clamp(112px, 16vh, 200px) clamp(84px, 12vh, 150px); }
section + section { padding-top: clamp(96px, 14vh, 180px); }

.stack   { display: flex; flex-direction: column; gap: 22px; }
.stack-s { display: flex; flex-direction: column; gap: 12px; }

/* ---- type ---------------------------------------------------------------- */

h1, h2, h3 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.06;
  text-wrap: balance;
}

h1 { font-size: clamp(2.6rem, 6.6vw, 4.6rem); letter-spacing: -0.038em; }
h2 { font-size: clamp(1.8rem, 3.4vw, 2.7rem); letter-spacing: -0.032em; }
h3 { font-size: 1.06rem; letter-spacing: -0.02em; line-height: 1.3; }

p { margin: 0; }

.lede {
  font-size: clamp(1.02rem, 1.4vw, 1.18rem);
  line-height: 1.6;
  color: var(--color-muted);
  max-width: 60ch;
}

.note { font-size: 0.84rem; line-height: 1.55; color: var(--color-muted); }

/* The app's small caps label, used for the same job it does there. */
.label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--color-faint);
}

/* ==========================================================================
   The card, the button, the tag: the app's own components
   ========================================================================== */

.card {
  background: var(--color-surface);
  border: 1px solid color-mix(in srgb, var(--color-line) 70%, var(--color-surface));
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}

.card-hover {
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.card-hover:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-brand-soft);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 18px;
  border: 1px solid var(--color-line);
  border-radius: var(--r-md);
  background: var(--color-surface);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 1px 2px rgba(20, 18, 31, 0.04);
  color: var(--color-ink);
  font: 500 14px/1.4 var(--font-ui);
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--t-fast) var(--ease),
    background var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    box-shadow var(--t-fast) var(--ease);
}
.btn:hover { background: var(--color-raised); border-color: var(--color-faint); }
.btn:active { transform: translateY(1px); }

.btn-lg { padding: 15px 24px; font-size: 15px; }

/* The one control the page exists for, and the only place the spring is spent. */
.btn-primary {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: #fff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 1px 2px rgba(20, 18, 31, 0.12),
    0 8px 20px -8px rgba(108, 77, 246, 0.55);
  transition:
    transform var(--t) var(--ease-spring),
    background var(--t-fast) var(--ease),
    box-shadow var(--t) var(--ease);
}
.btn-primary:hover {
  background: var(--color-brand-deep);
  border-color: var(--color-brand-deep);
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.26),
    0 2px 4px rgba(20, 18, 31, 0.14),
    0 14px 30px -10px rgba(108, 77, 246, 0.62);
}
.btn-primary:active { transform: translateY(0); }

.tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--r-full);
  background: var(--color-sunk);
  color: var(--color-muted);
  font-size: 12px;
  font-weight: 500;
}

.tag-brand { background: var(--color-brand-wash); color: var(--color-brand-deep); }

/* ==========================================================================
   The mark, animated the way the app's own splash animates it
   ========================================================================== */

.mark { display: inline-flex; align-items: center; gap: 11px; text-decoration: none; color: inherit; }

.mark svg { width: 30px; height: 30px; filter: drop-shadow(0 4px 12px rgba(108, 77, 246, 0.28)); }
.mark-lg svg { width: 92px; height: 92px; filter: drop-shadow(0 12px 28px rgba(108, 77, 246, 0.34)); }

.mark-word {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.028em;
  color: var(--color-ink);
}
.mark-lg .mark-word { font-size: 30px; }

/* Three beats, exactly as src/renderer/splash/index.html plays them: the tile
   arrives, the stroke draws itself, the tip pops. The rule lifting off the
   stem is the product in one gesture, so it is drawn rather than revealed. */
.mark .tile {
  transform-origin: 48px 48px;
  animation: tile 520ms var(--ease) both;
}
.mark .stroke {
  fill: none;
  stroke: #ffffff;
  stroke-width: 8.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 92;
  stroke-dashoffset: 92;
  animation: draw 760ms var(--ease) 260ms both;
}
.mark .tip {
  fill: #ffffff;
  transform-origin: 70.6px 59.5px;
  animation: pop 320ms var(--ease-spring) 900ms both;
}

@keyframes tile { from { opacity: 0; transform: scale(0.86); } to { opacity: 1; transform: none; } }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes pop  { from { opacity: 0; transform: scale(0.2); } to { opacity: 1; transform: none; } }

/* Pointing at the mark redraws the rule, because that stroke is the product. */
.mark:hover .stroke { animation: draw 620ms var(--ease) both; }
.mark:hover .tip { animation: pop 280ms var(--ease-spring) 420ms both; }

/* ==========================================================================
   Masthead
   ========================================================================== */

.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-block: 14px;
  background: var(--color-surface);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

/*
 * The app's own glass, and it only costs anything once the bar is over
 * something. Composited unconditionally it repaints a blurred strip across the
 * viewport on every frame, which on a page carrying a twenty second animation
 * is frames taken from the thing the reader is actually watching. Measured
 * here: the demonstration ran at a quarter speed with the filter always on.
 */
.masthead[data-stuck='true'] {
  background: color-mix(in srgb, var(--color-surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}

/* The rule appears only once the page has moved, so a page at rest has no
   line across it and a page in use has a defined top edge. */
.masthead[data-stuck='true'] {
  border-bottom-color: var(--color-line);
  box-shadow: 0 1px 2px rgba(20, 18, 31, 0.03);
}

.masthead nav { display: flex; align-items: center; gap: 2px; }

.navlink {
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-muted);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.navlink:hover { color: var(--color-ink); background: var(--color-sunk); }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero { padding-block: clamp(46px, 7vw, 84px) clamp(26px, 3vw, 40px); }

.hero-grid {
  display: grid;
  gap: clamp(26px, 4vw, 54px);
  grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  align-items: center;
}

@media (max-width: 940px) { .hero-grid { grid-template-columns: 1fr; } }

.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }

/* ==========================================================================
   The demonstration
   ========================================================================== */

.demo {
  border-radius: var(--r-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

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

.demo-title { font-size: 12px; font-weight: 600; color: var(--color-muted); }

.state {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.live {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--color-ink);
  padding-right: 9px;
  border-right: 1px solid var(--color-line);
}

.state-dot {
  width: 7px; height: 7px;
  border-radius: var(--r-full);
  background: var(--color-faint);
  transition: background var(--t) var(--ease);
}
.demo[data-state='recording'] .state-dot { background: var(--color-brand); animation: livepulse 1.9s var(--ease) infinite; }
.demo[data-state='consolidating'] .state-dot { background: var(--color-flag); }
.demo[data-state='filed'] .state-dot { background: var(--color-good); }

@keyframes livepulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(0.7); opacity: 0.5; }
}

/* ---- the strip ----------------------------------------------------------- */

.timeline { padding: 15px 16px 12px; border-bottom: 1px solid var(--color-line-soft); user-select: none; }
.track-wrap { position: relative; }

.track {
  position: relative;
  height: 34px;
  border: 1px solid var(--color-line);
  border-radius: var(--r-sm);
  background: var(--color-sunk);
  cursor: pointer;
  overflow: hidden;
}

.heard {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(0);
  background: var(--color-brand-wash);
  border-right: 1px solid var(--color-brand-soft);
  /* scaleX, not width: this runs every frame for twenty seconds, and animating
     width makes the browser lay the strip out again each time. */
  transition: transform 90ms linear;
}

.playhead {
  position: absolute;
  top: -4px; bottom: -4px;
  left: 0;
  width: 2px;
  border-radius: var(--r-full);
  background: var(--color-brand);
  box-shadow: 0 0 0 2px var(--color-surface);
  transition: left 90ms linear;
  pointer-events: none;
}

.tick {
  position: absolute;
  top: 0; bottom: 0;
  width: 2px;
  background: var(--color-line);
  transform: translateX(-1px);
  transition: background var(--t) var(--ease), width var(--t) var(--ease);
}
.tick[data-landed='true'] { background: var(--color-brand-soft); width: 3px; }

.clock {
  display: flex;
  justify-content: space-between;
  margin-top: 7px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.25;
  color: var(--color-faint);
}

/* ---- the document -------------------------------------------------------- */

.sheet { padding: 18px clamp(16px, 3vw, 26px) 24px; min-height: 300px; }

.sheet-empty {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 24px 2px;
  color: var(--color-muted);
  font-size: 0.92rem;
}

/* A line pours in as the playhead reaches it. It never fades in as a block:
   the point being made is that these sentences were captured as they were said. */
.line {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: 14px;
  padding-block: 9px;
  animation: pour var(--t-slow) var(--ease) both;
}

@keyframes pour {
  from { opacity: 0; transform: translateY(8px); clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; transform: none;            clip-path: inset(0 0 0 0); }
}

.line + .line { border-top: 1px solid var(--color-line-soft); }

/* THE PRODUCT'S RULE, and the reason the page exists.
   Mono is what the lecturer said. It carries the moment it was said. */
.said {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.62;
  color: var(--color-ink);
}

/* Serif is what Lectavi wrote. It never carries a time, because nobody said it. */
.added {
  font-family: var(--font-serif);
  font-size: 1.02rem;
  line-height: 1.55;
  color: var(--color-muted);
  font-style: italic;
}

.stamp {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border: 1px solid var(--color-line);
  border-radius: var(--r-sm);
  background: var(--color-surface);
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--color-muted);
  cursor: pointer;
  transition:
    background var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform var(--t-fast) var(--ease);
}
.stamp:hover {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: #fff;
}
.stamp:active { transform: translateY(1px); }

/* The absence is drawn, not left blank, so a reader can SEE that this line has
   no moment behind it rather than infer it from a gap. */
.nostamp {
  justify-self: start;
  padding-top: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-faint);
}

.line[data-cited='true'] .said {
  background: var(--color-brand-wash);
  box-shadow: -6px 0 0 var(--color-brand-wash), 6px 0 0 var(--color-brand-wash);
  border-radius: var(--r-dot);
}

.demo-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 16px;
  border-top: 1px solid var(--color-line-soft);
  background: var(--color-raised);
  font-size: 0.82rem;
  color: var(--color-muted);
}

.ctl { padding: 9px 15px; font-size: 13px; font-weight: 600; }

/* ==========================================================================
   Comparison, routes, the term
   ========================================================================== */

.two-up {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.panel { padding: 20px; }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
  padding-bottom: 11px;
  border-bottom: 1px solid var(--color-line-soft);
}

.inset {
  border-radius: var(--r-md);
  background: var(--color-raised);
  border: 1px solid var(--color-line-soft);
  padding: 14px 16px;
}

.flat { font-size: 0.94rem; line-height: 1.62; color: var(--color-muted); }

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

.route { padding: 20px; }

.route-icon {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  margin-bottom: 13px;
  border-radius: var(--r-md);
  background: var(--color-brand-wash);
  color: var(--color-brand);
}

/* ---- the grade split, drawn the way the class page draws it -------------- */

.split { display: flex; height: 10px; gap: 2px; border-radius: var(--r-full); overflow: hidden; background: var(--color-sunk); }
.split span { display: block; height: 100%; }

.split-rows { display: flex; flex-direction: column; gap: 1px; margin-top: 14px; }
.split-row {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 7px 6px;
  margin-inline: -6px;
  border-radius: var(--r-sm);
  border-bottom: 1px solid var(--color-line-soft);
  font-size: 0.92rem;
  transition: background var(--t-fast) var(--ease);
}
.split-row:hover { background: var(--color-sunk); }
.split-row:last-child { border-bottom: 0; }
.split-dot { width: 8px; height: 8px; flex: none; border-radius: var(--r-full); transform: translateY(-1px); }
.split-name { flex: 1; min-width: 0; color: var(--color-muted); }
.split-pct { font-weight: 700; color: var(--color-ink); font-variant-numeric: tabular-nums; }

.dates { display: flex; flex-direction: column; gap: 1px; }
.date-row {
  display: flex;
  gap: 12px;
  padding: 8px 6px;
  margin-inline: -6px;
  border-radius: var(--r-sm);
  border-bottom: 1px solid var(--color-line-soft);
  font-size: 0.9rem;
  transition: background var(--t-fast) var(--ease);
}
.date-row:hover { background: var(--color-sunk); }
.date-row:last-child { border-bottom: 0; }
.date-when {
  flex: none; width: 82px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--color-faint);
}
.date-what { color: var(--color-muted); }
.date-exam .date-when { color: var(--color-brand); }

/* ---- the accuracy record ------------------------------------------------- */

.record { overflow-x: auto; overscroll-behavior-x: contain; }
.grid-table { width: 100%; min-width: 520px; border-collapse: collapse; font-size: 0.92rem; }
.grid-table th {
  text-align: left;
  padding: 12px 14px;
  border-bottom: 1px solid var(--color-line);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-faint);
}
.grid-table td { padding: 15px 14px; border-bottom: 1px solid var(--color-line-soft); color: var(--color-muted); }
.grid-table tr:last-child td { border-bottom: 0; }
.grid-table .figure { color: var(--color-ink); font-weight: 700; font-size: 1.1rem; }

/* ==========================================================================
   Plans. The biggest block on the page after the demonstration.
   ========================================================================== */

.plans {
  display: grid;
  gap: 18px;
  /*
   * Two cards, so a width cap rather than auto-fit across the whole page. At
   * 1120px two auto-fit columns would each be 550px, which is a pricing card
   * the size of a hero and reads as a page with something missing from it.
   */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  max-width: 720px;
  align-items: stretch;
}

/*
 * What it actually comes to, under the cards.
 *
 * The card says a rate, this says the amount that leaves the account, which
 * are different questions and both get asked. Same [hidden] swap as the price,
 * and the same reason for saying display:none explicitly.
 */
.plan-total {
  max-width: 62ch;
  margin: 18px 0 0;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--color-muted);
}
.plan-total strong { color: var(--color-ink); font-weight: 600; }
.plan-total[hidden] { display: none; }

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

/*
 * Monthly against yearly.
 *
 * A segmented control rather than a switch, because a switch has an off
 * position and neither of these is off. Built on buttons with aria-pressed so
 * it is operable and announced without any script at all: with JavaScript
 * disabled the monthly price simply stands, which is the honest default.
 */
.cycle {
  display: inline-flex;
  gap: 3px;
  margin-bottom: 26px;
  padding: 3px;
  border: 1px solid var(--color-line);
  border-radius: var(--r-full);
  background: var(--color-sunk);
}

.cycle-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 17px;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--color-muted);
  font: 600 0.875rem/1 var(--font-ui);
  letter-spacing: -0.01em;
  cursor: pointer;
  transition:
    background var(--t) var(--ease),
    color var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}

.cycle-tab:hover {
  color: var(--color-ink);
}

.cycle-tab:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--color-brand-wash);
}

.cycle-tab[aria-pressed='true'] {
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: var(--shadow-sm);
}

/* The saving, said in money rather than as a percentage. Nobody should have
   to work out what 50 percent of a year of twenty dollars is. */
.cycle-save {
  padding: 2px 8px;
  border-radius: var(--r-full);
  background: var(--color-good-wash);
  color: var(--color-good-deep);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
}

/*
 * The price swaps rather than flickers.
 *
 * Both prices are in the markup and one carries [hidden], so the swap is a
 * class change rather than a reflow, and the entrance can be animated. Short
 * and precise: .2s, the same register as everything else that enters on this
 * page, rather than a slow fade that draws attention to the mechanism.
 */
@media (prefers-reduced-motion: no-preference) {
  .price[data-when] {
    animation: price-in var(--t-in) var(--ease-in) both;
  }
  @keyframes price-in {
    from {
      opacity: 0;
      transform: translateY(4px);
    }
  }
}

/* The recommended plan is lifted rather than outlined, the same way the app
   lifts the card you are pointing at. */
.plan-lead {
  background:
    linear-gradient(180deg, var(--color-brand-wash), var(--color-surface) 62%);
  border-color: var(--color-brand-soft);
  box-shadow: var(--shadow-md);
}

.plan-flag {
  position: absolute;
  top: -11px;
  left: 26px;
  padding: 4px 11px;
  border-radius: var(--r-full);
  background: var(--color-brand);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  box-shadow: 0 4px 12px -4px rgba(108, 77, 246, 0.7);
}

.plan-name { font-size: 15px; font-weight: 700; letter-spacing: -0.02em; }

.price {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: clamp(2.1rem, 3.4vw, 2.9rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--color-ink);
}
.price .unit { font-size: 0.85rem; font-weight: 500; letter-spacing: -0.01em; color: var(--color-muted); }

/*
 * display:flex above beats the browser's own [hidden] { display: none }, so
 * without this both prices render at once and the card advertises two numbers.
 * Any rule that sets display has to say this for itself.
 */
.price[hidden] { display: none; }

.plan-list { display: flex; flex-direction: column; gap: 9px; margin: 4px 0 0; padding: 0; list-style: none; }
.plan-list li { display: flex; gap: 9px; font-size: 0.9rem; line-height: 1.5; color: var(--color-muted); }
.plan-list svg { flex: none; margin-top: 3px; color: var(--color-good); }

.plan .btn { margin-top: auto; justify-content: center; }

/* ==========================================================================
   Questions, footer
   ========================================================================== */

.qa { border-top: 1px solid var(--color-line-soft); }
.qa details { border-bottom: 1px solid var(--color-line-soft); }
.qa summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 4px;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -0.015em;
  transition: color var(--t-fast) var(--ease);
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary:hover { color: var(--color-brand); }
.qa summary svg { flex: none; color: var(--color-faint); transition: transform var(--t) var(--ease), color var(--t-fast) var(--ease); }
.qa details[open] summary svg { transform: rotate(90deg); color: var(--color-brand); }
.qa-body { padding: 0 4px 20px; color: var(--color-muted); max-width: 70ch; font-size: 0.95rem; }

.closer {
  padding: clamp(34px, 5vw, 60px);
  text-align: center;
  border-radius: var(--r-lg);
  background: linear-gradient(165deg, var(--color-brand-wash), var(--color-surface) 70%);
  border: 1px solid var(--color-brand-soft);
  box-shadow: var(--shadow-md);
}

footer { border-top: 1px solid var(--color-line-soft); padding-block: 44px 56px; }
.foot-grid { display: flex; flex-wrap: wrap; gap: 30px 56px; justify-content: space-between; }
.foot-links { display: flex; flex-direction: column; gap: 9px; }
.foot-links a { font-size: 0.9rem; color: var(--color-muted); text-decoration: none; transition: color var(--t-fast) var(--ease); }
.foot-links a:hover { color: var(--color-ink); }
.foot-head { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-faint); margin-bottom: 4px; }

/* ==========================================================================
   Arrival

   Short and precise rather than slow and floaty. These ran at 420ms, which is
   long enough that somebody scrolling at a normal pace watches the page catch
   up with them, and the motion becomes the thing they notice instead of the
   content. A quarter of a second is enough to say "this arrived" and short
   enough to be over before it is looked at.

   The easing is a decelerating curve with no overshoot: content settling into
   place, not bouncing into it. Overshoot is for a control responding to a
   press, where it reads as the thing being springy. A paragraph is not springy.
   ========================================================================== */

/* Entrances only, kept separate from --ease so changing the feel of one does
   not change the feel of every hover on the page. */
:root { --ease-in: cubic-bezier(0.22, 0.68, 0.35, 1); --t-in: 260ms; }

.rise {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--t-in) var(--ease-in), transform var(--t-in) var(--ease-in);
}
.rise[data-seen='true'] { opacity: 1; transform: none; }

/* A group arrives in reading order rather than all at once. The step is small
   on purpose: enough to read as a sequence, not enough to wait through. */
.stagger > * { opacity: 0; transform: translateY(9px); }
.stagger[data-seen='true'] > * {
  opacity: 1;
  transform: none;
  transition: opacity var(--t-in) var(--ease-in), transform var(--t-in) var(--ease-in);
}
.stagger[data-seen='true'] > *:nth-child(2) { transition-delay: 45ms; }
.stagger[data-seen='true'] > *:nth-child(3) { transition-delay: 90ms; }
.stagger[data-seen='true'] > *:nth-child(4) { transition-delay: 135ms; }

.skip {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 90;
  padding: 11px 16px;
  border-radius: var(--r-md);
  background: var(--color-brand);
  color: #fff;
  font: 600 13px/1 var(--font-ui);
  text-decoration: none;
  box-shadow: var(--shadow-md);
  transform: translateY(-180%);
  transition: transform var(--t) var(--ease);
}
.skip:focus-visible { transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .rise, .stagger > * { opacity: 1; transform: none; }
  .mark .stroke { stroke-dashoffset: 0; }
}

@media (max-width: 640px) {
  .line { grid-template-columns: 1fr; gap: 6px; }
  .masthead nav { display: none; }
  .plan { padding: 26px 22px 28px; }
}

/* The large mark holds its three beats until it is on screen. A logo that has
   already finished performing by the time the reader arrives has not performed. */
.mark-lg .tile,
.mark-lg .stroke,
.mark-lg .tip { animation-play-state: paused; }
.mark-lg[data-seen='true'] .tile,
.mark-lg[data-seen='true'] .stroke,
.mark-lg[data-seen='true'] .tip { animation-play-state: running; }
