/* Kvanta PWA
 *
 * Mobile-first and app-shaped, not page-shaped: fixed viewport, no document
 * scroll, one screen visible at a time. The feed is the only scroller.
 */

/* Dark-first, per the design brief and the CEO call of 2026-08-20.
 *
 * The OS preference deliberately does NOT drive this. Chrome and Safari never
 * report "no preference" - they answer light or dark, and light is what a
 * stock phone says - so keying the palette off prefers-color-scheme would have
 * left most readers on light no matter which way round the rules were written.
 * Dark is simply the default, and light is an explicit choice made in Settings
 * and remembered in localStorage.
 *
 * The attribute lives on <html> and is set by an inline script in the head
 * before first paint, so a reader who chose light does not get a dark flash on
 * every launch.
 */
:root {
  --ink: #ffffff;
  --ink-soft: #a0a0a0;
  --paper: #000000;
  --paper-2: #000000;
  --line: #ffffff;
  --accent: #ffffff;
  --radius: 0;
  --pad: 22px;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --kai-rim: #ffffff;
}

:root[data-theme="light"] {
  --ink: #000000;
  --ink-soft: #5e5e5e;
  --paper: #ffffff;
  --paper-2: #ffffff;
  --line: #000000;
  --accent: #000000;
  --kai-rim: transparent;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--paper);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

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

.screen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--paper);
}
.screen[hidden] { display: none; }

/* ------------------------------- brand ------------------------------- */

.logo {
  font-size: 21px;
  font-weight: 620;
  letter-spacing: -0.02em;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.logo.small { font-size: 16px; }
.chevron {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  opacity: 0.45;
  font-weight: 700;
}

/* ------------------------------- gate -------------------------------- */

.gate-inner {
  margin: auto;
  width: 100%;
  max-width: 420px;
  padding: calc(var(--pad) + var(--safe-t)) var(--pad) calc(var(--pad) + var(--safe-b));
  text-align: left;
}

.gate-title {
  font-size: clamp(28px, 8vw, 36px);
  line-height: 1.12;
  letter-spacing: -0.03em;
  font-weight: 640;
  margin: 26px 0 12px;
}

.gate-sub {
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0 0 28px;
}

.gate-form { display: flex; flex-direction: column; gap: 10px; }

/* Targeted by form, not by input type or id. The code field is type="text"
   and the code button is a different id, so type/id selectors silently left
   the entire code screen unstyled - a browser-default grey button and a
   borderless box. */
.gate-form input {
  width: 100%;
  font: inherit;
  font-size: 16px; /* 16px or iOS zooms the viewport on focus */
  padding: 15px 16px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--paper-2);
  color: var(--ink);
}
.gate-form input:focus {
  outline: none;
  border-color: var(--accent);
}

button {
  font: inherit;
  cursor: pointer;
}

.gate-form button[type="submit"] {
  font-size: 16px;
  font-weight: 560;
  padding: 15px 16px;
  border: 0;
  border-radius: 14px;
  background: var(--accent);
  color: var(--paper);
}
.gate-form button[type="submit"]:disabled { opacity: 0.55; }

.gate-error {
  margin: 2px 0 0;
  font-size: 14px;
  color: #c0392b;
}

.gate-legal {
  margin: 18px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: inherit;
}

.sent-mark { color: var(--ink); margin-bottom: 4px; }
.sent-mark .icon { width: 34px; height: 34px; stroke-width: 1.4; }

/* Wide tracking and a monospace face so six digits read as six discrete
   characters, which is what makes a mistyped one obvious at a glance. */
.code-input {
  font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
  font-size: 30px;
  letter-spacing: 10px;
  text-align: center;
  font-weight: 600;
  padding-left: 10px; /* offsets the trailing letter-space so it looks centred */
}
.code-input::placeholder {
  color: var(--line);
  letter-spacing: 10px;
}


/* ================================ icons ================================ */

/* One stroke weight, one size scale, always currentColor. Unicode glyphs were
   used first and the platform substituted colour-emoji for several of them,
   which put tinted icons into a strictly monochrome UI. */
