/* GuideGen — site styles: landing page, guide editor, public viewer.
   The popup carries its own copy of these tokens, because an extension page can't
   load a stylesheet from here. Any control on both surfaces has to be styled in
   both places. Light and dark are both first class. */

:root {
  /* Ink & Paper.
     Two rules govern this palette, and they are the whole reason it doesn't look
     like every other purple-on-slate dashboard:

     1. The neutrals are WARM. Cool slate greys are what every framework default
        ships, so warm paper is the single cheapest way to look deliberate.
     2. Colour carries meaning, it is never decoration. The primary button is ink,
        not a brand hue — so the only saturated things on screen are the ones that
        mean something: a step number, an annotation, a recording light, a guide
        that is shared. One accent doing six jobs is what "nobody decided
        anything" looks like. */

  /* the one accent — step numbers, annotations, focus. Ochre, not purple:
     it has to stay legible drawn on top of the blue-grey admin panels this
     product exists to document, and orange is as far from that chrome as it gets. */
  --brand: #c2410c;
  --brand-2: #9e340a;
  --brand-soft: #f6ece2;
  --brand-ring: rgba(194, 65, 12, 0.28);
  --on-brand: #fffdfa;

  /* primary action = ink. Confident, and it never dates. */
  --pri: #1a1713;
  --pri-2: #322b23;
  --pri-fg: #fbfaf7;

  --bg: #fbfaf7;
  --bg-2: #f4f1ea;
  --panel: #ffffff;
  --panel-2: #f5f2ec;

  --ink: #1a1713;
  --ink-2: #443c31;
  --muted: #6f675b;
  --faint: #928879;

  --line: #e5dfd2;

  /* semantic, and tokenised so there is exactly one place to change them */
  --ok: #16643f;
  --err: #a8321f;
  --rec: #c1352c;
  --live-fg: #2f6344;
  --live-bg: #e7ece2;

  --r-sm: 7px;
  --r: 10px;
  --r-lg: 14px;
  --r-xl: 22px;

  /* Borders do the separating; shadows only lift things that genuinely float.
     Shadow on everything is another generated-UI tell. */
  --sh-1: 0 1px 2px rgba(26, 23, 19, 0.05);
  --sh-2: 0 6px 20px rgba(26, 23, 19, 0.07);
  --sh-3: 0 22px 60px rgba(26, 23, 19, 0.16);

  --fast: 130ms cubic-bezier(0.2, 0, 0.2, 1);
  --wrap: 1080px;

  /* native scrollbars, date pickers and form widgets follow this */
  color-scheme: light;
}

/* Dark is a *choice* now, not an OS reading.
   assets/theme.js resolves light | dark | auto and stamps data-theme on <html>
   before the first paint, so there is exactly one dark block here and no
   duplicated values. The site already can't work without JS — the whole
   dashboard and the public viewer are JS — so relying on it costs nothing, and
   if theme.js ever fails to load the page falls back to light, which is safe.

   The default is LIGHT, not the OS setting. Every artefact this product makes is
   light — the HTML export, the PDF, the published guide, the video slides — so an
   editor that matches the thing you're building is more coherent than one that
   flips with the time of day. "Auto" is one click away for anyone who wants it. */
:root[data-theme="dark"] {
  color-scheme: dark;

  /* Warm near-black, not navy. Same reasoning as the light scale. */
  --brand: #e08a4f;
  --brand-2: #eb9c65;
  --brand-soft: #2c2318;
  --brand-ring: rgba(224, 138, 79, 0.30);
  --on-brand: #21180f;

  --pri: #f2ede3;
  --pri-2: #ffffff;
  --pri-fg: #15130f;

  --bg: #15130f;
  --bg-2: #1a1712;
  --panel: #1c1a15;
  --panel-2: #23201a;

  --ink: #f2ede3;
  --ink-2: #cbc2b1;
  --muted: #9a9080;
  --faint: #746b5d;

  --line: #332e26;

  --ok: #63c08e;
  --err: #f0897c;
  --rec: #ef7a72;
  --live-fg: #88bd99;
  --live-bg: #1f2a20;

  --sh-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --sh-2: 0 6px 20px rgba(0, 0, 0, 0.45);
  --sh-3: 0 22px 60px rgba(0, 0, 0, 0.6);
}

* { box-sizing: border-box; }

/* The hidden attribute has to beat component display rules. The UA stylesheet's
   [hidden]{display:none} loses on specificity to things like
   .auth-wrap{display:grid} and header nav{display:flex} — which meant a
   signed-in user saw the sign-in form AND the dashboard stacked, with both
   navs in the header. Verified by screenshot; a DOM check on el.hidden passes
   regardless, so don't trust that alone. */
[hidden] { display: none !important; }

/* scrollbar-gutter keeps the layout still when a dialog locks body scrolling —
   without it the page jumps sideways by the scrollbar width as the modal opens. */
html { scroll-behavior: smooth; scrollbar-gutter: stable; }
/* The page behind a dialog must not scroll under it. The overlay does its own
   scrolling now, so there is nothing lost. */
body.modal-open { overflow: hidden; }
body {
  margin: 0;
  font: 16px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--brand-2); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 22px; }
.narrow { max-width: 720px; }

/* ---------- header ---------- */
header.site {
  position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
header.site .row {
  display: flex; align-items: center; gap: 14px;
  height: 62px; max-width: var(--wrap); margin: 0 auto; padding: 0 22px;
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 650; color: var(--ink); }
.brand:hover { text-decoration: none; }
.brand .mark {
  width: 27px; height: 27px; border-radius: 8px; flex: none;
  background: var(--pri); color: var(--pri-fg);
  display: grid; place-items: center;
}
.brand .mark svg { width: 15px; height: 15px; }
.brand span { letter-spacing: -0.015em; }
header.site nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
header.site nav a { color: var(--ink-2); font-size: 14px; font-weight: 550; padding: 7px 10px; border-radius: var(--r-sm); }
header.site nav a:hover { background: var(--panel-2); text-decoration: none; color: var(--ink); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink-2);
  padding: 11px 17px; border-radius: var(--r-sm);
  font-size: 14.5px; font-weight: 620; cursor: pointer;
  /* A <button> gets `line-height: normal` from the UA; an <a class="btn"> inherits
     the body's 1.65. So the same class rendered 41px tall on a button and 48px on a
     link — visible wherever the two sit together. Pin it. */
  line-height: 1.2;
  box-shadow: var(--sh-1);
  transition: background var(--fast), transform var(--fast), color var(--fast);
}
.btn:hover { background: var(--panel-2); color: var(--ink); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn svg { width: 16px; height: 16px; flex: none; }
/* A button is never a flex item that shrinks. Every row that holds buttons wraps
   (.modal .row, .rowtools, .acts, .ed-top, .cta-row, .dl, .wl), so the row has
   somewhere to put an overflow — whereas shrinking squeezed "Copy link" onto two
   lines in the share dialog and squashed the icon buttons in a step's toolbar from
   27px to 21px. Wrap, don't compress. */
.btn { flex: 0 0 auto; white-space: nowrap; }
.btn.brand-btn {
  background: var(--pri); color: var(--pri-fg); border-color: transparent;
  box-shadow: 0 2px 8px rgba(26, 23, 19, 0.20);
}
.btn.brand-btn:hover { background: var(--pri-2); color: var(--pri-fg); }
.btn.lg { padding: 14px 22px; font-size: 15.5px; }

/* ---------- hero ---------- */
.hero { padding: 74px 0 8px; text-align: center; }
.pill {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--brand-soft); color: var(--brand-2);
  font-size: 12.5px; font-weight: 650; letter-spacing: 0.01em;
  padding: 6px 13px; border-radius: 999px; margin-bottom: 20px;
}
h1.big {
  font-size: clamp(34px, 5.4vw, 55px); line-height: 1.08;
  letter-spacing: -0.035em; font-weight: 700;
  margin: 0 auto 18px; max-width: 15ch;
}
.lede {
  font-size: clamp(16.5px, 2vw, 19.5px); color: var(--muted);
  max-width: 60ch; margin: 0 auto 30px; line-height: 1.6;
}
.cta-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.cta-note { margin-top: 14px; font-size: 13px; color: var(--faint); }

