/* ============================================================================
   OOBSecret - mockup v1
   Design language: awesome-design-md / vercel (DESIGN.md)

   Deviations from the source DESIGN.md, all deliberate:
   1. Geist + Geist Mono are loaded as the real faces. The DESIGN.md calls them
      proprietary and suggests Inter / JetBrains Mono substitutes - but Vercel
      released both under the SIL OFL, so the genuine faces are used instead.
   2. The brand's hero mesh gradient is omitted. The file scopes it to hero
      scale and forbids reducing it; decorative colour undercuts a security
      tool, so depth comes from the brand's other documented cue instead -
      polarity-flipped ink bands.
   3. Button/input radius is held at the 6px app scale (--geist-radius) rather
      than the 100px marketing pill. The don'ts forbid mixing the two scales on
      one screen, and this page is a tool, not a marketing band.
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap');

/* ---- tokens ------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* colour - verbatim from DESIGN.md frontmatter */
  --ink: #171717;
  --on-ink: #ffffff;
  --body: #4d4d4d;
  /* DESIGN.md says #888888, which is 3.54:1 on white and 3.40:1 on canvas-soft -
     under the 4.5:1 AA floor for the 12px captions that use it. Raised to the
     lightest grey that clears AA on all three light surfaces. Dark needs no such
     fix: its #8f8f8f is already 6.12:1. */
  --mute: #707070;
  --hairline: #ebebeb;
  --hairline-strong: #a1a1a1;
  --canvas: #ffffff;
  --canvas-soft: #fafafa;
  --canvas-soft-2: #f5f5f5;
  --link: #0070f3;
  --link-deep: #0761d1;
  --link-bg-soft: #d3e5ff;
  --error: #ee0000;
  --error-soft: #f7d4d6;
  --error-deep: #c50000;
  --warning: #f5a623;
  --warning-soft: #ffefcf;
  --warning-deep: #ab570a;

  /* Inverse surface: the polarity-flipped band and the revealed-secret block.
     Stays dark in BOTH themes - in light it is the brand's depth cue, in dark
     it is a raised panel. That keeps the white-alpha text on it valid either way. */
  --invert-bg: #171717;
  --invert-fg: #ffffff;

  /* Success green. #15803d gives white label text 5.02:1; the more obvious
     #16a34a only manages 3.30:1 and fails AA at button size. */
  --success: #15803d;
  --success-hover: #126633;
  --on-success: #ffffff;

  --primary-hover: #000000;
  --danger-wash: #fff5f5;
  --focus-ring: #17171712;
  --ring: #00000014;            /* inset hairline used by the elevation stack */

  /* type */
  --sans: 'Geist', Inter, system-ui, -apple-system, sans-serif;
  --mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;

  /* spacing - 4px base */
  --s-xxs: 4px;  --s-xs: 8px;   --s-sm: 12px;  --s-md: 16px;
  --s-lg: 24px;  --s-xl: 32px;  --s-2xl: 40px; --s-3xl: 48px;
  --s-4xl: 64px; --s-5xl: 96px;

  /* radius */
  --r-xs: 4px; --r-sm: 6px; --r-md: 8px; --r-lg: 12px; --r-full: 9999px;

  /* elevation - stacked, never a single heavy drop */
  --shadow-1: #00000005;
  --shadow-2: #0000000a;
  --e1: 0 0 0 1px var(--ring) inset;
  --e2: 0 1px 1px var(--shadow-1), 0 2px 2px var(--shadow-2), 0 0 0 1px var(--ring) inset;
  --e3: 0 2px 2px var(--shadow-2), 0 8px 8px -8px var(--shadow-2), 0 0 0 1px var(--ring) inset;
  --e4: 0 2px 2px var(--shadow-2), 0 8px 16px -4px var(--shadow-2), 0 0 0 1px var(--ring) inset;

  --page: 1100px;
}