.icon {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon-filled { fill: currentColor; stroke: none; }

.icon-btn {
  background: none;
  border: 0;
  padding: 6px;
  margin: -6px;           /* keeps the 44px hit area without shifting the glyph */
  color: var(--ink-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}
.icon-btn:active { color: var(--ink); }

/* ------------------------------- feed -------------------------------- */

.feed-screen { background: var(--paper); }

.feed-bar {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(12px + var(--safe-t)) var(--pad) 12px;
  pointer-events: none;
}
.feed-bar > * { pointer-events: auto; }
.feed-bar .linkish { font-size: 13px; color: var(--ink-soft); }

.feed {
  flex: 1;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}
.feed::-webkit-scrollbar { display: none; }

.card {
  position: relative;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(64px + var(--safe-t)) var(--pad) calc(60px + var(--safe-b));
  max-width: 560px;
  margin: 0 auto;
}

.card-kicker {
  font-size: 12px;
  font-weight: 620;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 16px;
}

.card h2 {
  font-size: clamp(24px, 6.4vw, 31px);
  line-height: 1.18;
  letter-spacing: -0.025em;
  font-weight: 640;
  margin: 0 0 20px;
}

.card ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.card li {
  font-size: 17px;
  line-height: 1.48;
  padding-left: 18px;
  position: relative;
  color: var(--ink);
}
.card li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink);
  opacity: 0.34;
}

.card .source {
  margin-top: 26px;
  font-size: 14px;
}
.card .source a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.card .missing {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-soft);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
}

.big-num {
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 10px;
}