/* What the product does, in one glance, under the hero. Chips rather than a second
   nav: the header already carries five items and cannot take eight, and these are
   jump links into the sections that make each claim. Quiet by default — this is a
   contents list, not eight buttons competing with the install CTA above it. */
.caps { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 34px auto 0; max-width: 74ch; }
.caps a {
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; padding: 6px 12px; line-height: 1.3;
  transition: background var(--fast), color var(--fast), border-color var(--fast);
}
.caps a:hover { background: var(--panel-2); color: var(--ink); border-color: var(--faint); text-decoration: none; }
/* A jump link landing under a sticky header is the oldest anchor bug there is. */
:target { scroll-margin-top: 78px; }

/* ---------- sections ---------- */
section { padding: 62px 0; }
section.tint { background: var(--bg-2); border-block: 1px solid var(--line); }
/* Two tinted sections in a row would otherwise show a 2px rule between them — both
   borders land on the same line — against 1px everywhere else on the page. */
section.tint + section.tint { border-top: 0; }
h2.sec {
  font-size: clamp(25px, 3.4vw, 33px); letter-spacing: -0.028em;
  margin: 0 0 12px; font-weight: 690;
}
.sec-lede { color: var(--muted); max-width: 62ch; margin: 0 0 34px; }
.center { text-align: center; }
.center .sec-lede { margin-inline: auto; }

/* ---------- feature grid ---------- */
.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); }
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 22px;
  box-shadow: var(--sh-1);
}
.card .ico {
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--brand-soft); color: var(--brand-2);
  display: grid; place-items: center; margin-bottom: 13px;
}
.card .ico svg { width: 18px; height: 18px; }
.card h3 { margin: 0 0 6px; font-size: 16.5px; font-weight: 650; letter-spacing: -0.012em; }
.card p { margin: 0; color: var(--muted); font-size: 14.5px; line-height: 1.6; }

/* ---------- steps / how it works ---------- */
.steps { counter-reset: s; display: grid; gap: 26px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.steps > div { position: relative; padding-left: 46px; }
.steps > div::before {
  counter-increment: s; content: counter(s);
  position: absolute; left: 0; top: -2px;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand);
  display: grid; place-items: center; font-weight: 700; font-size: 14px;
}
.steps h3 { margin: 4px 0 5px; font-size: 16.5px; font-weight: 650; }
.steps p { margin: 0; color: var(--muted); font-size: 14.5px; }

/* ---------- format list ---------- */
.formats { display: flex; flex-wrap: wrap; gap: 9px; }
.formats span {
  border: 1px solid var(--line); background: var(--panel);
  border-radius: 999px; padding: 8px 15px;
  font-size: 14px; font-weight: 550; color: var(--ink-2);
}

/* ---------- waitlist ---------- */
.wl { display: flex; gap: 9px; flex-wrap: wrap; max-width: 470px; }
.wl input[type=email] {
  flex: 1; min-width: 220px;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  border-radius: var(--r-sm); padding: 12px 14px; font: inherit; font-size: 14.5px;
  outline: 0; transition: border-color var(--fast), box-shadow var(--fast);
}
.wl input[type=email]:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); }
.wl-msg { margin-top: 12px; font-size: 14px; min-height: 20px; }
.wl-msg.ok { color: var(--ok); }
.wl-msg.err { color: var(--err); }

/* ---------- faq ---------- */
.faq { display: grid; gap: 2px; max-width: 760px; }
.faq details {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--panel); padding: 0 17px;
}
.faq summary {
  cursor: pointer; padding: 15px 0; font-weight: 600; font-size: 15.5px;
  list-style: none; display: flex; justify-content: space-between; gap: 12px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--faint); font-weight: 500; font-size: 19px; line-height: 1; }
.faq details[open] summary::after { content: "\2013"; }
.faq details p { margin: 0 0 16px; color: var(--muted); font-size: 14.5px; }

/* ---------- footer ---------- */
footer.site {
  border-top: 1px solid var(--line); background: var(--bg-2);
  padding: 34px 0; font-size: 14px; color: var(--muted);
}
footer.site .row { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
footer.site a { color: var(--muted); }
footer.site .spacer { flex: 1; }

/* ---------- legal documents ---------- */
.doc { padding: 48px 0 80px; }
.doc h1 { font-size: clamp(28px, 4vw, 37px); letter-spacing: -0.03em; margin: 0 0 6px; }
.doc .updated { color: var(--faint); font-size: 14px; margin: 0 0 32px; }
.doc h2 { font-size: 19px; margin: 34px 0 8px; letter-spacing: -0.015em; }
.doc h3 { font-size: 16px; margin: 22px 0 6px; }
.doc p, .doc li { color: var(--ink-2); }
.doc ul { padding-left: 22px; }
.doc li { margin: 5px 0; }
.doc .callout {
  background: var(--brand-soft); border: 1px solid color-mix(in srgb, var(--brand) 22%, transparent);
  border-radius: var(--r); padding: 16px 18px; margin: 22px 0;
}
.doc .callout p:last-child { margin-bottom: 0; }
.doc table { width: 100%; border-collapse: collapse; margin: 18px 0; font-size: 14.5px; }
.doc th, .doc td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.doc th { color: var(--ink); font-weight: 650; }
.doc code {
  background: var(--panel-2); border: 1px solid var(--line);
  padding: 1px 5px; border-radius: 5px; font-size: 13.5px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
}

/* ---------- auth screen ---------- */
.auth-wrap { min-height: calc(100vh - 62px); display: grid; place-items: center; padding: 40px 20px; }
.auth-card {
  width: 100%; max-width: 400px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-xl); padding: 30px 28px; box-shadow: var(--sh-2);
}
.auth-card h1 { font-size: 23px; letter-spacing: -0.025em; margin: 0 0 6px; }
.auth-card .sub { color: var(--muted); font-size: 14.5px; margin: 0 0 22px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; color: var(--ink-2); }
.field input {
  width: 100%; border: 1px solid var(--line); background: var(--panel-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 11px 13px; font: inherit; font-size: 14.5px;
  outline: 0; transition: border-color var(--fast), box-shadow var(--fast);
}
.field input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); background: var(--panel); }
.auth-card .btn { width: 100%; margin-top: 4px; }
.auth-alt { margin-top: 18px; font-size: 14px; color: var(--muted); text-align: center; }
.auth-alt button {
  background: none; border: 0; color: var(--brand-2); font: inherit; font-weight: 600;
  cursor: pointer; padding: 0;
}
.auth-alt button:hover { text-decoration: underline; }
.msg { font-size: 13.5px; margin: 12px 0 0; min-height: 19px; line-height: 1.5; }
.msg.err { color: var(--err); }
.msg.ok { color: var(--ok); }
.link-btn {
  background: none; border: 0; padding: 0; font: inherit; font-size: 13px;
  color: var(--muted); cursor: pointer; text-decoration: underline;
}
.link-btn:hover { color: var(--ink-2); }

/* ---------- dashboard ---------- */
.dash { padding: 30px 0 90px; }
.dash-head { display: flex; align-items: flex-end; gap: 14px; margin-bottom: 24px; flex-wrap: wrap; }
.dash-head h1 { font-size: 26px; letter-spacing: -0.028em; margin: 0; }
.dash-head p { margin: 4px 0 0; color: var(--muted); font-size: 14.5px; }
.dash-head .spacer { flex: 1; }

.guide-row {
  display: flex; align-items: center; gap: 14px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 15px 17px; margin-bottom: 9px;
  box-shadow: var(--sh-1);
}
.guide-row .info { flex: 1; min-width: 0; }
.guide-row .t {
  font-weight: 620; font-size: 15.5px; letter-spacing: -0.012em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.guide-row .m { color: var(--muted); font-size: 13px; margin-top: 2px; }
.guide-row .acts { display: flex; gap: 6px; flex-wrap: wrap; }
/* Open + Copy link + View + the badge is ~250px of fixed width. On a narrow screen
   that leaves the title a dozen ellipsised characters — the row is listing guides,
   so the guide's name is the part that has to survive. Give it the line. */
@media (max-width: 620px) {
  .guide-row { flex-wrap: wrap; row-gap: 10px; }
  .guide-row .info { flex: 1 1 100%; }
}
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 650; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--muted); white-space: nowrap;
}
.badge.live { background: var(--live-bg); color: var(--live-fg); border-color: transparent; }
/* A catch-up capture. Ochre because it is provisional and will delete itself —
   which is meaning, not decoration: it is the one row on this page with a clock
   running on it. */