/* ---- dark theme ---------------------------------------------------------
   Values follow Vercel's own dark scale (Geist): near-black canvas, #ededed
   ink, and a CTA that flips to light-on-dark. Declared twice on purpose - once
   for the system preference (unless the user forced light) and once for the
   explicit toggle - so both directions win over the other.
   ------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ink: #ededed;
    --on-ink: #0a0a0a;
    --body: #a1a1a1;
    --mute: #8f8f8f;
    --hairline: #2e2e2e;
    --hairline-strong: #454545;
    --canvas: #0a0a0a;
    --canvas-soft: #141414;
    --canvas-soft-2: #1f1f1f;
    --link: #3291ff;
    --link-deep: #52a8ff;
    --link-bg-soft: #10253f;
    --error: #ff6369;
    --error-soft: #3c1618;
    --error-deep: #ff6369;
    --warning: #ffb224;
    --warning-soft: #35280d;
    --warning-deep: #ffb224;
    --invert-bg: #1c1c1c;
    --invert-fg: #ededed;
    --success: #3ecf8e;
    --success-hover: #5ad9a0;
    --on-success: #0a0a0a;
    --primary-hover: #ffffff;
    --danger-wash: #2a1416;
    --focus-ring: #ededed1f;
    --ring: #ffffff17;
    --shadow-1: #00000040;
    --shadow-2: #00000059;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --ink: #ededed;
  --on-ink: #0a0a0a;
  --body: #a1a1a1;
  --mute: #8f8f8f;
  --hairline: #2e2e2e;
  --hairline-strong: #454545;
  --canvas: #0a0a0a;
  --canvas-soft: #141414;
  --canvas-soft-2: #1f1f1f;
  --link: #3291ff;
  --link-deep: #52a8ff;
  --link-bg-soft: #10253f;
  --error: #ff6369;
  --error-soft: #3c1618;
  --error-deep: #ff6369;
  --warning: #ffb224;
  --warning-soft: #35280d;
  --warning-deep: #ffb224;
  --invert-bg: #1c1c1c;
  --invert-fg: #ededed;
  --success: #3ecf8e;
  --success-hover: #5ad9a0;
  --on-success: #0a0a0a;
  --primary-hover: #ffffff;
  --danger-wash: #2a1416;
  --focus-ring: #ededed1f;
  --ring: #ffffff17;
  --shadow-1: #00000040;
  --shadow-2: #00000059;
}

/* ---- reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font: 400 16px/24px var(--sans);
  -webkit-font-smoothing: antialiased;
}
img, svg { max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; border-radius: var(--r-xs); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- icons (Lucide, inlined in icons.js) -------------------------------- */
.icon { width: 16px; height: 16px; display: block; flex: none; }
.icon-sm .icon { width: 12px; height: 12px; }
/* wrappers are inline-flex so an icon sits on the text baseline row, not below it */
[data-icon], .lockline > span, .pane__name > span:first-child {
  display: inline-flex; align-items: center; flex: none;
}
.btn .icon { margin-right: -2px; }

/* ---- type scale --------------------------------------------------------- */
.display-xl { font-size: 48px; line-height: 48px; font-weight: 600; letter-spacing: -2.4px; margin: 0; }
.display-lg { font-size: 32px; line-height: 40px; font-weight: 600; letter-spacing: -1.28px; margin: 0; }
.display-md { font-size: 24px; line-height: 32px; font-weight: 600; letter-spacing: -0.96px; margin: 0; }
.display-sm { font-size: 20px; line-height: 28px; font-weight: 600; letter-spacing: -0.6px; margin: 0; }
.body-lg { font-size: 18px; line-height: 28px; margin: 0; }
.body-sm { font-size: 14px; line-height: 20px; letter-spacing: -0.28px; margin: 0; }
.caption { font-size: 12px; line-height: 16px; margin: 0; }
.eyebrow {
  font: 400 12px/16px var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mute);
  margin: 0;
}
.muted { color: var(--body); }
.faint { color: var(--mute); }

/* ---- layout ------------------------------------------------------------- */
.wrap {
  max-width: var(--page);
  margin: 0 auto;
  padding-inline: var(--s-lg);
}

/* ---- nav ---------------------------------------------------------------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  height: 64px;
  /* Solid, per the DESIGN.md nav-bar spec. A translucent nav turns muddy grey
     where it crosses the polarity-flipped ink band and ghosts the text under it. */
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
}
.nav__inner { display: flex; align-items: center; gap: var(--s-md); height: 64px; }
.brand {
  display: flex; align-items: center; gap: var(--s-xs);
  font-weight: 600; letter-spacing: -0.4px;
  color: var(--ink); text-decoration: none;
}
/* The acronym carries the weight; "Share" recedes to 500 so "OOB" reads as a unit. */
.brand__word b { font-weight: 600; }
.brand__word { font-weight: 500; }
.brand__mark {
  display: inline-grid; place-items: center;
  width: 28px; height: 28px;
  background: var(--ink); color: var(--on-ink);
  border-radius: var(--r-sm);
}
.nav__links { display: flex; gap: var(--s-xxs); margin-left: auto; }
.nav__link {
  display: inline-flex; align-items: center;
  padding: var(--s-xs) var(--s-sm);
  border-radius: var(--r-full);
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  color: var(--body); text-decoration: none;
  transition: background .15s, color .15s;
}
.nav__link:hover { background: var(--canvas-soft-2); color: var(--ink); }

/* theme toggle - shows the theme you'd switch TO */
.icon-btn {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px; margin-left: var(--s-xxs);
  padding: 0;
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  color: var(--body);
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.icon-btn:hover { background: var(--canvas-soft-2); color: var(--ink); border-color: var(--hairline-strong); }
.theme-icon { display: none; grid-area: 1 / 1; }
:root:not([data-theme="dark"]) .theme-icon--in-light { display: inline-flex; }
:root[data-theme="dark"] .theme-icon--in-dark { display: inline-flex; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-icon--in-light { display: none; }
  :root:not([data-theme="light"]) .theme-icon--in-dark { display: inline-flex; }
  :root[data-theme="light"] .theme-icon--in-light { display: inline-flex; }
}

/* ---- buttons - app scale, 6px ------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-xs);
  height: 40px; padding: 0 var(--s-md);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-size: 14px; font-weight: 500; line-height: 20px;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, opacity .15s;
  white-space: nowrap;
  text-decoration: none;          /* .btn is used on <a> as well as <button> */
}
.btn--primary { background: var(--ink); color: var(--on-ink); }
.btn--primary:hover { background: var(--primary-hover); }
.btn--primary:disabled { background: var(--canvas-soft-2); color: var(--mute); cursor: not-allowed; }
.btn--secondary { background: var(--canvas); color: var(--ink); border-color: var(--hairline); }
.btn--secondary:hover { border-color: var(--hairline-strong); }
.btn--danger { background: var(--canvas); color: var(--error-deep); border-color: color-mix(in srgb, var(--error) 35%, transparent); }
.btn--danger:hover { background: var(--danger-wash); border-color: var(--error); }
.btn--lg { height: 48px; padding: 0 var(--s-lg); font-size: 16px; line-height: 24px; }
.btn--block { width: 100%; }