.hint {
  position: absolute;
  left: var(--pad);
  bottom: calc(38px + var(--safe-b));
  margin-top: 0;
  font-size: 13px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 8px;
}
.hint .arrow {
  width: 16px;
  height: 16px;
  animation: nudge 1.9s ease-in-out infinite;
}
@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50%      { transform: translateY(4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hint .arrow { animation: none; }
  .feed { scroll-behavior: auto; }
}

.install-btn {
  margin-top: 22px;
  align-self: flex-start;
  font-size: 15px;
  font-weight: 560;
  padding: 13px 22px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: var(--paper);
}

.install-steps {
  margin-top: 18px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
}

/* --------------------------- notifications --------------------------- */

.notify-wrap {
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
/* Collapse the rule entirely when there is nothing to ask - on iOS before
   install, or where push is unsupported - so the end card does not end on a
   stray divider. */
.notify-wrap:empty {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.notify-copy {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
}

.notify-row {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 4px;
}

/* The install button carries its own top margin for the case where it is the
   only thing on the card; inside a row that spacing is the row's job. */
.notify-row .install-btn { margin-top: 14px; }

.install-btn.ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
}

.install-btn[disabled] { opacity: .55; }

.notify-row .linkish {
  font-size: 14px;
  color: var(--ink-soft);
}

.notify-msg {
  margin-top: 14px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink);
}

/* --------------------------- progress rail --------------------------- */

.progress {
  position: absolute;
  right: 9px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Dots, not dashes. A column of 3x14 bars at the right edge is the exact
   shape of a scrollbar, so that is what it read as - a broken one, since it
   never moved. Round dots read as page indicators, and the active one grows
   into a capsule rather than just brightening. */
.progress span {
  width: 4px;
  height: 4px;
  border-radius: 999px;
  background: var(--ink);
  opacity: 0.18;
  transition: opacity .25s ease, height .25s ease;
}
.progress span.on {
  opacity: 0.55;
  height: 13px;
}

/* ======================= transition into the app ======================= */

/* The read opens with no chrome at all, so the move into the app shell is the
   moment the product stops looking like a newsletter. Opacity rather than a
   slide: the feed is a vertical pager, and sliding would read as one more
   card rather than a change of place. */
.feed-screen.fading-out {
  opacity: 0;
  transition: opacity .25s ease;
  pointer-events: none;
}
.shell.fading-in {
  animation: shell-in .3s ease both;
}
@keyframes shell-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .feed-screen.fading-out { transition: none; }
  .shell.fading-in { animation: none; }
}

/* ============================== app shell ============================== */

.shell {
  display: flex;
  flex-direction: column;
}

.shell-bar {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: calc(var(--safe-t) + 16px) var(--pad) 12px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.shell-title {
  font-size: 13px;
  color: var(--ink-soft);
  letter-spacing: .02em;
}

/* The only scroller in the shell. The bar and tabbar are pinned so the app
   never scrolls as a document, which is most of what separates "app" from
   "web page" on a phone. */
.shell-body {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
/* A visible scrollbar is the single clearest "this is a web page" tell on a
   phone-shaped surface. */
.shell-body::-webkit-scrollbar { display: none; }

.tab-view {
  padding: 22px var(--pad) 28px;
}
.tab-view[hidden] { display: none; }

.view-h {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-soft);
  margin: 26px 0 12px;
}
.view-h:first-child { margin-top: 0; }

.view-p {
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0 0 18px;
}
.view-mono {
  font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
  font-size: 14px;
  color: var(--ink);
  margin: 0 0 8px;
  word-break: break-all;
}

/* -------------------------------- rows -------------------------------- */

.row {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 16px 2px;
  color: var(--ink);
  font: inherit;
  min-height: 44px; /* touch target floor */
}
.row:last-child { border-bottom: 0; }
.row:active { background: var(--paper-2); }

.row-main { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-width: 0; }
.row-title {
  font-size: 15px;
  font-weight: 550;
  line-height: 1.4;
}
.row-sub {
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.45;
  /* Two lines then clip: guide summaries vary wildly in length and a ragged
     list is harder to scan than a slightly truncated one. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.row-chev { width: 18px; height: 18px; color: var(--ink-soft); opacity: .55; }

.signout-link { margin-top: 30px; display: inline-block; font-size: 14px; }
.settings-notify { margin-top: 0; padding-top: 0; border-top: 0; }

/* ------------------------------- tab bar ------------------------------- */

.tabbar {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line);
  padding-bottom: var(--safe-b);
  background: var(--paper);
}
.tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 10px 4px 8px;
  background: none;
  border: 0;
  color: var(--ink-soft);
  font: inherit;
  min-height: 52px;
}
.tab-icon { width: 21px; height: 21px; stroke-width: 1.5; }
/* The active tab thickens rather than changing colour: the palette is
   monochrome, so weight is the only honest way to show selection. */
.tab[aria-current="true"] .tab-icon { stroke-width: 1.9; }
.tab-label { font-size: 11px; letter-spacing: .02em; }
.tab[aria-current="true"] { color: var(--ink); }
.tab[aria-current="true"] .tab-label { font-weight: 600; }

.explore-btn {
  margin-top: 20px;
  background: transparent;
  color: var(--ink);
  border: 1.5px solid var(--ink);
}

/* ============================ focus states ============================ */

/* Keyboard focus was invisible everywhere: buttons carry no default ring once
   they are restyled, and the feed is a tabbable element. :focus-visible keeps
   it off during touch and mouse use, where a persistent ring just looks like
   a rendering fault. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 6px;
}
.gate-form input:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}
.feed:focus { outline: none; }
.feed:focus-visible { outline: none; }

/* Pressed feedback on the two button shapes, so a tap acknowledges itself on
   a phone where there is no hover to rely on. */
.install-btn:active { opacity: .82; }
.tab:active .tab-icon { opacity: .6; }

/* ================================ plan ================================ */

.premium-tag {
  margin-left: 10px;
  padding: 2px 7px;
  border: 1px solid currentColor;
  border-radius: 4px;
  font-size: 10px;
  letter-spacing: .09em;
  /* Outline, not a filled badge. The palette has no accent colour to spend on
     a status pill, and a solid block here would out-shout the headline. */
  opacity: .75;
}

.plan-wrap { margin-bottom: 4px; }

.plan-now {
  font-size: 22px;
  font-weight: 640;
  letter-spacing: -0.02em;
  margin: 0 0 6px;
}

.plan-btn {
  display: block;
  width: 100%;
  margin-top: 12px;
  align-self: stretch;
  text-align: center;
}

.plan-msg {
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink);
}