/* --brand-2 on --brand-soft, as every other soft-ochre chip on this page uses —
   --brand itself doesn't clear AA on it in dark mode. */
.badge.buf { color: var(--brand-2); border-color: transparent; background: var(--brand-soft); }
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* Dashed, so a provisional row reads as provisional before the badge is read. */
.guide-row.pending { border-style: dashed; }

.blank {
  border: 1px dashed var(--line); border-radius: var(--r-lg);
  padding: 52px 28px; text-align: center; background: var(--panel-2);
}
.blank .ico {
  width: 44px; height: 44px; border-radius: 13px; margin: 0 auto 14px;
  background: var(--bg-2); color: var(--faint);
  display: grid; place-items: center;
}
.blank h2 { margin: 0 0 7px; font-size: 17.5px; font-weight: 650; }
.blank p { margin: 0 auto; color: var(--muted); max-width: 44ch; font-size: 14.5px; }
.blank .cta { margin-top: 20px; }

.skel { height: 66px; border-radius: var(--r); background: var(--panel-2); margin-bottom: 9px;
  animation: pulse-skel 1.3s ease-in-out infinite; }
@keyframes pulse-skel { 0%,100% { opacity: 1 } 50% { opacity: 0.55 } }

.acct { display: flex; align-items: center; gap: 10px; font-size: 13.5px; color: var(--muted); }

/* ---------- public guide viewer ---------- */
/* Two things about this one line, both of them bugs that shipped:
   - The horizontal padding is stated. `padding: 34px 0 90px` is a shorthand, so it
     overrode `.wrap`'s `0 22px` and set left/right to zero — invisible on a desktop,
     where a 720px column sits in the middle of the screen, and on a phone the title,
     the step text and every screenshot ran into the edge of the display.
   - It is **wider than `.narrow`**, and no longer uses it. 720px is a reading column;
     this is an image-first document, and a 1600px screenshot rendered into 672px of
     it made the small UI text — the thing the reader came for — unreadable. */
.viewer { padding: 34px 22px 90px; max-width: 1040px; }
.viewer-head { margin-bottom: 30px; }
.viewer-head h1 {
  font-size: clamp(26px, 4vw, 36px); letter-spacing: -0.03em;
  margin: 0 0 8px; line-height: 1.15;
}
.viewer-head .meta { color: var(--muted); font-size: 14.5px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.viewer-head .meta .sep { width: 3px; height: 3px; border-radius: 50%; background: var(--faint); }

.vstep { display: flex; gap: 16px; padding: 22px 0; border-top: 1px solid var(--line); }
.vstep:first-of-type { border-top: 0; padding-top: 6px; }
.vstep .n {
  width: 30px; height: 30px; min-width: 30px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand); font-weight: 700; font-size: 14px;
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
}
.vstep.note .n { background: var(--panel-2); color: var(--muted); border: 1px solid var(--line); }
.vstep .body { flex: 1; min-width: 0; }
.vstep .txt {
  font-size: 17px; font-weight: 560; letter-spacing: -0.012em;
  margin: 3px 0 0; line-height: 1.5;
}
.vstep.note .txt { font-weight: 450; color: var(--ink-2); }
.vstep figure {
  margin: 14px 0 0; border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; background: var(--panel-2); line-height: 0;
}
.vstep figure img { width: 100%; }
.note-tag {
  display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--brand-2); background: var(--brand-soft);
  border-radius: 6px; padding: 3px 7px; margin-bottom: 6px;
}

.viewer-foot {
  margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--line);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  color: var(--muted); font-size: 14px;
}
.viewer-foot .spacer { flex: 1; }

.state {
  padding: 90px 24px; text-align: center;
}
.state .ico {
  width: 46px; height: 46px; border-radius: 14px; margin: 0 auto 16px;
  background: var(--panel-2); color: var(--faint); display: grid; place-items: center;
}
.state h1 { font-size: 21px; margin: 0 0 8px; letter-spacing: -0.02em; }
.state p { margin: 0 auto; color: var(--muted); max-width: 46ch; }
.state .cta { margin-top: 22px; }

.vskel { height: 15px; border-radius: 6px; background: var(--panel-2); margin-bottom: 10px;
  animation: pulse-skel 1.3s ease-in-out infinite; }
.vskel.img { height: 210px; border-radius: var(--r); margin-top: 14px; }
.vskel.w60 { width: 60%; } .vskel.w40 { width: 40%; } .vskel.title { height: 30px; width: 70%; margin-bottom: 18px; }

/* ---------- viewer: header, and what it carries once you scroll ---------- */
header.site .row .spacer { flex: 1; }
.hdr-title {
  font-size: 14.5px; font-weight: 600; color: var(--ink-2); letter-spacing: -0.01em;
  max-width: 42ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  opacity: 0; transform: translateY(3px); transition: opacity var(--fast), transform var(--fast);
  pointer-events: none;
}
.hdr-title.show { opacity: 1; transform: none; }
.hdr-step {
  font-size: 13px; font-weight: 600; color: var(--muted);
  font-variant-numeric: tabular-nums; opacity: 0; transition: opacity var(--fast);
}
.hdr-step.show { opacity: 1; }
/* Read progress, on the header's own bottom edge — no extra row of chrome. */
/* Anchored to the sticky header, which is already a positioned element. */
.hdr-bar {
  height: 2px; width: 0; background: var(--brand);
  position: absolute; left: 0; bottom: -1px;
}

