/* Ioskeley Mono: an Iosevka configuration tuned to match Berkeley Mono TX-02.
   SIL OFL 1.1, so it is free to publish and free to self-host, unlike TX-02
   itself.

   Every face here is self-hosted and nothing is fetched from a CDN, so the
   site renders with no third party request at all. That is the same claim the
   firmware makes about the network, and a page that phones out to a font host
   while advertising an airgapped signer would undercut it.

   IBM Plex Mono is the fallback face, also SIL OFL 1.1, also local. Both are
   listed in THIRD_PARTY_NOTICES.md. */
@font-face {
  font-family: "Ioskeley Mono";
  src: url("fonts/IoskeleyMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Ioskeley Mono";
  src: url("fonts/IoskeleyMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Ioskeley Mono";
  src: url("fonts/IoskeleyMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* The fallback face, local rather than from Google Fonts. It covers the three
   weights the page asks for, so a slow or blocked Ioskeley never lands the
   layout on a system monospace of a different width. */
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}


:root {
  color-scheme: dark;

  /* Reconciled with main/kiss_theme.h, every value here is a WT_* token.
     Do not add colours that the firmware does not have. */
  --bg: #070a10;        /* WT_BG   */
  --ink: #e8eef7;       /* WT_INK  */
  --muted: #a7b2c4;
  --dim: #7a869c;       /* WT_MUT  */
  --green: #35d07f;     /* WT_OK   */
  --amber: #f2b84b;     /* WT_WARN */
  --red: #ff4d5e;       /* WT_STOP */

  /* surfaces */
  --panel: #0b0e14;
  --panel-2: #0a0e15;
  --line: #1e2531;
  --line-soft: #1a2130;
  --control: #2a3346;
  --disabled: #4c5666;
  --key: #10141d;       /* WT_KEY: the menu/tab key surface on the device */

  /* The device's accent set, straight from ACC_HEX / ACC_BG_HEX in
     main/kiss_theme.c. MONO is a cool steel, deliberately NOT the ink. The
     four here are the four on the device, in the device's order. */
  --accent: #9fb6d4;
  --accent-bg: #232e42;

  --max: 1180px;
  /* One typeface for the whole site, no sans anywhere. Ioskeley Mono is the
     Berkeley Mono match; IBM Plex Mono covers the gap before the files land.

     A fixed pitch sets roughly a third wider than a proportional face at the
     same size, so a line of it holds fewer words and a paragraph of it tires
     the reader sooner. The answer is not a second face, it is a shorter line:
     the docs cap their measure near 62 characters and lead at 1.75. */
  --mono: "Ioskeley Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
}

:root[data-accent="green"] {
  --accent: #35d07f;
  --accent-bg: #102417;
}

:root[data-accent="pink"] {
  --accent: #e85ab8;
  --accent-bg: #261724;
}

:root[data-accent="orange"] {
  --accent: #ff8a3d;
  --accent-bg: #2b190d;
}

/* The repo, as the mark people already recognise rather than a word in the
   tab row. It sits with the accent picker: both are tools about the site, not
   places in it. */
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid transparent;
  border-bottom: 1px solid transparent;
  border-radius: 9px;
  color: var(--dim);
  transition: color 170ms ease, border-color 170ms ease, background 170ms ease;
}

.icon-link svg {
  width: 17px;
  height: 17px;
  fill: currentColor;
}

.icon-link:hover {
  color: var(--ink);
  border-color: var(--line);
  background: var(--key);
}

/* The accent picker, sitting where the device puts its theme tab. */
.theme-pick {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-left: 12px;
  border-left: 1px solid var(--line);
}

.theme-pick .swatch {
  width: 17px;
  height: 17px;
  padding: 0;
  border: 1px solid var(--control);
  border-radius: 50%;
  background: var(--sw);
  cursor: pointer;
}

.theme-pick .swatch[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--sw);
}

* {
  box-sizing: border-box;
}

/* Never let the browser fake a weight or a slant. If a cut is missing the page
   should show that honestly rather than smearing the stems of a squared mono. */
* {
  font-synthesis-weight: none;
  font-synthesis: none;
}

html {
  scroll-behavior: smooth;
  /* The whole type scale is in rem, so the root size sets it. 125% = 20px,
     lifting the nav, the eyebrow labels and the fine print well off the
     cramped 10-12px they sat at when this keyed off the browser default. */
  font-size: 125%;
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
  /* The signer's own backdrop, not a neon tech grid: two near-invisible ink
     rules on a 40px pitch, the same restrained field the wallet screens use. */
  background:
    linear-gradient(rgba(232, 238, 247, 0.021) 1px, transparent 1px),
    linear-gradient(90deg, rgba(232, 238, 247, 0.021) 1px, transparent 1px),
    var(--bg);
  background-size: 40px 40px;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

button,
input {
  font: inherit;
}

a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--control);
  padding-bottom: 2px;
  transition: border-color 170ms ease, color 170ms ease;
}

a:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  padding: 13px 24px;
  border-bottom: 1px solid var(--line);
  background: rgba(7, 10, 16, 0.88);
  backdrop-filter: blur(10px);
}

/* The mark is the logo, so it leads and the wordmark follows it. Sized here
   rather than only on the tag, so it stays one number across every page. */
.brand img {
  width: 32px;
  height: 32px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  border-bottom: 0;
  padding-bottom: 0;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.16em;
}

/* The device's menu is a row of key-surface tabs with a 1px edge, so the site
   header wears the same control rather than a row of bare text links. */
.topnav {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

.topnav a {
  border: 1px solid transparent;
  border-bottom: 1px solid transparent;
  border-radius: 9px;
  padding: 7px 14px;
  color: var(--dim);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  transition: color 170ms ease, border-color 170ms ease, background 170ms ease;
}

.topnav a:hover {
  color: var(--ink);
  border-color: var(--line);
  background: var(--key);
}

/* The tab you are on, matching the device's selected key, in the accent the
   device would draw it in. */
.topnav a[aria-current="page"] {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-bg);
}

.slab {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

.spec {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}

.spec div {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 18px;
  background: var(--panel);
}

.spec span {
  color: var(--dim);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.spec strong {
  color: var(--ink);
  font-weight: 400;
  font-size: 0.95rem;
}

.steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.steps li {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  counter-increment: step;
}

.steps li::before {
  content: counter(step, decimal-leading-zero) ".";
  color: var(--dim);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
}

.steps h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.steps p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.55;
}

.feats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.feats article {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}

.feats span {
  color: var(--dim);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
}

.feats h3 {
  margin: 0;
  font-size: 1.02rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.feats p {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.55;
}

.feats code {
  color: var(--ink);
  font-size: 0.95em;
}

.doclinks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.doclinks a {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}

.doclinks a:hover {
  border-color: var(--control);
  background: #0d1119;
}

.doclinks strong {
  font-weight: 500;
  font-size: 0.98rem;
}

.doclinks span {
  color: var(--dim);
  font-size: 0.88rem;
  line-height: 1.45;
}

.shell {
  max-width: var(--max);
  margin: 0 auto;
  padding: 72px 24px 72px;
  display: flex;
  flex-direction: column;
  gap: 38px;
}

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

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  align-items: center;
  gap: 46px;
}

.hero-copy {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* ---------- the reveal ----------
   A signer hidden inside an arcade game is the whole product. The page shows
   that once, in the hero, instead of describing it in a paragraph. Everything
   else on this site holds still. */

.reveal-frame {
  position: relative;
  aspect-ratio: 800 / 480;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  overflow: hidden;
}

.reveal-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.reveal-frame .decoy {
  animation: reveal-out 11s ease-in-out infinite;
}

.reveal-frame .signer {
  animation: reveal-in 11s ease-in-out infinite;
}

/* corner brackets, lifted from the wallet home screen's own frame */
.reveal-frame i {
  position: absolute;
  width: 15px;
  height: 15px;
  border: 0 solid rgba(232, 238, 247, 0.5);
  z-index: 2;
}

.reveal-frame i:nth-of-type(1) { top: 9px; left: 9px; border-top-width: 1px; border-left-width: 1px; }
.reveal-frame i:nth-of-type(2) { top: 9px; right: 9px; border-top-width: 1px; border-right-width: 1px; }
.reveal-frame i:nth-of-type(3) { bottom: 9px; left: 9px; border-bottom-width: 1px; border-left-width: 1px; }
.reveal-frame i:nth-of-type(4) { bottom: 9px; right: 9px; border-bottom-width: 1px; border-right-width: 1px; }

.hero-device {
  margin: 0;
}

.reveal-caption {
  display: grid;
  /* The two spans stack in one cell and cross-fade, so they have to agree on
     where they sit. Without this each took its own width from the start of
     the track and the pair drifted apart as the words changed length. */
  justify-items: center;
  text-align: center;
  margin: 12px 0 0;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
}

.reveal-caption span {
  grid-area: 1 / 1;
}

.reveal-caption .decoy {
  animation: reveal-out 11s ease-in-out infinite;
}

.reveal-caption .signer {
  color: var(--ink);
  animation: reveal-in 11s ease-in-out infinite;
}

@keyframes reveal-out {
  0%, 38% { opacity: 1; }
  48%, 88% { opacity: 0; }
  98%, 100% { opacity: 1; }
}

@keyframes reveal-in {
  0%, 38% { opacity: 0; }
  48%, 88% { opacity: 1; }
  98%, 100% { opacity: 0; }
}

.eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px 10px;
  max-width: 42ch;
  line-height: 1.35;
  margin: 0;
  color: var(--dim);
  font-size: 0.8rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

/* The separator hangs off the PRECEDING segment, so if the line ever does
   break, the slash trails line one instead of leading line two. */
.eyebrow span:not(:last-child)::after {
  content: "/";
  margin-left: 10px;
  color: var(--disabled);
}

h1 {
  margin: 0;
  max-width: 20ch;
  font-size: clamp(2.3rem, 4.4vw, 3.1rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

h2 {
  margin: 0;
  font-size: 1.32rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* Section titles wear the firmware's brackets: the same framing the device
   puts around a reticle or a revealed value. */
.slab h2::before,
.slab h2::after {
  color: var(--accent);
  font-weight: 400;
}

.slab h2::before { content: "[ "; }
.slab h2::after { content: " ]"; }

/* The docs intro is prose, not the install page's copy-beside-device split, so
   it must not inherit .hero's two-column grid: that stranded the title in the
   right-hand column and set the two ledes side by side. */
.docs-hero {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Inside the rail's narrower column, four step cards across is unreadable and
   three feature cards is tight. Both drop to two. */
.docs-body .steps,
.docs-body .feats {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 720px) {
  .docs-body .steps,
  .docs-body .feats {
    grid-template-columns: 1fr;
  }
}

/* ---------- docs: a sticky rail of the device's own tabs ----------
   Eleven sections in one flat pill row read as a pile. Grouped into four
   stages and pinned beside the text, they read as a path, and the tab for
   the section you are in lights up the way the device marks a selected key. */
.docs-layout {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

.docs-rail {
  position: sticky;
  top: 74px;
  max-height: calc(100vh - 96px);
  overflow-y: auto;
}

.docs-rail nav {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Collapsible, the way Sparrow's docs sidebar groups its sections. <details>
   rather than a scripted menu: it is keyboard reachable and it still opens
   with JavaScript off. */
.rail-group {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 16px 0 0;
}

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

.rail-group > summary {
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  list-style: none;
  padding: 5px 0;
  color: var(--dim);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  user-select: none;
}

.rail-group > summary::-webkit-details-marker {
  display: none;
}

/* the brackets ride the label, not the summary: the summary is a flex row now
   and pseudo-elements on it would become row items of their own. */
.rail-group > summary span::before {
  content: "[ ";
  color: var(--accent);
}

.rail-group > summary span::after {
  content: " ]";
  color: var(--accent);
}

.rail-ico {
  flex: none;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform-origin: 50% 50%;
}

.rail-chev {
  flex: none;
  width: 13px;
  height: 13px;
  margin-left: auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 220ms cubic-bezier(0.34, 1.4, 0.64, 1);
}

.rail-group[open] > summary .rail-chev {
  transform: rotate(180deg);
}

/* The tap. A spring rather than a fade, so the icon reads as a thing that
   answered you. */
@keyframes railPop {
  0% { transform: scale(1) rotate(0deg); }
  35% { transform: scale(1.3) rotate(-8deg); }
  70% { transform: scale(0.94) rotate(3deg); }
  100% { transform: scale(1) rotate(0deg); }
}

.rail-ico.pop {
  animation: railPop 440ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (prefers-reduced-motion: reduce) {
  .rail-ico.pop { animation: none; }
  .rail-chev { transition: none; }
}

.rail-group > summary:hover {
  color: var(--ink);
}

.rail-group[open] > summary {
  color: var(--muted);
}

/* The docs open on the documentation itself, not on a title card: one compact
   heading and one orienting line, then the first section. */
.docs-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 4px;
}

.docs-head h1 {
  margin: 0;
  font-size: 1.7rem;
  line-height: 1.15;
}

.docs-rail a {
  display: block;
  border: 1px solid transparent;
  border-bottom: 1px solid transparent;
  border-radius: 8px;
  padding: 6px 10px;
  margin-left: 21px;
  color: var(--dim);
  font-size: 0.8rem;
  line-height: 1.3;
  transition: color 170ms ease, border-color 170ms ease, background 170ms ease;
}

.docs-rail a:hover {
  color: var(--ink);
  border-color: var(--line);
  background: var(--key);
}

.docs-rail a[aria-current="true"] {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-bg);
}

.docs-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* the card carries its own margin for the old single-column layout */
.docs-body .doc-card {
  margin-top: 0;
  scroll-margin-top: 84px;
}

@media (max-width: 900px) {
  /* minmax(0, 1fr) so a wide child scrolls in its own box rather than pushing
     the column, and the page, past the viewport. */
  .docs-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
  }

  .docs-rail {
    position: static;
    max-height: none;
  }

  .docs-rail nav {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .rail-group {
    width: 100%;
    margin: 10px 0 2px;
  }
}

/* The install page is one screen. Nobody should have to scroll to reach the
   button that does the thing the page is named after, so the vertical rhythm
   here is tighter than the documentation pages. */
.install-shell {
  padding-top: 14px;
  padding-bottom: 14px;
  gap: 12px;
}

.install-shell .hero {
  grid-template-columns: minmax(0, 1fr) 270px;
  gap: 26px;
}

.install-shell .hero-copy {
  gap: 12px;
}

.install-shell h1 {
  font-size: clamp(2rem, 3.6vw, 2.6rem);
}

.install-shell .install-card {
  gap: 11px;
  padding: 18px;
}

/* The depth that used to sit in three paragraphs under the button, as one row
   of links. Everything here is a page, not a thing to read now. */
.fineprint {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin: 0;
  font-size: 0.82rem;
}

/* The install is three moves, and it reads as three moves. The counter is the
   device's own zero-padded step numbering rather than a plain 1/2/3. */
.install-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: istep;
}

/* No box. These three sit inside .install-card, which is already a box, and a
   card inside a card is two frames around one sentence. The number in a ring
   does the same job of marking a step and costs no border. */
.install-steps li {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: 3px 12px;
  border: 0;
  background: none;
  padding: 0;
  counter-increment: istep;
}

.install-steps li > * {
  grid-column: 2;
}

.install-steps li::before {
  content: counter(istep);
  grid-column: 1;
  grid-row: 1;
  align-self: start;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--control);
  border-radius: 50%;
  background: var(--accent-bg);
  color: var(--accent);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0;
}

.install-steps h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.install-steps p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.55;
}

@media (max-width: 820px) {
  .install-steps {
    grid-template-columns: 1fr;
  }
}

/* Four corner brackets from a single pseudo-element: eight hairline segments
   pinned to the corners, the reticle the device frames a target with. */
.framed {
  position: relative;
}

.framed::after {
  content: "";
  position: absolute;
  inset: -1px;
  pointer-events: none;
  --bc: var(--control);
  --bl: 18px;
  --bt: 1px;
  background:
    linear-gradient(var(--bc), var(--bc)) top left,
    linear-gradient(var(--bc), var(--bc)) top left,
    linear-gradient(var(--bc), var(--bc)) top right,
    linear-gradient(var(--bc), var(--bc)) top right,
    linear-gradient(var(--bc), var(--bc)) bottom left,
    linear-gradient(var(--bc), var(--bc)) bottom left,
    linear-gradient(var(--bc), var(--bc)) bottom right,
    linear-gradient(var(--bc), var(--bc)) bottom right;
  background-repeat: no-repeat;
  background-size:
    var(--bl) var(--bt), var(--bt) var(--bl),
    var(--bl) var(--bt), var(--bt) var(--bl),
    var(--bl) var(--bt), var(--bt) var(--bl),
    var(--bl) var(--bt), var(--bt) var(--bl);
}

.lede {
  max-width: 64ch;
  margin: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.65;
  text-wrap: pretty;
}

.docs-link {
  align-self: flex-start;
  font-size: 1rem;
}

.status-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.status-pill {
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 6px 12px;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.01em;
}

.status-pill.ready {
  color: var(--green);
  background: rgba(53, 208, 127, 0.07);
}

.status-pill.caution {
  color: var(--amber);
  background: rgba(242, 184, 75, 0.07);
}

.status-pill.stop {
  color: var(--red);
  background: rgba(255, 77, 94, 0.07);
}

/* ---------- install card ---------- */

.install-card {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 26px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.verify-line {
  display: grid;
  grid-template-columns: 9px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  padding: 14px 16px;
  border: 1px solid rgba(242, 184, 75, 0.28);
  border-radius: 9px;
  background: rgba(242, 184, 75, 0.05);
  transition: border-color 220ms ease, background 220ms ease;
}

.verify-line:has(.verify-light.ready) {
  border-color: rgba(53, 208, 127, 0.28);
  background: rgba(53, 208, 127, 0.05);
}

.verify-line:has(.verify-light.stop) {
  border-color: rgba(255, 77, 94, 0.28);
  background: rgba(255, 77, 94, 0.05);
}

.verify-line strong {
  display: block;
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--ink);
}

.verify-line span {
  display: block;
  margin-top: 2px;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.82rem;
}

.verify-light {
  width: 9px;
  height: 9px;
  margin-top: 9px;
  border-radius: 999px;
  background: var(--amber);
}

.verify-light.ready {
  background: var(--green);
}

.verify-light.stop {
  background: var(--red);
}

.ack-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  max-width: 70ch;
  color: var(--muted);
  cursor: pointer;
}

.ack-row input {
  width: 20px;
  height: 20px;
  margin: 3px 0 0;
  accent-color: var(--green);
  flex: none;
}

/* The board question on the install card: its two answers are ack rows, kept
   close together so they read as one choice rather than two more steps. */
.board-pick {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.board-pick > strong {
  color: var(--ink);
  font-weight: 500;
}

.install-actions {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 56px;
}

.flash-button {
  min-height: 54px;
  border: 1px solid var(--green);
  border-radius: 999px;
  padding: 14px 34px;
  background: rgba(53, 208, 127, 0.12);
  color: #8ce8b8;
  font-size: 0.98rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 170ms ease, color 170ms ease, border-color 170ms ease;
}

.flash-button:hover {
  background: rgba(53, 208, 127, 0.2);
  color: #b6f2d3;
}

.flash-button:disabled {
  border-color: var(--control);
  background: transparent;
  color: var(--disabled);
  cursor: not-allowed;
}

.hint {
  margin: 0;
  color: var(--dim);
  font-size: 0.92rem;
}

.is-hidden {
  display: none;
}

.card-rule {
  height: 1px;
  background: var(--line-soft);
}

.power-note {
  margin: 0;
  max-width: 66ch;
  color: var(--muted);
}

.power-note strong {
  color: var(--ink);
  font-weight: 500;
}

.power-note code {
  color: var(--ink);
  font-size: 0.95em;
}

.power-note + .power-note {
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

/* ---------- receipt (details) ---------- */

.receipt {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  overflow: hidden;
}

.receipt > summary {
  padding: 14px 20px;
  color: var(--dim);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}

.receipt > summary::-webkit-details-marker {
  display: none;
}

.receipt > summary::after {
  content: " \25B8";
}

.receipt[open] > summary::after {
  content: " \25BE";
}

.receipt-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: baseline;
  padding: 13px 20px;
  border-top: 1px solid var(--line-soft);
}

.receipt-row span {
  margin: 0;
  color: var(--dim);
}

.receipt strong {
  color: var(--amber);
  font-family: var(--mono);
  font-size: 0.86rem;
  font-weight: 400;
  text-align: right;
  word-break: break-all;
}

.receipt strong.ok {
  color: var(--green);
}

.receipt strong.stop {
  color: var(--red);
}

/* ---------- three notes ---------- */

.know {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.know article {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}

.know span {
  color: var(--dim);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
}

.know article.ok span {
  color: var(--green);
}

.know article.stop span {
  color: var(--red);
}

.know p {
  margin: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

/* ---------- motion ---------- */

.motion-link,
button {
  transition: transform 170ms ease, color 170ms ease, border-color 170ms ease, background 170ms ease;
}

.is-clicked {
  animation: tap 220ms ease;
}

.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms ease, transform 520ms ease;
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@keyframes tap {
  0% { transform: scale(1); }
  45% { transform: scale(0.985); }
  100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  /* hold on the signer, the state that matters */
  .reveal-frame .decoy,
  .reveal-caption .decoy {
    opacity: 0;
  }

  .reveal-frame .signer,
  .reveal-caption .signer {
    opacity: 1;
  }
}

@media (max-width: 900px) {
  /* .install-shell .hero carries two classes and so outranked the bare .hero
     collapse below, whatever the order. The install page kept its two column
     hero all the way down to a phone, where it left the title in a column
     about ninety pixels wide, one word to a line, under the device shot. */
  .hero,
  .install-shell .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 30px;
  }

  /* Collapsed, the device shot inherits the whole column and fills a tablet
     edge to edge. It keeps the width it has beside the title instead. */
  .hero-device {
    width: 100%;
    max-width: 420px;
    margin-inline: auto;
  }

  .feats,
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .shell {
    padding: 48px 20px 56px;
    gap: 30px;
  }

  /* .facts and .part-row belong to guide.html; their phone collapse has
     always lived in this shared sheet, so it stays here. */
  .know,
  .facts,
  .part-row {
    grid-template-columns: 1fr;
  }

  .install-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .flash-button {
    width: 100%;
  }

  /* The top bar was the one thing with no phone rule, so seven nav links sat in
     a single non-wrapping row and pushed the document to 651px inside a 375px
     viewport. The whole page scrolled sideways, which is most of how anyone
     arriving from a chat link would have seen it. Let both the bar and the nav
     wrap, and tighten the gaps to match the smaller type. */
  .topbar {
    flex-wrap: wrap;
    gap: 10px 16px;
    padding: 11px 20px;
  }

  .topnav {
    flex-wrap: wrap;
    gap: 10px 16px;
  }

  /* Two columns of body copy at 375px is a column of about 20 characters. */
  .feats,
  .steps,
  .spec,
  .doclinks {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- accent, last so it wins the ties ----------
   The accent goes on the SMALL type only: the step numbers, the punctuation
   beside them, and the small caps labels. Headings stay ink on purpose. Every
   one of these labels sits directly above a title, so tinting both stacked an
   accent number on an accent heading and the pair fought each other -- the
   small label is what the colour is for, and the title reads off it.
   Body copy stays ink too; an accent that colours the prose is not an accent.
   These tie on specificity with the base rules above, so order decides. */
.doc-card .eyebrow,
.steps li::before,
.install-steps li::before,
.feats span,
.spec span {
  color: var(--accent);
}

/* the separator between eyebrow segments on the install page */
.eyebrow span:not(:last-child)::after {
  color: var(--accent);
}

/* The markers of the ordinary lists in the docs: "1." "2." with their periods,
   and the bullet dots. These are drawn by the browser, not by a rule of ours,
   so they were the numbers the accent missed. */
.doc-card li::marker,
.docs-body li::marker {
  color: var(--accent);
}

/* The sentence-ending full stops, wrapped by theme.js because no selector can
   reach one character. Only terminal stops are wrapped, so decimals and file
   names keep their dots.

   NOT called .stop: that name is already the STATUS class here
   (.status-pill.stop, .verify-light.stop, .know article.stop) and colouring a
   status element with the accent is exactly what kiss_theme.h forbids. */
.fullstop {
  color: var(--accent);
}

/* One topic at a time: the hidden ones must not hold a flex slot open. */
.docs-body .doc-card[hidden] {
  display: none;
}

/* Where to go next, at the foot of every topic. Sparrow and Supabase both
   carry this, and it is what turns a pile of sections into a path. */
.docs-pager {
  display: flex;
  gap: 12px;
  margin-top: 4px;
}

.docs-pager a {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  transition: border-color 170ms ease, background 170ms ease;
}

.docs-pager .pager-next {
  align-items: flex-end;
  text-align: right;
}

.docs-pager a:hover {
  border-color: var(--accent);
  background: var(--key);
}

.docs-pager span {
  color: var(--dim);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.docs-pager strong {
  color: var(--ink);
  font-weight: 500;
  font-size: 0.95rem;
}

@media (max-width: 720px) {
  .docs-pager {
    flex-direction: column;
  }

  .docs-pager .pager-next {
    align-items: flex-start;
    text-align: left;
  }
}

/* The header carries a lockup, three tabs, the repo mark and four swatches.
   That fits a laptop and not a phone, so on a narrow screen everything in it
   gives up a little rather than the bar growing to three rows. */
@media (max-width: 640px) {
  .topbar {
    gap: 10px;
    padding: 10px 16px;
  }

  .brand {
    gap: 8px;
    font-size: 0.78rem;
    letter-spacing: 0.08em;
  }

  .brand img {
    width: 26px;
    height: 26px;
  }

  .topnav {
    gap: 4px;
  }

  .topnav a {
    padding: 6px 10px;
    font-size: 0.78rem;
  }

  .theme-pick {
    padding-left: 8px;
  }

  .icon-link {
    width: 26px;
    height: 26px;
  }
}

/* Below this the wordmark goes and the mark stands alone, because the three
   tabs plus the repo mark plus four swatches cannot share a row with it at
   phone width, and the bar was landing on three rows. The mark is the logo and
   still the link home; the anchor carries an aria-label so dropping the text
   costs the link no name. */
@media (max-width: 430px) {
  .topbar {
    gap: 8px;
    padding: 9px 14px;
  }

  .brand {
    font-size: 0;
  }

  .topnav a {
    padding: 6px 8px;
    font-size: 0.74rem;
  }

  .theme-pick {
    padding-left: 4px;
  }
}

/* Shown only when the browser has no Web Serial. It sits outside the install
   gate on purpose: the gate cannot open for this reader, so anything inside it
   is invisible to exactly the person it is written for. */
.browser-note {
  margin: 0;
  padding: 13px 15px;
  border: 1px solid rgba(242, 184, 75, 0.4);
  border-radius: 10px;
  background: rgba(242, 184, 75, 0.06);
  color: var(--amber);
  font-size: 0.9rem;
  line-height: 1.55;
}

.browser-note a {
  color: var(--amber);
  border-bottom-color: rgba(242, 184, 75, 0.5);
}

/* Route B. A device already running beta8 or later updates from a card with no
   cable and no computer, which is easier than anything else on this page, so
   it says so rather than hiding in the docs. */
.sd-route {
  margin: 0;
  padding: 12px 15px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--key);
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.55;
}

.sd-route strong {
  color: var(--ink);
  font-weight: 500;
}