/* ---- hero --------------------------------------------------------------- */
.hero { padding-block: var(--s-2xl) var(--s-lg); text-align: center; }
.hero__badge {
  display: inline-flex; align-items: center; gap: var(--s-xs);
  padding: 6px var(--s-sm);
  background: var(--canvas-soft);
  border: 1px solid var(--hairline);
  border-radius: var(--r-full);
  font: 400 12px/16px var(--mono);
  color: var(--body);
  margin-bottom: var(--s-lg);
}
.hero__badge .dot {
  width: 6px; height: 6px; border-radius: var(--r-full);
  background: var(--link);
}
.hero h1 { max-width: 16ch; margin-inline: auto; }
.hero__sub { max-width: 54ch; margin: var(--s-md) auto 0; color: var(--body); }

/* ---- the app card ------------------------------------------------------- */
.app {
  max-width: 760px; margin: var(--s-lg) auto 0;
  background: var(--canvas);
  border-radius: var(--r-lg);
  box-shadow: var(--e4);
  padding: var(--s-lg);
}
/* Desktop padding came down to 24px, which this override already was - so it
   goes one step further rather than sitting here doing nothing. */
@media (max-width: 599px) { .app { padding: var(--s-md); } }

.field { display: block; margin-bottom: var(--s-md); }
.field__label { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--s-xs); }
.field__label span:first-child { font-size: 14px; font-weight: 500; line-height: 20px; }

.secret-input {
  width: 100%;
  min-height: 148px;
  padding: var(--s-sm);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  font: 400 13px/20px var(--mono);
  color: var(--ink);
  resize: vertical;
  transition: border-color .15s, box-shadow .15s;
}
.secret-input::placeholder { color: var(--mute); }
.secret-input:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--focus-ring); }

/* segmented controls */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-lg); }
@media (max-width: 599px) { .grid-2 { grid-template-columns: 1fr; gap: var(--s-md); } }

.segmented {
  display: flex;
  background: var(--canvas-soft-2);
  border-radius: var(--r-sm);
  padding: 3px;
  gap: 2px;
}
.segmented button {
  flex: 1;
  height: 32px;
  border: 0; background: transparent;
  border-radius: var(--r-xs);
  font-size: 13px; font-weight: 500; line-height: 20px;
  color: var(--body);
  cursor: pointer;
  transition: background .15s, color .15s, box-shadow .15s;
}
.segmented button:hover { color: var(--ink); }
.segmented button[aria-pressed="true"] {
  background: var(--canvas);
  color: var(--ink);
  box-shadow: 0 1px 1px var(--shadow-1), 0 0 0 1px var(--ring);
}

/* passphrase */
.toggle-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-md);
  padding: var(--s-sm) 0;
}
.toggle-row__text { min-width: 0; }
.switch {
  position: relative; flex: none;
  width: 40px; height: 24px;
  border: 0; padding: 0;
  background: var(--canvas-soft-2);
  box-shadow: 0 0 0 1px var(--ring) inset;
  border-radius: var(--r-full);
  cursor: pointer;
  transition: background .18s;
}
.switch::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 18px; height: 18px; border-radius: var(--r-full);
  background: var(--canvas);
  box-shadow: 0 1px 2px #00000029;
  transition: transform .18s;
}
/* Selected state uses the system's single accent. Green would be a sixth
   colour the design language forbids, and on a security product it would also
   imply "safe" about what are only settings. */
.switch[aria-checked="true"] { background: var(--link); }
.switch[aria-checked="true"]::after { transform: translateX(16px); }

.text-input {
  width: 100%; height: 40px;
  padding: 0 var(--s-sm);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  transition: border-color .15s, box-shadow .15s;
}
.text-input:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--focus-ring); }

.rule { height: 1px; background: var(--hairline); border: 0; margin: var(--s-lg) 0; }

/* ---- grouped options ---------------------------------------------------- */
/* The top margins here and on .app__footer replace two <hr class="rule">
   dividers that used to sit above them. The rules carried 24px either side, so
   the space has to come from somewhere or the sections butt together; without a
   drawn line, slightly less of it reads better. */
.group__legend {
  margin: var(--s-lg) 0 var(--s-xs);
  font-size: 14px; font-weight: 500; line-height: 20px;
}
.group {
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  overflow: hidden;
}
.group__row { padding: var(--s-sm) var(--s-md); }
.group__row + .group__row { border-top: 1px solid var(--hairline); }
/* rows in a group carry their own padding, so the row itself sheds its vertical padding */
.group__row .toggle-row { padding: 0; }

.app__footer { display: flex; align-items: center; justify-content: space-between; gap: var(--s-md); margin-top: var(--s-lg); }
.lockline { display: flex; align-items: center; gap: var(--s-xs); font: 400 12px/16px var(--mono); color: var(--mute); }
@media (max-width: 599px) {
  .app__footer { flex-direction: column; align-items: stretch; }
  .app__footer .btn { width: 100%; }
}