/* ---------- viewer: the header block ---------- */
.appchip {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 13px;
  font-size: 13px; font-weight: 620; color: var(--ink-2);
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px 11px 4px 4px;
}
.appchip .tile {
  width: 21px; height: 21px; border-radius: 50%; flex: none;
  background: var(--brand); color: var(--on-brand);
  display: grid; place-items: center; font-size: 11.5px; font-weight: 700;
}
.vdesc {
  margin: 10px 0 14px; color: var(--ink-2); font-size: 16.5px; line-height: 1.6;
  max-width: 68ch;
}
.viewer-head .meta .who { display: inline-flex; align-items: center; gap: 7px; color: var(--ink-2); font-weight: 560; }
.viewer-head .meta .av {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--pri); color: var(--pri-fg);
  display: grid; place-items: center; font-size: 10px; font-weight: 700; letter-spacing: 0.02em;
}
.startrow { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; margin-top: 20px; }
.startrow .starturl {
  font-size: 12.5px; color: var(--muted); background: var(--panel-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 5px 9px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.vtoc { margin-top: 20px; border: 1px solid var(--line); border-radius: var(--r); background: var(--panel); }
.vtoc summary {
  cursor: pointer; padding: 11px 15px; font-size: 14px; font-weight: 620; color: var(--ink-2);
  list-style: none;
}
.vtoc summary::-webkit-details-marker { display: none; }
.vtoc summary::before { content: "▸ "; color: var(--faint); }
.vtoc[open] summary::before { content: "▾ "; }
.vtoc ol { margin: 0; padding: 2px 15px 13px 34px; }
.vtoc li { color: var(--muted); font-size: 14px; line-height: 1.55; }
.vtoc a { color: var(--ink-2); }

/* ---------- viewer: a step ---------- */
.vstep .txtrow { display: flex; align-items: flex-start; gap: 8px; }
.vstep .txtrow .txt { flex: 1; min-width: 0; }
.vstep .anchor {
  flex: 0 0 auto; width: 27px; height: 27px; border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent; color: var(--faint);
  display: grid; place-items: center; cursor: pointer;
  opacity: 0; transition: opacity var(--fast), color var(--fast), background var(--fast);
}
.vstep .anchor svg { width: 15px; height: 15px; }
.vstep:hover .anchor, .vstep .anchor:focus-visible { opacity: 1; }
.vstep .anchor:hover { background: var(--panel-2); color: var(--ink-2); }
.vstep .vlink {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 7px;
  font-size: 13.5px; color: var(--brand-2); font-weight: 560;
}
.vstep .vlink svg { width: 13px; height: 13px; }
.vstep figure { position: relative; }
.vstep figure img { cursor: zoom-in; }
.zoombtn {
  position: absolute; right: 10px; bottom: 10px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 11px; border-radius: var(--r-sm); cursor: pointer;
  font-size: 12.5px; font-weight: 620; line-height: 1;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(24, 21, 17, 0.72); color: #fff;
  backdrop-filter: blur(6px);
  opacity: 0; transition: opacity var(--fast);
}
.zoombtn svg { width: 14px; height: 14px; }
.vstep figure:hover .zoombtn, .zoombtn:focus-visible { opacity: 1; }
/* Arriving on /g/{id}#step-7 — say which one without moving anything. */
.vstep.flash { background: var(--brand-soft); border-radius: var(--r); }

/* ---------- viewer: lightbox ---------- */
/* Above the sticky header (z-index 30) *and* the modal overlay, and opaque: at 0.92
   the header's own backdrop-filter kept re-compositing through it, so the page's
   wordmark and buttons sat on top of the picture. */
.lightbox {
  position: fixed; inset: 0; z-index: 200; display: flex; flex-direction: column;
  background: #131110;
}
.lb-bar {
  display: flex; align-items: center; gap: 8px; padding: 12px 14px;
  color: rgba(255, 255, 255, 0.9); font-size: 13.5px; font-weight: 600;
}
.lb-bar .lb-sp { flex: 1; }
.lb-btn {
  min-width: 34px; height: 34px; padding: 0 10px; border-radius: var(--r-sm);
  border: 1px solid rgba(255, 255, 255, 0.18); background: rgba(255, 255, 255, 0.08);
  color: #fff; font-size: 15px; font-weight: 620; cursor: pointer; line-height: 1;
}
.lb-btn:hover { background: rgba(255, 255, 255, 0.16); }
.lb-stage {
  flex: 1; min-height: 0; display: grid; place-items: center;
  overflow: hidden; padding: 0 14px 18px; cursor: zoom-in;
}
.lb-stage.zoomed { cursor: grab; }
.lb-stage img {
  max-width: 100%; max-height: 100%; border-radius: var(--r);
  background: #fff; transform-origin: center center;
  transition: transform 90ms linear; touch-action: none; user-select: none;
}

/* ---------- viewer: the promo bar ---------- */
.promo {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: none; align-items: center; gap: 12px;
  padding: 12px 22px; font-size: 14px; color: var(--ink-2);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-top: 1px solid var(--line);
}
.promo.show { display: flex; }
.promo .sp { flex: 1; }
.promo .x {
  width: 30px; height: 30px; border-radius: var(--r-sm); flex: none;
  border: 1px solid var(--line); background: var(--panel); color: var(--muted);
  cursor: pointer; font-size: 13px;
}
.promo .x:hover { color: var(--ink); }

@media (max-width: 760px) {
  .promo { padding: 10px 14px; font-size: 13px; }
  .promo span:first-child { max-width: 22ch; }
}

/* The viewer's header is not the dashboard's: it holds three compact actions rather
   than a nav of links, and the generic two-row rule at 560px dropped Print onto a
   second line on every phone. Icon-only below 700px keeps it to one row down to
   ~360px, and lets it wrap on its own below that rather than being pinned to two. */
/* Selectors written to out-specify the generic 560px header rule below, which pins
   the wordmark to row one and the nav to row two — that rule exists for the
   dashboard's five nav links and is wrong for three icon buttons. */
@media (max-width: 700px) {
  header.site .row.vrow { flex-wrap: wrap; row-gap: 6px; height: auto; min-height: 62px; }
  header.site .row.vrow nav { order: 0; flex-basis: auto; margin-left: 0; }
  header.site .row.vrow .theme-toggle { order: 0; margin-left: auto; }
  .vrow .btn .t { display: none; }
  .vrow .btn { padding: 8px 10px !important; }
  .vrow .hdr-title, .vrow .hdr-step { display: none; }
  .viewer { padding-left: 16px; padding-right: 16px; }
  .zoombtn { opacity: 1; }        /* no hover on a touch screen */
}
@media (pointer: coarse) {
  .vstep .anchor { opacity: 1; }
  .zoombtn { opacity: 1; }
  /* Nothing here is ever hovered, so anything hover reveals has to start open. Key
     it on the pointer, not the width: a narrow window on a desktop still has a mouse. */
  .ins-btn { opacity: 1; }
  .ins-btn .lbl { max-width: 140px; margin-left: 6px; }
  .btn.exp .lbl { max-width: 240px; margin-left: 7px; }
}

/* A recipient's most likely second action is printing it. */
@media print {
  .promo, .lightbox, .hdr-bar, .vstep .anchor, .zoombtn, .vtoc { display: none !important; }
  header.site, footer.site, .viewer-foot, .overlay, .toast { display: none !important; }
  body.modal-open { overflow: visible; }
  body { background: #fff; color: #000; }
  .viewer { padding: 0; }
  .vstep { page-break-inside: avoid; border-top: 1px solid #ddd; }
  .vstep .n { background: #2b2620 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .vstep figure { border-color: #ccc; }
  a { color: #000; text-decoration: none; }
}

/* ---------- notices ---------- */
.ext-note, .ed-banner {
  border: 1px solid var(--line); background: var(--panel-2);
  border-radius: var(--r); padding: 13px 15px; margin-bottom: 18px;
  font-size: 13.5px; line-height: 1.55; color: var(--ink-2);
}
.ext-note b, .ed-banner b { color: var(--ink); }

/* ---------- guide editor ---------- */
.ed { padding: 26px 0 90px; }

.ed-top {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 22px;
}
.ed-top .spacer { flex: 1; }
.ed-top .title-wrap { min-width: 220px; flex: 1 1 260px; }
.ed-title {
  width: 100%; border: 1px solid transparent; background: transparent;
  color: var(--ink); border-radius: var(--r-sm); padding: 5px 8px;
  font-family: inherit; font-size: 22px; font-weight: 660; letter-spacing: -0.025em;
  outline: 0; transition: border-color var(--fast), background var(--fast);
}
.ed-title:hover { border-color: var(--line); }
.ed-title:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.ed-top .submeta { color: var(--muted); font-size: 13px; padding: 0 9px; }

/* The shared guide's intro. Styled like the title — quiet until you touch it — because
   it is the same kind of thing: a field that usually just reads as text.
   `font-family: inherit` as its own declaration, never inside a `font:` shorthand:
   that shorthand is invalid with `inherit` and silently drops a textarea to the UA's
   monospace default. */
.ed-desc {
  display: block; width: 100%; resize: none; overflow: hidden;
  margin: 4px 0 18px; padding: 9px 11px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; color: var(--ink-2);
  font-family: inherit; font-size: 15px; line-height: 1.6;
  outline: 0; transition: border-color var(--fast), background var(--fast);
}
.ed-desc::placeholder { color: var(--faint); }
.ed-desc:hover { border-color: var(--line); }
.ed-desc:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }

.btn.sm { padding: 7px 11px; font-size: 13px; }
.btn.icon { padding: 8px; }
.btn.icon.sm { padding: 6px; }
.btn.icon svg { width: 15px; height: 15px; }
.btn.danger { color: var(--err); }
.btn.danger:hover { background: color-mix(in srgb, var(--err) 10%, transparent); color: var(--err); }
.btn[disabled] { opacity: 0.45; pointer-events: none; }

/* ---------- export menu ---------- */
.menu-wrap { position: relative; }
.menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;
  min-width: 262px; padding: 7px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-3);
  display: none;
}
.menu.open { display: block; }
.menu .lbl {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--faint); padding: 7px 9px 5px;
}
.menu .sep { height: 1px; background: var(--line); margin: 5px 3px; }
.menu button {
  display: flex; align-items: center; gap: 11px; width: 100%;
  border: 0; background: none; color: var(--ink); cursor: pointer;
  padding: 8px 9px; border-radius: var(--r-sm); font: inherit; text-align: left;
}
.menu button:hover { background: var(--panel-2); }
.menu .ico {
  flex: none; width: 26px; height: 26px; border-radius: 7px;
  display: grid; place-items: center; color: var(--ink-2);
  background: var(--panel-2); border: 1px solid var(--line);
}
.menu .ico svg { width: 14px; height: 14px; }
.menu button:hover .ico { color: var(--ink); }
.menu .txt { display: flex; flex-direction: column; font-size: 14px; font-weight: 560; }
.menu .txt small { color: var(--muted); font-size: 12px; font-weight: 400; margin-top: 1px; }

/* ---------- step cards ---------- */
.step {
  display: flex; gap: 13px; padding: 16px 0;
  border-top: 1px solid var(--line);
}
.step:first-of-type { border-top: 0; }
.step.dragging { opacity: 0.4; }
.step.drop-before { box-shadow: inset 0 2px 0 var(--brand); }
.step.drop-after { box-shadow: inset 0 -2px 0 var(--brand); }

/* The number sits above the grip so it lines up with the first line of step text.
   The grip is invisible until hover but still occupies its box, so nothing shifts. */
.step .gutter { width: 30px; flex: none; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.step .num {
  width: 27px; height: 27px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand); font-size: 13px; font-weight: 700;
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
}
.step.is-note .num { background: var(--panel-2); color: var(--muted); border: 1px solid var(--line); }
.step .grip {
  color: var(--faint); cursor: grab; opacity: 0; padding: 2px;
  transition: opacity var(--fast);
}
.step .grip svg { width: 15px; height: 15px; }
.step:hover .grip { opacity: 1; }

.step .content { flex: 1; min-width: 0; }
.step .note-badge {
  display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--brand-2); background: var(--brand-soft);
  border-radius: 6px; padding: 3px 7px; margin-bottom: 7px;
}
/* Never `font: <size>/<lh> inherit` — that shorthand is invalid, fails silently,
   and a textarea then falls back to the UA default, which is monospace. */
.step textarea {
  width: 100%; border: 1px solid var(--line); background: var(--panel-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 10px 12px;
  font-family: inherit; font-size: 15.5px; font-weight: 550; line-height: 1.5;
  letter-spacing: -0.01em;
  outline: 0; resize: none; overflow: hidden;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.step textarea:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.step.is-note textarea { font-weight: 450; }

.step .shot {
  position: relative; margin-top: 11px; border: 1px solid var(--line);
  border-radius: var(--r); overflow: hidden; background: var(--panel-2); line-height: 0;
}
.step .shot canvas { width: 100%; height: auto; display: block; }
.step .shot.redacting { cursor: crosshair; }

/* ---- add a step here ----------------------------------------------------------
   A + between every pair of steps. Quiet until the row is hovered, because there is
   one of these between all thirteen steps and thirteen permanent buttons down the
   middle of the page would compete with the steps themselves. The row keeps its
   height either way, so nothing moves when it appears. */
.insert { height: 26px; display: flex; align-items: center; justify-content: center; position: relative; }
.insert::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  background: var(--brand); opacity: 0; transition: opacity var(--fast);
}
.insert:hover::before, .insert:focus-within::before { opacity: 0.35; }
.ins-btn {
  display: inline-flex; align-items: center; gap: 0; overflow: hidden;
  border: 1px dashed var(--line); background: var(--bg); color: var(--muted);
  border-radius: 999px; padding: 4px 8px; cursor: pointer; line-height: 1;
  font-size: 12.5px; font-weight: 620; z-index: 1;
  opacity: 0; transition: opacity var(--fast), color var(--fast), border-color var(--fast), background var(--fast);
}
.ins-btn svg { width: 14px; height: 14px; flex: none; }
.ins-btn .lbl {
  max-width: 0; white-space: nowrap; overflow: hidden;
  transition: max-width var(--fast), margin-left var(--fast);
}
.insert:hover .ins-btn, .ins-btn:focus-visible { opacity: 1; }
.insert:hover .ins-btn .lbl, .ins-btn:focus-visible .lbl { max-width: 140px; margin-left: 6px; }
.ins-btn:hover { color: var(--brand-2); border-color: var(--brand); background: var(--brand-soft); border-style: solid; }

/* ---- an icon button that grows into its label ---------------------------------
   "Redact" was a legal word for a picture-editing action. The icon is the blur tool
   every image editor draws as a droplet, and the label it expands into says what it
   does. The label is always in the DOM — it is the accessible name — so this is
   decoration on top of a button that is already readable to a screen reader.
   A `max-width` transition, not `display`, so a host page or a user setting that
   kills transitions degrades to an always-open label rather than to nothing. */
.btn.exp { overflow: hidden; }
.btn.exp .lbl {
  max-width: 0; white-space: nowrap; overflow: hidden;
  transition: max-width var(--fast), margin-left var(--fast);
}
.btn.exp:hover .lbl, .btn.exp:focus-visible .lbl, .btn.exp.open .lbl { max-width: 240px; margin-left: 7px; }

/* ---- the add/edit step dialog -------------------------------------------------- */
.modal .field label { display: block; font-size: 12px; font-weight: 650; color: var(--ink-2); margin-bottom: 6px; }
.modal .field label .opt { font-weight: 500; color: var(--faint); text-transform: none; letter-spacing: 0; }
.modal .field textarea {
  width: 100%; border: 1px solid var(--line); background: var(--panel-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 10px 12px; outline: 0; resize: vertical;
  font-family: inherit; font-size: 14.5px; line-height: 1.55;
}
.modal .field textarea:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.modal .drop {
  border: 1px dashed var(--line); border-radius: var(--r); background: var(--panel-2);
  padding: 14px; text-align: center; cursor: pointer;
  transition: border-color var(--fast), background var(--fast);
}
.modal .drop:hover, .modal .drop:focus-visible, .modal .drop.over {
  border-color: var(--brand); background: var(--brand-soft); outline: 0;
}
.modal .drop-empty { display: flex; flex-direction: column; align-items: center; gap: 7px; color: var(--muted); font-size: 13px; }
.modal .drop-empty svg { width: 22px; height: 22px; }
.modal .drop img {
  max-width: 100%; max-height: 210px; border-radius: var(--r-sm);
  border: 1px solid var(--line); display: block; margin: 0 auto 10px;
}

/* ---- the API log -------------------------------------------------------------
   A guide must not turn into a log file. A single-page app fires requests on
   nearly every click, so the inline view is sized by whether anything *failed*:
   a successful step gets one muted line that doesn't expand, a failed one gets
   the failures shown without asking. Everything, in full, lives in the drawer. */

/* The quiet case. Deliberately not a card, not bordered, not a heading — it reads
   as a footnote on the step, because that is what it is. */
.netquiet { margin-top: 8px; }
.netlink {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 3px 0; cursor: pointer;
  color: var(--faint); font: inherit; font-size: 12.5px;
}
.netlink:hover { color: var(--ink-2); text-decoration: underline; }
.netlink svg { flex: none; }

/* The failed case. Ochre left edge rather than a full tinted panel: enough to find
   at a glance while scrolling, not enough to outweigh the screenshot above it. */
.netlog {
  margin-top: 10px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--panel-2); font-size: 13px; overflow: hidden;
}
.netlog.bad { border-left: 3px solid var(--brand); }
.nethead {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; color: var(--ink-2);
}
.nethead svg { flex: none; color: var(--brand-2); }
.netrows { border-top: 1px solid var(--line); padding: 4px 0; }

/* A fixed-width method and status either side of a flexible path: the columns are
   what make a run of these scannable rather than a wall of text. The path is the
   only part allowed to shrink, and it truncates rather than wrapping — a wrapped
   path turns a 30-row log into 60 rows of ragged text. */
.netrow {
  display: flex; align-items: baseline; gap: 10px; padding: 5px 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px;
}
.netrow .m { flex: 0 0 44px; color: var(--faint); font-weight: 650; }
.netrow .p { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }
.netrow .s { flex: 0 0 auto; color: var(--muted); font-weight: 650; }
.netrow .t { flex: 0 0 52px; text-align: right; color: var(--faint); }
.netrow.bad .s { color: var(--brand-2); }

/* Response bodies clamp to ~9 lines with an explicit expander rather than scrolling
   inside the card. A nested scroll region inside a scrolling page is the worst
   pattern on the web, and a 200-line stack trace would otherwise own the viewport. */
.netbodywrap { margin: 2px 12px 10px; }
.netbody {
  margin: 0; padding: 9px 11px; border-radius: 8px;
  background: var(--bg-2); border: 1px solid var(--line);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.55; color: var(--ink-2);
  white-space: pre-wrap; overflow-wrap: anywhere; overflow: hidden;
}
/* An exact number of lines plus the padding, so the clamp lands between lines
   instead of slicing one in half. The fade is the honest signal that there is more
   below — a hard edge on a full line reads as the end of the response. */
.netbody.clamped {
  max-height: calc(8 * 1.55em + 20px);
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(180deg, #000 calc(100% - 22px), transparent);
}
.netbody.tall.clamped { max-height: calc(16 * 1.55em + 20px); }
.netbody.clamped.open {
  max-height: none;
  -webkit-mask-image: none;
  mask-image: none;
}
.netmore { margin-top: 6px; }
.netcut { margin-top: 5px; color: var(--faint); font-size: 11.5px; }

/* Two blocks can sit under one request — the cURL of what was sent, then what came
   back — so each needs a label. Without one they read as a single wall of monospace
   with no seam, which is exactly the "filled with logs" failure this feature has to
   avoid. The label is small and quiet: it is a seam, not a heading. */
.netdetail:empty { display: none; }
/* The peek button. Quiet until hovered, and it sits at the end of the status line
   rather than under it — a row of forty requests has to stay one line each, or the
   drawer becomes the wall the inline view was designed to avoid. */
.netpeek {
  all: unset; box-sizing: border-box; cursor: pointer; flex: 0 0 auto;
  margin-left: 2px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel);
  font: 600 11px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .02em; color: var(--muted);
  transition: color var(--fast), background var(--fast), border-color var(--fast);
}
.netpeek:hover { color: var(--ink); background: var(--panel-2); border-color: var(--faint); }
.netrow.bad .netpeek { border-color: var(--brand-ring); color: var(--brand-2); }
.netitem + .netitem { border-top: 1px solid var(--line); }
.netdetail .netbodywrap + .netbodywrap { margin-top: -4px; }
.netblockhead {
  display: flex; align-items: center; gap: 8px; margin: 0 0 4px;
}
.netblocklabel {
  font-size: 11px; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--faint);
}
.netblockhead .btn { padding: 2px 8px; font-size: 11.5px; }

.netfoot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-top: 1px solid var(--line);
}
.netnote { color: var(--faint); font-size: 12px; }
.btn.has-bad #ed-netlog-label { color: var(--brand-2); font-weight: 650; }