.plan-legal {
  margin-top: 16px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ---------------------------- appearance ---------------------------- */

.theme-row {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}
.theme-opt {
  flex: 1 1 0;
  padding: 12px 10px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: transparent;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 550;
  min-height: 44px;
}
/* Selection is shown by border and ink weight, not a fill, so the control
   stays legible in both palettes without an accent colour to lean on. */
.theme-opt[aria-pressed="true"] {
  border-color: var(--ink);
  color: var(--ink);
}

/* --------------------------- app disclaimer --------------------------- */

/* Quiet but readable. A disclaimer set small enough to be unreadable is not a
   disclaimer, so this stays at 12px on --ink-soft rather than shrinking into
   the background. */
.card-legal {
  margin: 22px 0 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 34em;
}

.gate-legal.fca {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* ================================= Kai ================================= */

/* Pixel sprite, 46x32 cells. Sizes stay whole multiples of the cell (1x 46px,
   2x 92px) so every sprite pixel lands on whole screen pixels and stays sharp.
   Face and patches never invert; the rim only shows in dark mode. */
.kai {
  width: 92px;
  height: 64px;
  display: block;
  color: var(--ink);
  image-rendering: pixelated;
}
.kai .kw { fill: #ffffff; }
.kai .ki { fill: #000000; }
.kai .kp { fill: currentColor; }
.kai .kr { fill: var(--kai-rim); }

.kai-block { margin: 4px 0 0; }
.kai-title {
  margin: 18px 0 6px;
  font-size: 19px;
  font-weight: 620;
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.kai-body {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 30em;
}

/* In a tab view he is a smaller aside, not the headline. */
.tab-view .kai { width: 92px; height: 64px; }
.tab-view .kai-title { font-size: 17px; margin-top: 14px; }

/* =============================== Ask Kai =============================== */

.ask-intro {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-bottom: 20px;
}
.ask-intro .kai-title { margin-top: 0; }
.kai.ask-kai-big { width: 92px; height: 64px; flex: 0 0 auto; }
.kai.ask-kai { width: 46px; height: 32px; flex: 0 0 auto; }

.ask-form { display: flex; gap: 10px; align-items: stretch; }
.ask-input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 16px; /* 16px or iOS zooms the viewport on focus */
  padding: 13px 15px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--paper-2);
  color: var(--ink);
}
.ask-input:focus { outline: none; border-color: var(--accent); }
.ask-btn { margin-top: 0; align-self: stretch; padding: 13px 20px; }

.ask-results:empty { display: none; }

.ask-answer {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin: 24px 0 4px;
}
.ask-answer-body { flex: 1 1 auto; min-width: 0; }

/* The matched question, always shown above the answer. Many stored answers
   begin "No." or "Yes." and are incoherent without it. */
.ask-q {
  margin: 0 0 8px;
  font-size: 16px;
  font-weight: 620;
  line-height: 1.35;
  letter-spacing: -0.01em;
}
.ask-a {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink-soft);
}
.ask-src { margin: 12px 0 0; font-size: 13px; }
/* A calculation's working: one step per line, figures aligned by reading order. */
.ask-breakdown {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  border-top: 1px solid var(--line, rgba(127,127,127,.25));
}
.ask-breakdown li {
  padding: 9px 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  border-bottom: 1px solid var(--line, rgba(127,127,127,.25));
  font-variant-numeric: tabular-nums;
}
.ask-src a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.ask-examples { margin-top: 30px; }
.ask-example {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 8px;
  color: var(--ink-soft);
  font: inherit;
  font-size: 14px;
  min-height: 44px;
}
.ask-example:active { background: var(--paper-2); color: var(--ink); }

/* Five tabs is tighter than four; let the labels shrink rather than wrap. */
.tabbar { grid-template-columns: repeat(5, 1fr); }
.tab-label { font-size: 10.5px; }

/* ---------------------- Kai on the end card ---------------------- */

/* Kai used to be reachable only three taps deep behind the "..." menu, which
   is the same as not shipping him. This is the one screen every reader gets
   to, and the moment a question is most likely to have occurred to them. */
.end-ask {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  margin-top: 22px;
  padding: 12px 14px;
  background: none;
  border: 1px solid var(--line);
  border-radius: 14px;
  color: var(--ink);
  font: inherit;
  min-height: 44px;
}
.end-ask:active { background: var(--paper-2); }
.kai.end-ask-kai { width: 46px; height: 32px; flex: 0 0 auto; }
.end-ask-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.end-ask-title { font-size: 15px; font-weight: 600; }
.end-ask-sub { font-size: 13px; color: var(--ink-soft); }

/* ============================= G8 SKIN (Oct 2026) ============================= */

/* The app in the G8 look (admin-previews/g8-app-screens.html): Bricolage
   Grotesque for type, DM Mono for small labels, soft grey rules, pill buttons
   and fields, and selection shown by weight rather than by inverting. Replaces
   the Terminal Pure skin of Sept 2026 as one section, so it can be reviewed or
   removed as a unit; the backup from before it is /home/opc/backups/g8-app-*.
   Dark stays the default (CEO call 2026-08-20); light is chosen under You. */
:root {
  --ink: #ffffff;
  --ink-soft: #a0a0a0;
  --paper: #000000;
  --paper-2: #161616;
  --line: #2a2a2a;
  --accent: #ffffff;
  --ink-hover: #d9d9d9;
  --sans: "Bricolage Grotesque", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --ease-out: cubic-bezier(.22, 1, .36, 1);
}
:root[data-theme="light"] {
  --ink: #000000;
  --ink-soft: #505050;
  --paper: #ffffff;
  --paper-2: #efefef;
  --line: #d8d8d8;
  --accent: #000000;
  --ink-hover: #262626;
}
html, body { font-family: var(--sans); }

/* Brand mark: bold sans with the prompt chevron in mono. */
.logo { font-family: var(--sans); font-weight: 800; letter-spacing: -0.02em; gap: 6px; }
.logo.small { font-size: 18px; }
.chevron { font-family: var(--mono); font-weight: 500; opacity: 1; color: var(--ink-soft); }

/* Headings: heavy, tight. */
.gate-title, .card h2, .kai-title, .plan-now {
  font-family: var(--sans);
  font-weight: 800;
  letter-spacing: -0.03em;
}
.card h2 { line-height: 1.08; }
.card li, .ask-a { font-family: var(--sans); }
.ask-a { color: var(--ink); }

/* Small labels: mono, uppercase, quiet. */
.view-h, .card-kicker, .shell-title {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.shell-title { text-transform: none; letter-spacing: .02em; }

/* Bars: a slim header with a soft rule. */
.shell-bar { align-items: center; min-height: 56px; padding-top: calc(var(--safe-t) + 6px); padding-bottom: 6px; }

/* Fields and buttons are pills. */
.gate-form input, .ask-input {
  min-height: 52px;
  padding: 0 20px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  font-family: var(--sans);
}
.gate-form input:focus, .ask-input:focus { border-color: var(--ink); }
.code-input { font-family: var(--mono); }
.code-input::placeholder { color: var(--ink-soft); }

.gate-form button[type="submit"], .install-btn {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 700;
  min-height: 52px;
  padding: 0 24px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  transition: background-color .18s var(--ease-out), transform .18s var(--ease-out);
}
.gate-form button[type="submit"]:active, .install-btn:active { transform: scale(0.98); opacity: 1; background: var(--ink-hover); }
.install-btn.ghost, .explore-btn {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}
.install-btn.ghost:active, .explore-btn:active { background: var(--paper-2); color: var(--ink); }

.gate-error { color: var(--ink); font-weight: 700; }

/* Story bullets: small round marks. */
.card li { padding-left: 18px; }
.card li::before { opacity: .5; }
.card .missing, .install-steps { background: var(--paper-2); border: 0; border-radius: 20px; }

.progress span { opacity: .25; }
.progress span.on { opacity: 1; }

/* Rows: plain, divided by soft rules; a press shows the surface tint. */
.row { padding: 14px 2px; min-height: 56px; }
.row:active, .ask-example:active, .end-ask:active { background: var(--paper-2); color: var(--ink); }
.row-title { font-size: 16px; font-weight: 600; }
.row-sub { font-size: 13px; }
.row-chev { opacity: .7; }

/* Tab bar: the active tab is shown by ink and weight; icons lift a little. */
.tabbar { border-top: 1px solid var(--line); }
.tab { min-height: 56px; }
.tab[aria-current="true"] { background: none; color: var(--ink); }
.tab[aria-current="true"] .tab-label { font-weight: 700; }
.tab-label { font-family: var(--sans); font-size: 12px; letter-spacing: 0; }
.tab-icon, .tab-label { transform-origin: 50% 50%; transition: transform 420ms cubic-bezier(.34, 1.45, .64, 1); }
@media (hover: hover) { .tab:hover .tab-icon { transform: translateY(-2px) scale(1.06); } }
.tab:active .tab-icon, .tab:active .tab-label { transform: scale(.92); transition-duration: 90ms; opacity: 1; }

/* Appearance: three pills; the chosen one is filled. */
.theme-opt {
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 600;
  min-height: 48px;
}
.theme-opt[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.premium-tag { opacity: 1; border-radius: 999px; font-family: var(--mono); }

/* Ask Kai: the website page's layout. A big title, a pill field over a full
   width pill button, and the examples as ruled rows with an arrow. */
.tab-view .ask-intro .kai-title, .ask-intro .kai-title { font-size: clamp(30px, 9vw, 40px); line-height: 1.02; margin: 0 0 8px; }
.ask-intro .kai-body { font-size: 16px; line-height: 1.55; }
.ask-form { flex-direction: column; gap: 12px; }
.ask-btn { width: 100%; padding: 0 24px; }
.ask-examples { margin-top: 28px; border-top: 1px solid var(--line); }
.ask-example {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  margin: 0;
  padding: 12px 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
}
.ask-example::after { content: "\2192"; flex: 0 0 auto; color: var(--ink); }
.ask-q { font-weight: 700; }
.end-ask { border: 1px solid var(--line); border-radius: 20px; }
.end-ask-title { font-weight: 700; }

/* Focus ring follows the pill shapes, on pill controls only. Never on a
   scroller: a radius on the focused feed clipped its corners (and the swipe
   hint with them). */
.gate-form input:focus-visible, .gate-form button:focus-visible, .ask-input:focus-visible,
.install-btn:focus-visible, .explore-btn:focus-visible, .theme-opt:focus-visible { border-radius: 999px; }

@media (prefers-reduced-motion: reduce) {
  .tab-icon, .tab-label, .tab:hover .tab-icon, .tab:active .tab-icon, .tab:active .tab-label { transform: none !important; transition: none !important; }
  .gate-form button[type="submit"]:active, .install-btn:active { transform: none; }
}

/* ================================= Prep ================================= */

/* Past reads has no tab of its own once Prep takes Archive's place. */
.archive-back { display: inline-block; margin: 0 0 14px; font-size: 14px; }
.past-reads { margin-top: 28px; }
.row[disabled] { opacity: .55; }

/* Full-screen host for a running test or recording: no tab bar, and it scrolls
   itself because the app never scrolls as a document. */
.prep-screen {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: none;
  padding: var(--safe-t) 0 var(--safe-b);
}
.prep-screen::-webkit-scrollbar { display: none; }
.prep-screen .prep-mount { flex: 0 0 auto; padding: 16px var(--pad) 28px; }

.prep-data .view-p { margin-top: 0; }
.prep-remove { margin-top: 6px; }
.prep-msg { margin-top: 12px; }
.optin-wrap { margin-top: 18px; }
.signout-note { margin-top: 30px; margin-bottom: 0; }
.signout-note + .signout-link { margin-top: 12px; }

/* Prep update prompt and build id */
.prep-update { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; padding: 10px 12px; border: 1px solid currentColor; }
.prep-update-text { font-size: 14px; line-height: 1.35; }
.prep-update-btn { flex: none; min-height: 44px; min-width: 96px; padding: 0 14px; border: 1px solid currentColor; background: transparent; color: inherit; font: inherit; font-weight: 600; cursor: pointer; }
.prep-update-btn[disabled] { opacity: .55; }
.prep-build { margin: 18px 0 8px; font-family: ui-monospace, "JetBrains Mono", monospace; font-size: 11px; opacity: .6; word-break: break-all; }

/* ------------------------- G8 sign-in override ----------------------------
 * Scoped to the gate and code screens only. Black-and-white G8 type and pill
 * controls. Colours come from the existing tokens, so dark-first and light
 * themes keep working. Change this block, not the rules above it.
 */
#gate .gate-title,
#sent .gate-title {
  font-family: 'Bricolage Grotesque', system-ui, -apple-system, sans-serif;
  font-weight: 800;
  font-size: clamp(30px, 9vw, 40px);
  line-height: 1.04;
  letter-spacing: -0.035em;
}

#gate .gate-sub,
#sent .gate-sub {
  font-family: 'Bricolage Grotesque', system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.55;
}

#gate .gate-form input,
#sent .gate-form input {
  min-height: 52px;
  padding: 0 20px;
  border-radius: 999px;
  border-width: 1px;
}

#gate .gate-form button[type="submit"],
#sent .gate-form button[type="submit"] {
  min-height: 52px;
  padding: 0 28px;
  border-radius: 999px;
  font-family: 'Bricolage Grotesque', system-ui, -apple-system, sans-serif;
  font-size: 16px;
  font-weight: 700;
  transition: background-color .18s cubic-bezier(.22, 1, .36, 1), transform .18s cubic-bezier(.22, 1, .36, 1);
}
#gate .gate-form button[type="submit"]:active,
#sent .gate-form button[type="submit"]:active {
  transform: scale(0.98);
}

#sent .code-input {
  font-family: 'DM Mono', ui-monospace, Menlo, monospace;
  font-size: 24px;
  letter-spacing: 0.4em;
  text-align: center;
  padding-left: 0.4em;
}

#gate .gate-legal,
#sent .gate-legal {
  font-size: 14px;
  line-height: 1.6;
}

@media (prefers-reduced-motion: reduce) {
  #gate .gate-form button[type="submit"]:active,
  #sent .gate-form button[type="submit"]:active { transform: none; }
}