/* ---- result panel ------------------------------------------------------- */
[hidden] { display: none !important; }

.result__head { display: flex; align-items: flex-start; gap: var(--s-sm); margin-bottom: var(--s-lg); }
.result__check {
  flex: none; display: inline-grid; place-items: center;
  width: 32px; height: 32px; border-radius: var(--r-full);
  background: var(--link-bg-soft); color: var(--link-deep);
}

.linkbar {
  display: flex; align-items: center; gap: var(--s-xs);
  padding: var(--s-xs);
  background: var(--canvas-soft);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
}
.linkbar input {
  flex: 1; min-width: 0;
  height: 32px; padding: 0 var(--s-xs);
  background: transparent; border: 0;
  font: 400 13px/20px var(--mono);
  color: var(--ink);
  text-overflow: ellipsis;
}
.linkbar input:focus { outline: none; }
.btn--copy { height: 32px; padding: 0 var(--s-sm); font-size: 13px; }

.chips { display: flex; flex-wrap: wrap; gap: var(--s-xs); margin-top: var(--s-md); }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px var(--s-xs);
  background: var(--link-bg-soft);
  border: 1px solid color-mix(in srgb, var(--link) 30%, transparent);
  border-radius: var(--r-full);
  font: 400 12px/16px var(--mono);
  color: var(--link-deep);
}
.chip .icon { width: 13px; height: 13px; color: var(--link); }
/* The warning chip stays amber on purpose: it is flagging something, and
   colouring it like the informational chips would hide that. */
.chip--warn .icon { color: var(--warning-deep); }
.chip--warn { background: var(--warning-soft); border-color: color-mix(in srgb, var(--warning) 28%, transparent); color: var(--warning-deep); }

.pane--wide { margin-top: var(--s-lg); }
.pane {
  background: var(--canvas);
  border-radius: var(--r-md);
  box-shadow: var(--e3);
  padding: var(--s-md);
}
.pane__title { display: flex; align-items: center; justify-content: space-between; gap: var(--s-xs); margin-bottom: var(--s-sm); }
.pane__name {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 500; line-height: 20px;
}
.pane__name .icon { color: var(--mute); }

.email {
  margin: 0;
  padding: var(--s-sm);
  background: var(--canvas-soft);
  border-radius: var(--r-xs);
  box-shadow: var(--e1);
  font-family: var(--sans);       /* body copy stays sans - mono is for code only */
  font-size: 13px; line-height: 20px;
  color: var(--body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;        /* the link is one long unbroken token */
  max-height: 212px; overflow-y: auto;
}
.email strong { color: var(--ink); font-weight: 500; }

.result__actions { display: flex; gap: var(--s-xs); margin-top: var(--s-lg); }
@media (max-width: 599px) { .result__actions { flex-direction: column; } }

/* ---- dark band - the brand's depth cue --------------------------------- */
.band-dark {
  background: var(--invert-bg); color: var(--invert-fg);
  margin-top: var(--s-3xl);
  padding-block: var(--s-4xl);
}
.band-dark .eyebrow { color: #ffffff8a; }
.band-dark h2 { margin-top: var(--s-sm); }
.band-dark__lead {
  max-width: 62ch;
  margin: var(--s-md) 0 0;
  font-size: 18px; line-height: 28px;
  color: #ffffffb8;
}
.band-dark__lead em { font-style: normal; color: var(--invert-fg); }
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-lg); margin-top: var(--s-2xl); }
@media (max-width: 899px) { .steps { grid-template-columns: 1fr; } }
.step { border-top: 1px solid #ffffff29; padding-top: var(--s-md); }
.step__n { font: 400 12px/16px var(--mono); color: #ffffff8a; }
.step h3 { font-size: 16px; font-weight: 500; line-height: 24px; margin: var(--s-xs) 0 var(--s-xxs); }
.step p { margin: 0; font-size: 14px; line-height: 20px; letter-spacing: -0.28px; color: #ffffffb8; }

/* ---- feature row -------------------------------------------------------- */
.section { padding-block: var(--s-5xl); }
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-md); margin-top: var(--s-2xl); }
@media (max-width: 899px) { .features { grid-template-columns: 1fr; } }
.feature {
  background: var(--canvas);
  border-radius: var(--r-md);
  box-shadow: var(--e3);
  padding: var(--s-lg);
}
.feature__icon {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px; margin-bottom: var(--s-sm);
  background: var(--canvas-soft-2);
  border-radius: var(--r-sm);
  color: var(--ink);
}
.feature h3 { font-size: 16px; font-weight: 500; line-height: 24px; margin: 0 0 var(--s-xxs); }
.feature p { margin: 0; font-size: 14px; line-height: 20px; letter-spacing: -0.28px; color: var(--body); }

.techline {
  display: flex; align-items: flex-start; gap: var(--s-xs);
  margin: var(--s-lg) 0 0;
  font: 400 12px/16px var(--mono);
  color: var(--mute);
}
.techline .icon { margin-top: 0; }
.techline a { color: var(--link); text-decoration: none; }
.techline a:hover { text-decoration: underline; }

/* ---- recipient preview -------------------------------------------------- */
.tabs {
  display: flex; flex-wrap: wrap; gap: var(--s-xxs);
  width: fit-content; max-width: 100%;
  margin-top: var(--s-lg);
  background: var(--canvas-soft-2);
  border-radius: var(--r-sm);
  padding: 3px;
}
.tabs button {
  height: 32px; padding: 0 var(--s-sm);
  border: 0; background: transparent; border-radius: var(--r-xs);
  font-size: 13px; font-weight: 500; color: var(--body);
  cursor: pointer; transition: background .15s, color .15s, box-shadow .15s;
}
.tabs button[aria-selected="true"] {
  background: var(--canvas); color: var(--ink);
  box-shadow: 0 1px 1px var(--shadow-1), 0 0 0 1px var(--ring);
}

.viewport {
  margin-top: var(--s-md);
  background: var(--canvas-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--e1);
  padding: var(--s-lg);
}
.browser {
  max-width: 560px; margin-inline: auto;
  background: var(--canvas);
  border-radius: var(--r-md);
  box-shadow: var(--e4);
  overflow: hidden;
}
.browser__bar {
  display: flex; align-items: center; gap: var(--s-xs);
  padding: var(--s-xs) var(--s-sm);
  border-bottom: 1px solid var(--hairline);
  background: var(--canvas-soft);
}
.browser__dots { display: flex; gap: 5px; }
.browser__dots i { width: 8px; height: 8px; border-radius: var(--r-full); background: var(--hairline); display: block; }
.browser__url {
  flex: 1; min-width: 0;
  font: 400 11px/16px var(--mono); color: var(--mute);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.browser__body { padding: var(--s-xl) var(--s-lg); text-align: center; }

.reveal {
  margin: var(--s-md) 0 0;
  padding: var(--s-sm);
  background: var(--invert-bg); color: var(--invert-fg);
  box-shadow: var(--e1);
  border-radius: var(--r-md);
  font: 400 13px/20px var(--mono);
  text-align: left;
  white-space: pre-wrap; word-break: break-all;
}
.reveal__actions {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-xs);
  margin-top: var(--s-sm);
}
.state-icon {
  display: grid; place-items: center;
  width: 40px; height: 40px; margin: 0 auto var(--s-sm);
  border-radius: var(--r-full);
}
.state-icon--lock { background: var(--canvas-soft-2); color: var(--ink); }
.state-icon--gone { background: var(--error-soft); color: var(--error-deep); }
.state-icon .icon { width: 18px; height: 18px; }
.state-icon--ok { background: var(--link-bg-soft); color: var(--link-deep); }

/* ---- blog index --------------------------------------------------------- */
.blog-head { padding-block: var(--s-4xl) var(--s-lg); }
.blog-head h1 { margin-top: var(--s-sm); }
.blog-head__sub { max-width: 58ch; margin-top: var(--s-md); }

.post-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-xs);
  font: 400 12px/16px var(--mono);
  color: var(--mute);
}
.post-meta__tag {
  padding: 2px var(--s-xs);
  background: var(--canvas-soft-2);
  border-radius: var(--r-full);
  color: var(--body);
}