/* ---- the drawer --------------------------------------------------------------
   Wider than a confirm dialog, because monospace rows in a 540px column truncate
   to uselessness. The list scrolls inside a bounded region while the dialog itself
   stays put — the one place a nested scroll is right, since the alternative is a
   dialog taller than the screen with its Done button below the fold. */
.modal.wide { max-width: 880px; }
.netsum { margin: 4px 0 14px; color: var(--muted); font-size: 14px; }
.netbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.netfilter { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-size: 13.5px; color: var(--ink-2); }
.netfilter input { width: 15px; height: 15px; accent-color: var(--pri); }
.netfilter input:disabled + span { color: var(--faint); }
.netscroll {
  max-height: min(58vh, 560px); overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel-2);
}
.netgrp { border-bottom: 1px solid var(--line); padding-bottom: 6px; }
.netgrp:last-child { border-bottom: 0; }
/* Sticky group header, so you always know which step the rows under your cursor
   belong to while scrolling a long log. */
.netgrph {
  display: flex; align-items: center; gap: 9px; padding: 9px 12px;
  position: sticky; top: 0; z-index: 1;
  background: var(--panel); border-bottom: 1px solid var(--line);
}
.netgrph .n {
  flex: none; width: 21px; height: 21px; border-radius: 50%;
  background: var(--brand-soft); color: var(--brand-2);
  font-size: 11.5px; font-weight: 700; display: grid; place-items: center;
}
.netgrph .tx {
  flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 650; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.netmoreline { padding: 4px 12px 6px; color: var(--faint); font-size: 12px; }

@media (max-width: 560px) {
  /* The timing column is the first thing worth losing when there is no room for
     the path — a truncated endpoint is useless, 180ms is a nicety. */
  .netrow .t { display: none; }
  .netrow .m { flex: 0 0 38px; }
  .netfilter input { width: 17px; height: 17px; }
}
.step .shot.redacting canvas { pointer-events: none; }
.step .shot .sel {
  display: none; position: absolute; z-index: 2;
  border: 2px solid var(--brand); background: rgba(194, 65, 12, 0.16);
  pointer-events: none;
}
.shot-skel {
  height: 210px; background: var(--panel-2);
  animation: pulse-skel 1.3s ease-in-out infinite;
}
.step figure.baked {
  margin: 11px 0 0; border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; background: var(--panel-2); line-height: 0; position: relative;
}
.step figure.baked img { width: 100%; }
.step figure.baked:not(.gone)::after {
  content: "annotations baked in";
  position: absolute; top: 8px; right: 8px;
  background: rgba(26, 23, 19, 0.74); color: #fbfaf7;
  font-size: 10.5px; font-weight: 650; letter-spacing: 0.03em;
  padding: 3px 7px; border-radius: 5px; line-height: 1.3;
}
.step .no-img { margin: 9px 0 0; font-size: 12.5px; color: var(--faint); line-height: 1.5; }

.step .rowtools { display: flex; align-items: center; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.step .rowtools .spacer { flex: 1; }

/* ---------- toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 14px);
  max-width: calc(100vw - 32px); text-align: center;
  background: var(--pri); color: var(--pri-fg);
  padding: 11px 17px; border-radius: 999px; font-size: 13.5px; font-weight: 550;
  box-shadow: var(--sh-3); z-index: 90;
  opacity: 0; pointer-events: none;
  transition: opacity var(--fast), transform var(--fast);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ---------- modal ---------- */
/* Flex + `margin: auto` rather than grid + place-items, because a grid item taller
   than its area is centred and then clipped at BOTH ends with no way to scroll to
   it — the share dialog's buttons were unreachable on a 420px-tall viewport. Auto
   margins centre a flex item only while it fits, and `overflow-y: auto` takes over
   once it doesn't. */
.overlay {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(21, 19, 15, 0.55); backdrop-filter: blur(2px);
  display: none; align-items: center; justify-content: center;
  padding: 24px; overflow-y: auto; overscroll-behavior: contain;
}
.overlay.open { display: flex; }
.modal {
  /* 540, not 470: the share dialog's action row is five buttons and a spacer, which
     measures 481px including its gaps. At 470 it wrapped to a second line on a
     desktop too — wide enough for the widest row this dialog has, and no wider. */
  width: 100%; max-width: 540px; margin: auto;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--sh-3); padding: 22px;
}
.modal h3 { margin: 0 0 7px; font-size: 18px; font-weight: 660; letter-spacing: -0.02em; }
.modal p { margin: 0 0 16px; color: var(--muted); font-size: 14px; line-height: 1.6; }
/* The share dialog's row is five buttons wide. Unwrapped, it set the modal's
   min-content width to ~470px whatever the screen was: below that the dialog hung
   off the right edge of the viewport and Update and Copy link could not be reached
   at all. It must wrap, and the wrapped line right-aligns so the primary action
   stays where the eye already is. */
.modal .row {
  display: flex; gap: 8px; align-items: center; margin-top: 18px;
  flex-wrap: wrap; row-gap: 8px; justify-content: flex-end;
}
/* `flex: 1 1 0` not `flex: 1` — a wrapping spacer must not claim a whole line. */
.modal .row .spacer { flex: 1 1 0; min-width: 0; }
/* Below this, five side-by-side buttons are unreadable however they wrap. Stack
   them full width, reversed so the primary action is at the top and the dismiss is
   furthest from the thumb's resting position. */
@media (max-width: 460px) {
  .modal .row { flex-direction: column-reverse; align-items: stretch; }
  .modal .row .spacer { display: none; }
}
/* The extension used to style its own copy of this form; the two surfaces don't
   share CSS, so a control that exists on both has to be styled in both places. */
.modal .field { margin-bottom: 13px; }
.modal .field input {
  width: 100%; border: 1px solid var(--line); background: var(--panel-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 10px 12px; font: inherit; font-size: 14px; outline: 0;
}
.modal .field input:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.modal .field-label { display: block; font-size: 12px; font-weight: 650; color: var(--ink-2); margin-bottom: 6px; }
.modal .hint { font-size: 12.5px; color: var(--muted); margin-top: 8px; line-height: 1.5; }
.modal .status-line { font-size: 13px; color: var(--muted); min-height: 18px; margin-top: 10px; line-height: 1.5; }

.segmented { display: flex; gap: 4px; background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 3px; }
.segmented button {
  flex: 1; border: 0; background: none; color: var(--ink-2);
  padding: 7px 10px; border-radius: 7px; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.segmented button[aria-pressed="true"] { background: var(--panel); color: var(--ink); box-shadow: var(--sh-1); }

.switch { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 16px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 38px; height: 22px; border-radius: 999px; background: var(--line);
  position: relative; flex: none; margin-top: 2px; transition: background var(--fast);
}
.switch .track::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px; border-radius: 50%; background: var(--panel);
  transition: transform var(--fast);
}
.switch input:checked + .track { background: var(--pri); }
.switch input:checked + .track::after { transform: translateX(16px); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--brand-ring); }
.switch .label { display: flex; flex-direction: column; font-size: 14px; }
.switch .label small { color: var(--muted); font-size: 12.5px; margin-top: 2px; line-height: 1.45; }

.progress { height: 6px; border-radius: 999px; background: var(--panel-2); overflow: hidden; margin-top: 14px; }
.progress > div { height: 100%; width: 0; background: var(--brand); transition: width 200ms linear; }

/* Keep new motion inside the reduced-motion contract. */
@media (prefers-reduced-motion: reduce) {
  .toast, .progress > div, .step .grip, .switch .track, .switch .track::after { transition: none !important; }
  .shot-skel, .skel, .vskel { animation: none !important; }
}

/* ---------- theme toggle ---------- */
/* Three states shown at once rather than a cycling button: a single icon that
   rotates through light -> dark -> auto never tells you what pressing it will do. */
.theme-toggle {
  display: flex; gap: 2px; margin-left: auto;
  padding: 2px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel-2);
}
header.site nav { margin-left: 10px; }
.theme-toggle button {
  width: 27px; height: 27px; padding: 0; flex: none;
  display: grid; place-items: center; cursor: pointer;
  border: 0; background: none; border-radius: 999px;
  color: var(--faint);
  transition: color var(--fast), background var(--fast);
}
.theme-toggle button svg { width: 14px; height: 14px; }
.theme-toggle button:hover { color: var(--ink-2); }
.theme-toggle button[aria-pressed="true"] {
  background: var(--panel); color: var(--ink); box-shadow: var(--sh-1);
}
.theme-toggle button:focus-visible {
  outline: 0; box-shadow: 0 0 0 3px var(--brand-ring);
}
/* On a narrow screen the wordmark, the toggle and the account row won't all fit on one
   line — and left to wrap on their own they took three, because the toggle and the nav
   each spilled in turn (133px of sticky header on a 320px screen, measured). So pin the
   arrangement instead: wordmark and toggle share the first line, nav gets the second.
   Two rows, always, whatever the nav happens to contain.

   The toggle stays three visible buttons rather than collapsing to one cycling icon —
   see the theme-toggle note above; a rotating icon never says what pressing it does. */
@media (max-width: 560px) {
  /* `height` had to become `min-height`: a wrapped row is taller than 62px, and a
     fixed height let the second line spill through the header's bottom border. */
  header.site .row { flex-wrap: wrap; row-gap: 6px; height: auto; min-height: 62px; padding-block: 9px; }
  .theme-toggle { order: 0; margin-left: auto; }
  header.site nav { order: 1; flex-basis: 100%; margin-left: 0; }
}
/* The landing header carries five items — three of them jump links to sections the
   reader scrolls through anyway. All five plus the wordmark and the theme toggle need
   about 660px; below that they wrap to a second line, and at 320px they pushed the
   Install button past the right edge and gave the page a horizontal scrollbar. Sign
   in and Install are the two that go somewhere, so they are the two that stay.
   760, not 560: the wrap starts long before the overflow does. */
@media (max-width: 760px) {
  header.site nav a[href^="#"] { display: none; }
}

/* ---------- touch and small screens ---------- */

/* The header is sticky, so an in-page jump lands the target under it. Sections have
   62px of their own top padding, which covers it at desktop widths by one pixel —
   but the header wraps to two lines below 560px and then genuinely hides the
   heading. Cheap insurance either way. */
section[id] { scroll-margin-top: 80px; }

/* iOS Safari zooms the whole page in when a focused control's text is under 16px,
   and does not zoom back out. Every form control here was between 14 and 15.5px. */