.post-lead {
  display: block;
  padding: var(--s-xl);
  background: var(--canvas);
  border-radius: var(--r-lg);
  box-shadow: var(--e4);
  text-decoration: none; color: inherit;
  transition: box-shadow .18s, transform .18s;
}
.post-lead:hover { box-shadow: var(--e4), 0 12px 28px -12px var(--shadow-2); transform: translateY(-1px); }
.post-lead__body { display: block; max-width: 60ch; }
.post-lead__title { display: block; margin-top: var(--s-sm); }
.post-lead__excerpt { display: block; margin-top: var(--s-xs); }
.post-lead__more {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--s-md);
  font-size: 14px; font-weight: 500; color: var(--link);
}
.post-lead:hover .post-lead__more { text-decoration: underline; }

.post-archive { padding-block: var(--s-lg) var(--s-2xl); }
.post-list { list-style: none; margin: var(--s-md) 0 0; padding: 0; }
.post-list li + li { border-top: 1px solid var(--hairline); }
.post-row {
  display: grid;
  grid-template-columns: 104px 1fr auto;
  gap: var(--s-md);
  align-items: start;
  padding: var(--s-lg) var(--s-sm);
  margin-inline: calc(var(--s-sm) * -1);
  border-radius: var(--r-md);
  text-decoration: none; color: inherit;
  transition: background .15s;
}
.post-row:hover { background: var(--canvas-soft); }
.post-row__date { font: 400 12px/20px var(--mono); color: var(--mute); }
.post-row__title { display: block; font-size: 16px; font-weight: 500; line-height: 24px; }
.post-row:hover .post-row__title { color: var(--link); }
.post-row__excerpt {
  display: block; margin-top: var(--s-xxs); max-width: 62ch;
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  color: var(--body);
}
.post-row__tag {
  font: 400 12px/16px var(--mono);
  color: var(--mute);
  padding-top: 4px;
}
@media (max-width: 699px) {
  .post-row { grid-template-columns: 1fr; gap: var(--s-xxs); }
  .post-row__tag { display: none; }
}

.cta-band { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-lg); }
.cta-band .band-dark__lead { font-size: 16px; line-height: 24px; }
/* The band is dark in both themes, so its CTA is pinned light-on-dark rather
   than following --ink, which would make it invisible in dark mode. */