@media (max-width: 560px) {
  .field input, .modal .field input, .wl input[type=email], .step textarea { font-size: 16px; }
}

/* Hover is the wrong sense to design for on a touch screen, and 27px is the wrong
   size to hit with a thumb. Keyed on the pointer, not the width, because a small
   window on a desktop still has a mouse. */
@media (pointer: coarse) {
  .btn.sm { padding: 9px 13px; }
  .btn.icon { padding: 11px; }
  .btn.icon.sm { padding: 10px; }
  .theme-toggle button { width: 34px; height: 34px; }
  .theme-toggle button svg { width: 15px; height: 15px; }
  .link-btn { padding: 6px 2px; }
  header.site nav a { padding: 9px 11px; }
  /* The drag grip is opacity 0 until :hover, which on a touch device is never — the
     reorder handle was invisible and undiscoverable there. */
  .step .grip { opacity: 1; padding: 7px; }
}

/* Drawing a redaction box is a pointer drag, so the browser must not claim the
   gesture for scrolling while redaction mode is on. */
.step .shot.redacting { touch-action: none; }

/* A URL or a storage key in a legal document is one long unbreakable token. */
.doc code, .doc td { overflow-wrap: anywhere; }

/* ---------- export activity (owner) ---------- */
.activity {
  margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--line);
}
.activity h2 { font-size: 15.5px; font-weight: 660; margin: 0 0 4px; letter-spacing: -0.015em; }
.activity .act-empty { color: var(--muted); font-size: 13.5px; margin: 0 0 12px; line-height: 1.55; max-width: 70ch; }
.act-list { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.act-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 13px; font-size: 13.5px;
  border-top: 1px solid var(--line); background: var(--panel);
}
.act-row:first-child { border-top: 0; }
.act-row .who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
.act-row .kind {
  flex: none; font-size: 11px; font-weight: 650; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--brand-2); background: var(--brand-soft);
  padding: 3px 7px; border-radius: 5px;
}
.act-row .when { flex: none; color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* ---------- consent notice (viewer sign-in) ---------- */
/* Deliberately not styled as a warning. It is a plain statement of what the owner
   will see, and dressing it as an alert would make an honest disclosure look like
   a problem. */
.consent {
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 11px 13px; margin: 0 0 15px;
  font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
}
.consent b { color: var(--ink); }

/* The viewer's export menu hangs off the header, which is sticky and sits above
   the page — so it needs to escape rather than be clipped. */
header.site .menu-wrap .menu { top: calc(100% + 8px); }

/* A 262px menu anchored to its button can't be kept on screen by CSS alone: the
   editor's Export button sits mid-row, and `right: 0` sent the menu to x=-104 at
   320px — the format labels were off the left edge. The old fix here was
   `right: -60px` on the viewer's copy, which trades one edge for the other.
   So below 560px the menu stops being a dropdown and becomes a sheet pinned to the
   viewport, which no button position can push out of view. z-index clears the
   sticky header (30) and stays under the modal overlay (80). */
@media (max-width: 560px) {
  .menu {
    position: fixed; z-index: 40;
    top: auto; bottom: 10px; left: 10px; right: 10px;
    min-width: 0; max-height: 72vh; overflow-y: auto;
  }
  header.site .menu-wrap .menu { top: auto; }
  .menu button { padding: 11px 9px; }
}

/* ---------- install page ---------- */
.install .updated { margin-bottom: 26px; }
.dl {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  border: 1px solid var(--line); background: var(--panel);
  border-radius: var(--r-lg); padding: 20px 22px; margin: 26px 0 34px;
  box-shadow: var(--sh-1);
}
.dl .dl-main { flex: 1; min-width: 220px; }
.dl .dl-h { font-size: 17px; font-weight: 660; margin: 0 0 4px; letter-spacing: -0.018em; }
.dl .dl-sub { margin: 0; color: var(--muted); font-size: 13.5px; line-height: 1.55; }

/* Numbered steps. counter-reset on the list rather than a marker, so the number can
   sit in an ochre disc without the browser's own list styling fighting it. */
.steps-num { list-style: none; counter-reset: st; padding: 0; margin: 0 0 30px; }
.steps-num > li {
  counter-increment: st; position: relative;
  padding: 0 0 16px 42px; color: var(--ink-2); line-height: 1.65;
}
.steps-num > li::before {
  content: counter(st);
  position: absolute; left: 0; top: 1px;
  width: 27px; height: 27px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand);
  font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
  display: grid; place-items: center;
}
.steps-num > li b { color: var(--ink); font-weight: 650; }
.steps-num.tight > li { padding-bottom: 9px; }

/* A callout that needs to be read, not skimmed past. Warm rather than red — it's a
   consequence to understand, not an error. */
/* Two weights of callout, because a page with two identical tinted boxes has no
   emphasis — it just has two boxes. `.note` is context you can skim; the default
   brand tint is the one that has to be read. `.warn` is the default plus a solid
   accent bar, for the one consequence on a page that will cost someone data. */
.doc .callout.note {
  background: var(--panel-2);
  border-color: var(--line);
}
.doc .callout.warn {
  border-left: 4px solid var(--brand);
  border-top-left-radius: 3px; border-bottom-left-radius: 3px;
}
.doc .callout.warn > p:first-child { color: var(--ink); }
.install .closing {
  margin-top: 34px; padding-top: 20px; border-top: 1px solid var(--line);
  color: var(--muted); font-size: 14px;
}
.dl .dl-pending {
  flex: 1 1 260px; margin: 0; font-size: 13.5px; line-height: 1.55;
  color: var(--ink-2); background: var(--panel-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 11px 13px;
}

/* ---------- Google sign-in ---------- */
/* Google's brand guidelines want their own mark and a neutral surface — so this is
   deliberately NOT the ink primary button. It's a peer to the form below it, not a
   louder version of it. */
.google-btn {
  width: 100%; justify-content: center; gap: 10px;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); font-weight: 600;
}
.google-btn:hover { background: var(--panel-2); }
.google-btn svg { flex: none; }
.or {
  display: flex; align-items: center; gap: 12px;
  margin: 16px 0; color: var(--faint); font-size: 12px;
}
.or::before, .or::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
.modal .google-btn { margin-bottom: 0; }

/* ============================================================ the house page
   backpocket.website — the apex. Same tokens as everything else; no new palette.
   The demo is the only genuinely new component, and it is deliberately built out of
   the same primitives (cards, brand ring, warm paper) so the page looks like the
   product it is advertising rather than like a landing-page template. */
.house-hero { padding-bottom: 26px; }
.house-hero .lede { max-width: 58ch; }

/* ---- the interactive demo ---- */
.demo {
  display: grid; gap: 18px; align-items: start;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
}
@media (max-width: 900px) { .demo { grid-template-columns: 1fr; } }

/* the pretend app */
.demo-app {
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden;
  background: var(--panel); box-shadow: var(--sh-1);
}
.da-top {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 12px; background: var(--panel-2); border-bottom: 1px solid var(--line);
}
.da-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--faint); opacity: 0.45; }
.da-url {
  margin-left: 10px; font-size: 11.5px; color: var(--muted);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 10px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.da-body { display: grid; grid-template-columns: 148px minmax(0, 1fr); min-height: 268px; }
@media (max-width: 560px) { .da-body { grid-template-columns: 108px minmax(0, 1fr); } }
.da-side { border-right: 1px solid var(--line); padding: 10px; display: flex; flex-direction: column; gap: 4px; }
.da-nav {
  text-align: left; border: 1px solid transparent; background: none; cursor: pointer;
  color: var(--ink-2); font: inherit; font-size: 12.5px; font-weight: 560;
  padding: 7px 9px; border-radius: var(--r-sm);
}
.da-nav:hover { background: var(--panel-2); color: var(--ink); }
.da-nav.on { background: var(--brand-soft); color: var(--brand-2); font-weight: 650; }
.da-main { padding: 13px; display: flex; flex-direction: column; gap: 10px; }
.da-row { display: flex; gap: 8px; }
.da-input {
  flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink); font: inherit; font-size: 13px;
  padding: 8px 11px; outline: 0;
}
.da-input:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.da-btn {
  border: 1px solid transparent; background: var(--pri); color: var(--pri-fg);
  font: inherit; font-size: 12.5px; font-weight: 620; cursor: pointer;
  padding: 8px 13px; border-radius: var(--r-sm); white-space: nowrap;
}
.da-btn.ghost { background: var(--panel); color: var(--ink-2); border-color: var(--line); }
.da-btn.ghost:hover { background: var(--panel-2); color: var(--ink); }
.da-card {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel-2);
  padding: 10px 12px; font-size: 13px; cursor: pointer;
}
.da-card:hover { border-color: var(--faint); }
.da-card b { display: block; font-size: 13px; }
.da-muted { color: var(--muted); font-size: 11.5px; }
.da-check {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px;
  color: var(--ink-2); cursor: pointer; padding: 6px 2px;
}

/* the guide building itself */
.demo-out {
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel);
  box-shadow: var(--sh-1); display: flex; flex-direction: column; overflow: hidden;
}
.demo-out-top {
  display: flex; align-items: center; gap: 9px; padding: 10px 13px;
  border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.demo-out-top .spacer { flex: 1; }
.do-title { font-size: 13px; font-weight: 660; }
.do-count { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.demo-steps { padding: 13px; display: flex; flex-direction: column; gap: 11px; max-height: 420px; overflow-y: auto; }
.demo-empty {
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  padding: 52px 18px; color: var(--faint); text-align: center;
}
.demo-empty svg { width: 26px; height: 26px; }
.demo-empty p { margin: 0; font-size: 13.5px; }
.demo-step { display: flex; gap: 11px; }
.demo-step .ds-n {
  width: 23px; height: 23px; min-width: 23px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand);
  font-size: 11.5px; font-weight: 700; display: grid; place-items: center;
  font-variant-numeric: tabular-nums;
}
.demo-step .ds-b { flex: 1; min-width: 0; }
.demo-step .ds-t { margin: 2px 0 0; font-size: 14px; font-weight: 560; line-height: 1.45; }

/* A step's picture: the mock cloned, shrunk, ringed. `zoom` rather than transform so it
   takes its own space in the flow — a scaled element keeps its original box and would
   leave a hole four times its height underneath. */
.shot-mini {
  margin-top: 8px; border: 1px solid var(--line); border-radius: var(--r-sm);
  overflow: hidden; background: var(--panel-2);
}
.shot-mini-in { position: relative; zoom: 0.44; pointer-events: none; }
.shot-mini-in .demo-app { border: 0; border-radius: 0; box-shadow: none; }
.shot-ring {
  position: absolute; border: 3px solid var(--brand); border-radius: 6px;
  box-shadow: 0 0 0 3px var(--brand-ring);
}
.demo-out-foot {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  padding: 12px 13px; border-top: 1px solid var(--line); background: var(--panel-2);
}
.demo-hint { font-size: 12px; color: var(--muted); }
.demo-note { margin-top: 20px; color: var(--muted); font-size: 14px; max-width: 74ch; }

/* ---- the tools grid ---- */
.tools-grid { align-items: start; }
.card.tool { display: flex; flex-direction: column; }
.card.tool .tool-top { margin-bottom: 9px; }
.tool-badge {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--muted); background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 6px; padding: 3px 7px;
}
.tool-badge.live { color: var(--on-brand); background: var(--brand); border-color: transparent; }
.card.tool.live { border-color: var(--brand); }
.tool-acts { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 13px; align-items: center; }
.vote-form { display: flex; gap: 6px; flex-wrap: wrap; width: 100%; }
.vote-form input {
  flex: 1; min-width: 140px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink); font: inherit; font-size: 13px;
  padding: 7px 10px; outline: 0;
}
.vote-form input:focus { border-color: var(--brand); background: var(--panel); box-shadow: 0 0 0 3px var(--brand-ring); }
.voted { font-size: 12.5px; font-weight: 600; color: var(--brand-2); }

/* ---- share ---- */
.share { margin-top: 40px; padding-top: 26px; border-top: 1px solid var(--line); }
.share-lbl { display: block; font-size: 14px; color: var(--muted); margin-bottom: 11px; }
.share-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.built { margin-top: 34px; font-size: 13.5px; color: var(--faint); }