.btn--invert { background: var(--invert-fg); color: var(--invert-bg); }
.btn--invert:hover { opacity: .88; }

/* ---- article ------------------------------------------------------------ */
/* Article + sticky table of contents on the left. The pair is centred as a unit
   and both columns are fixed, so the prose never shifts. Below 1024px there is no
   room for the sidebar: it is hidden and the prose takes the width. The aside also
   comes first in the DOM, so tab order follows what you see. */
.article-wrap {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--s-4xl) var(--s-lg) 0;
  display: grid;
  /* fixed pair, centred as a unit - a 1fr prose column leaves dead space
     between the text and the TOC at wide viewports */
  grid-template-columns: 200px minmax(0, 720px);
  justify-content: center;
  gap: var(--s-4xl);
}
@media (max-width: 1023px) {
  .article-wrap { grid-template-columns: minmax(0, 720px); gap: 0; }
  .toc { display: none; }
}
.article { max-width: 720px; min-width: 0; }

.toc {
  position: sticky;
  top: calc(64px + var(--s-lg));        /* clears the sticky nav */
  align-self: start;
  max-height: calc(100vh - 64px - var(--s-2xl));
  overflow-y: auto;
  padding-bottom: var(--s-lg);
}
.toc__title {
  margin: 0 0 var(--s-sm);
  font: 400 12px/16px var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mute);
}
.toc__list { display: flex; flex-direction: column; border-left: 1px solid var(--hairline); }
.toc__list a {
  padding: 6px var(--s-sm);
  margin-left: -1px;
  border-left: 1px solid transparent;
  font-size: 13px; line-height: 18px; letter-spacing: -0.26px;
  color: var(--body); text-decoration: none;
  transition: color .15s, border-color .15s;
}
.toc__list a:hover { color: var(--ink); }
/* left-edge indicator, the pattern the DESIGN.md documents for active rows */
.toc__list a.is-active { color: var(--ink); font-weight: 500; border-left-color: var(--ink); }
.article__head { padding-bottom: var(--s-lg); border-bottom: 1px solid var(--hairline); }
.backlink {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 500;
  color: var(--body); text-decoration: none;
}
.backlink:hover { color: var(--ink); }

.prose { padding-block: var(--s-lg) var(--s-2xl); }
.prose p, .prose ul, .prose ol { font-size: 17px; line-height: 28px; color: var(--body); margin: 0 0 var(--s-md); }
.prose h2 {
  scroll-margin-top: calc(64px + var(--s-lg));
  font-size: 24px; font-weight: 600; line-height: 32px; letter-spacing: -0.96px;
  color: var(--ink);
  margin: var(--s-xl) 0 var(--s-xs);
}
.prose strong { color: var(--ink); font-weight: 500; }
.prose em { font-style: italic; }
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li { margin-bottom: var(--s-xs); }
.prose li::marker { color: var(--mute); }
/* inline code is a technical label, so it takes the mono face; body copy never does */
.prose code {
  font: 400 .875em/1 var(--mono);
  padding: 2px 5px;
  background: var(--canvas-soft-2);
  border-radius: var(--r-xs);
  color: var(--ink);
}
.code {
  margin: 0 0 var(--s-md);
  padding: var(--s-md);
  background: var(--invert-bg); color: var(--invert-fg);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  overflow-x: auto;
}
.code code {
  font: 400 12px/20px var(--mono);
  background: none; padding: 0; color: inherit;
  white-space: pre;
}

.callout {
  display: flex; gap: var(--s-sm);
  margin: 0 0 var(--s-md);
  padding: var(--s-md);
  background: var(--warning-soft);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  font-size: 15px; line-height: 24px;
  color: var(--ink);
}
.callout .icon { color: var(--warning-deep); margin-top: 3px; }
.callout strong { font-weight: 500; }

.article__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-md);
  /* margin, not just padding: the rule was landing flush on the tag pills (or on
     the next-post card, when there is one) directly above it. */
  margin-top: var(--s-2xl);
  padding-block: var(--s-lg) var(--s-4xl);
  border-top: 1px solid var(--hairline);
}

/* ---- footer ------------------------------------------------------------- */
.foot {
  border-top: 1px solid var(--hairline);
  padding-block: var(--s-3xl) var(--s-lg);
  margin-top: var(--s-5xl);
}
.foot__grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: var(--s-xl) var(--s-lg);
}
@media (max-width: 899px) { .foot__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 599px) { .foot__grid { grid-template-columns: 1fr; gap: var(--s-lg); } }

.foot__brand { max-width: 34ch; }
.foot__blurb {
  margin: var(--s-sm) 0 0;
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  color: var(--body);
}
.foot__col { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-xs); }
.foot__coltitle {
  margin: 0 0 var(--s-xxs);
  font: 400 12px/16px var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mute);
  font-weight: 400;
}
.foot__col a {
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  color: var(--body); text-decoration: none;
}
.foot__col a:hover { color: var(--ink); }
.foot__col a[aria-current="page"] { color: var(--ink); font-weight: 500; }

.foot__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-xs);
  margin-top: var(--s-2xl);
  padding-top: var(--s-md);
  border-top: 1px solid var(--hairline);
}
.foot__note { margin: 0; font: 400 12px/16px var(--mono); color: var(--mute); }

/* ---- toast -------------------------------------------------------------- */
.toast {
  position: fixed; left: 50%; bottom: var(--s-lg);
  transform: translate(-50%, 8px);
  display: flex; align-items: center; gap: var(--s-xs);
  padding: var(--s-sm) var(--s-md);
  /* Was ink-coloured, which disappeared against the polarity-flipped band it
     most often floats over. Green reads as confirmation and separates from both
     the white canvas and the dark band. */
  background: var(--success); color: var(--on-success);
  border-radius: var(--r-md);
  box-shadow: 0 0 0 1px #00000026, 0 8px 16px -4px #00000040, 0 24px 32px -8px #00000033;
  font-size: 14px; font-weight: 500;
  opacity: 0; pointer-events: none;
  transition: opacity .18s, transform .18s;
  z-index: 100;
}
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
.toast .icon { width: 15px; height: 15px; }

@media (max-width: 599px) {
  .display-xl { font-size: 36px; line-height: 38px; letter-spacing: -1.6px; }
  .display-lg { font-size: 26px; line-height: 32px; letter-spacing: -1px; }
  .hero { padding-block: var(--s-2xl) var(--s-lg); }
  .band-dark, .section { padding-block: var(--s-4xl); }
  .nav__links .nav__link[data-optional] { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ---- utilities ----------------------------------------------------------
   These exist because the Content-Security-Policy forbids inline style
   attributes. For a zero-knowledge app that restriction is worth keeping
   strict, so one-off spacing lives here as classes instead. */
.u-medium     { font-weight: 500; }
.u-subtext    { display: block; margin-top: 2px; }
.u-mt-2       { margin-top: 2px; }
.u-mt-xxs     { margin-top: var(--s-xxs); }
.u-mt-xs      { margin-top: var(--s-xs); }
.u-mt-sm      { margin-top: var(--s-sm); }
.u-mt-md      { margin-top: var(--s-md); }
.u-mt-lg      { margin-top: var(--s-lg); }
.u-mb-0       { margin-bottom: 0; }
.u-pt-0       { padding-top: 0; }
.u-error      { color: var(--error-deep); }
.u-band-center{ padding-block: var(--s-5xl); text-align: center; }
.u-lede       { margin: var(--s-md) auto 0; max-width: 44ch; }
.u-formbox    { max-width: 280px; margin: var(--s-md) auto 0; }

/* ---- retrieval page (moved out of s.html: inline <style> is CSP-blocked) -- */
.retrieve-shell { display: grid; place-items: center; min-height: calc(100vh - 64px); padding: var(--s-2xl) var(--s-lg); }
.retrieve-card {
  width: 100%; max-width: 480px;
  background: var(--canvas); border-radius: var(--r-lg);
  box-shadow: var(--e4); padding: var(--s-2xl) var(--s-xl);
  text-align: center;
}
.retrieve-card h1 { margin: 0; }
.retrieve-foot { margin-top: var(--s-lg); text-align: center; }
.retrieve-foot a { font-size: 13px; color: var(--mute); text-decoration: none; }
.retrieve-foot a:hover { color: var(--ink); }

/* ---- insecure-context banner -------------------------------------------- */
.banner {
  margin: 0 auto var(--s-lg);
  max-width: 760px;
  padding: var(--s-sm) var(--s-md);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  font-size: 14px; line-height: 21px;
  color: var(--ink);
}
.banner code { font: 400 .9em/1 var(--mono); background: #00000014; padding: 1px 4px; border-radius: 3px; }
.banner a { color: inherit; font-weight: 500; }
.banner--danger { background: var(--error-soft); }

/* ---- hero phrase rotator -------------------------------------------------
   All phrases stay in the DOM so crawlers see every term; only one is visible.
   Stacked in a single grid cell so the badge takes the width of the longest
   phrase and never jitters as it cycles. */
.rotator { display: inline-grid; }
.rotator__item {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s ease;
  white-space: nowrap;
}
.rotator__item.is-on { opacity: 1; visibility: visible; }

@media (prefers-reduced-motion: reduce) {
  .rotator__item { transition: none; }
}

/* ---- tags ----------------------------------------------------------------
   Topic pages exist so a reader can follow a thread through the blog, and so
   each subject has one URL a search engine can rank. */
.tagrow { display: flex; flex-wrap: wrap; gap: var(--s-xs); margin: 0; }
.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  background: var(--link-bg-soft);
  border: 1px solid color-mix(in srgb, var(--link) 30%, transparent);
  border-radius: var(--r-full);
  font: 400 12px/16px var(--mono);
  color: var(--link-deep);
  text-decoration: none;
  transition: border-color .15s;
}
.tag:hover { border-color: var(--link); }
.tag__count { color: var(--link); opacity: .75; }

.blog-head__tags { margin: var(--s-md) 0 0; }

.tagcloud {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--s-sm);
  margin-top: var(--s-md);
}
.tagcard {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s-md);
  background: var(--canvas);
  border-radius: var(--r-md);
  box-shadow: var(--e3);
  text-decoration: none; color: inherit;
  transition: box-shadow .15s;
}
.tagcard:hover { box-shadow: var(--e4); }
.tagcard__name { font-size: 15px; font-weight: 500; }
.tagcard:hover .tagcard__name { color: var(--link); }
.tagcard__count { font: 400 12px/16px var(--mono); color: var(--mute); }

/* The rule above each of these is a separator, so it needs air on BOTH sides.
   With padding alone the line sat flush against the last paragraph or pill of
   the block before it and read as an underline rather than a divider. */
.article__tags {
  margin-top: var(--s-2xl);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--hairline);
}
.article__tags .foot__coltitle { margin-bottom: var(--s-xs); }

/* ---- FAQ ------------------------------------------------------------------ */
.faq {
  margin-top: var(--s-2xl);
  padding-top: var(--s-2xl);
  border-top: 1px solid var(--hairline);
}
.faq__heading {
  display: flex; align-items: center; gap: var(--s-xs);
  margin: 0 0 var(--s-md);
  font-size: 22px; line-height: 28px; font-weight: 600; letter-spacing: -.02em;
  color: var(--ink);
}
.faq__heading .icon { color: var(--mute); }

.faq__list {
  background: var(--canvas-soft);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  /* clips the first and last row's hover fill to the rounded corners */
  overflow: hidden;
}
.faq__item + .faq__item { border-top: 1px solid var(--hairline); }

.faq__q {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-md);
  padding: var(--s-md);
  cursor: pointer;
  font-size: 16px; line-height: 24px; font-weight: 500;
  color: var(--ink);
  transition: background .15s, color .15s;
  /* the native disclosure triangle, in both engines - replaced by the chevron */
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { background: var(--canvas-soft-2); color: var(--link); }
.faq__q:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
.faq__qtext { text-wrap: pretty; }

.faq__chevron {
  color: var(--mute);
  transition: transform .2s ease;
}
.faq__item[open] .faq__chevron { transform: rotate(180deg); }
.faq__item[open] .faq__q { color: var(--ink); }
.faq__item[open] .faq__q:hover { color: var(--link); }

.faq__a { padding: 0 var(--s-md) var(--s-md); }
.faq__a p {
  margin: 0;
  max-width: 68ch;
  font-size: 15px; line-height: 25px;
  color: var(--body);
}

@media (prefers-reduced-motion: reduce) {
  .faq__chevron { transition: none; }
}

/* The category chip is a label, not a link - it had hover affordances that
   promised a topic page which is not generated for categories. */

/* ---- next post ------------------------------------------------------------ */
.next-post {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: var(--s-lg);
  padding: var(--s-md);
  background: var(--canvas-soft);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  text-decoration: none; color: inherit;
  transition: background .15s;
}
.next-post:hover { background: var(--canvas-soft-2); }
.next-post__label {
  font: 400 11px/16px var(--mono);
  text-transform: uppercase; letter-spacing: .06em; color: var(--mute);
}
.next-post__title { font-size: 16px; font-weight: 500; line-height: 24px; }
.next-post:hover .next-post__title { color: var(--link); }

/* ---- tools ---------------------------------------------------------------- */
.tool-list { list-style: none; margin: var(--s-md) 0 0; padding: 0; }
.tool {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--s-md);
  align-items: center;
  padding: var(--s-md);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
}
.tool + .tool { margin-top: var(--s-xs); }
.tool__icon {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px;
  background: var(--canvas-soft-2);
  border-radius: var(--r-sm);
  color: var(--mute);
}
.tool__name { display: block; font-size: 15px; font-weight: 500; line-height: 22px; }
.tool__desc {
  display: block; margin-top: 2px;
  font-size: 14px; line-height: 20px; letter-spacing: -0.28px;
  color: var(--body);
}
/* Amber rather than green: these are not ready, and the colour should say so. */
.tool__status {
  padding: 4px 10px;
  background: var(--warning-soft);
  border: 1px solid color-mix(in srgb, var(--warning) 28%, transparent);
  border-radius: var(--r-full);
  font: 400 12px/16px var(--mono);
  color: var(--warning-deep);
  white-space: nowrap;
}
@media (max-width: 599px) {
  .tool { grid-template-columns: auto 1fr; }
  .tool__status { grid-column: 2; justify-self: start; }
}
.tool-cta { margin-top: var(--s-2xl); border-radius: var(--r-lg); padding-block: var(--s-xl); }
.tool-cta .wrap { padding-inline: var(--s-lg); }

/* ---- 404 ------------------------------------------------------------------ */
.notfound-note {
  max-width: 46ch;
  margin: var(--s-lg) auto 0;
  padding: var(--s-sm) var(--s-md);
  background: var(--canvas-soft);
  border-radius: var(--r-md);
  box-shadow: var(--e1);
  text-align: left;
}
.notfound-note p { margin: 0; color: var(--body); }
.notfound-links {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-xs);
  margin-top: var(--s-lg);
}

/* ---- reCAPTCHA ------------------------------------------------------------ */
/* The floating badge is hidden, which Google allows only when the page carries
   the attribution text instead - see #captchaNote in index.html. visibility,
   not display: v3 reads the badge's box and hiding it outright can stall it. */
.grecaptcha-badge { visibility: hidden; }

/* Sits under the app card, centred on it. Legal boilerplate: present and
   legible, but not competing with the form above it. */
.captcha-note {
  margin: var(--s-md) 0 0;
  text-align: center;
  font-size: 12px; line-height: 18px;
  color: var(--mute);
  text-wrap: pretty;
}
.captcha-note a { color: var(--mute); text-decoration: underline; }
.captcha-note a:hover { color: var(--ink); }
