/*
 * Design tokens — the single :root block shared by the whole SPA (landing
 * and authed app alike, one build post-12-01-PLAN.md, DS-01). Do not
 * redefine any of these elsewhere; extend app.css instead.
 */
:root {
  --ink: #17141B;
  --paper: #F5F3ED;
  --card: #FFFFFF;
  --grape: #6425E0;
  --grape-deep: #4B18B0;
  --lilac: #EDE4FF;
  --muted: #6B6478;
  --line: #E5E0D6;
  --term: #161320;
  --term-line: #2A2437;
  --term-fg: #D8D2E8;
  --term-dim: #7E7796;
  --ok: #54D6A0;
  --shadow: 5px 5px 0 var(--ink);
  --radius: 14px;
}

/*
 * apps/web's own stylesheet. The landing (Landing.tsx) and the authed app
 * now render from this one SPA build (12-01-PLAN.md, DS-01) — there is no
 * separate static public/index.html build anymore; every rule below is
 * shared by both surfaces from a single source.
 */

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .btn.hard:hover {
    transform: none;
  }
  .card:hover {
    transform: none;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: var(--grape);
  color: #fff;
}

:focus-visible {
  outline: 2px solid var(--grape);
  outline-offset: 3px;
  border-radius: 4px;
}

.wrap {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 24px;
}

/* ---------- brand / header ---------- */
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -0.02em;
}

.logo-mark {
  height: 30px;
  width: auto;
  flex: 0 0 auto;
}

/* brand-name: YAFL expands to Yet Another File Layer on hover */
.brand-name { display: inline-flex; white-space: nowrap; }
.brand-name .bw { display: inline-flex; align-items: baseline; }
.brand-name .bw + .bw { margin-left: 0.02em; transition: margin-left 0.28s ease; }
.brand-name .bx {
  display: inline-block;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  font-weight: 400;
  transition: max-width 0.28s ease, opacity 0.22s ease;
}
a.brand:hover .brand-name .bw + .bw { margin-left: 0.28em; }
a.brand:hover .brand-name .bx { max-width: 5.5ch; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .brand-name .bx, .brand-name .bw + .bw { transition: none; }
}

.glyph {
  width: 26px;
  height: 26px;
  border: 2px solid var(--ink);
  border-radius: 50%;
  display: grid;
  place-items: center;
  position: relative;
  flex: 0 0 auto;
}

.glyph::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--grape);
}

header.app-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.app-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 64px;
}

/* ---------- buttons ---------- */
.btn {
  font-family: 'Inter';
  font-weight: 600;
  font-size: 0.92rem;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  border: 2px solid var(--ink);
  border-radius: 10px;
  padding: 9px 16px;
  background: var(--grape);
  color: #fff;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.btn.hard {
  box-shadow: var(--shadow);
}

.btn.hard:hover {
  transform: translate(-2px, -2px);
  box-shadow: 7px 7px 0 var(--ink);
}

.btn.hard:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 var(--ink);
}

.btn.ghost {
  background: var(--card);
  color: var(--ink);
}

.btn.ghost:hover {
  background: var(--lilac);
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

/* ---------- cards ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  transition: border-color 0.15s, transform 0.15s;
}

.card:hover {
  border-color: var(--ink);
  transform: translateY(-3px);
}

.card.state-error {
  border-color: #FF9BB0;
}

.card.state-ok {
  border-color: var(--ok);
}

/* ---------- receive: the decrypt/download file card ---------- */
.dl-card {
  display: flex;
  flex-direction: column;
  gap: 20px;
  border-width: 2px;
}

.dl-head {
  display: flex;
  align-items: center;
  gap: 14px;
}

.dl-ic {
  flex-shrink: 0;
  color: var(--grape);
}

.dl-info {
  min-width: 0;
}

.dl-card .dl-name {
  margin: 0;
  font-weight: 600;
  font-size: 1.06rem;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dl-card .dl-meta {
  margin: 3px 0 0;
  font-family: 'JetBrains Mono';
  font-size: 0.86rem;
  color: var(--muted);
}

.dl-dot {
  opacity: 0.5;
  padding: 0 2px;
}

.dl-btn {
  width: 100%;
  justify-content: center;
}

/* ---------- fields ---------- */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
}

.field label {
  font-family: 'JetBrains Mono';
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.02em;
}

.field input {
  font-family: 'Inter';
  font-size: 0.95rem;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 10px;
  padding: 11px 14px;
}

.field input:focus {
  outline: 2px solid var(--grape);
  outline-offset: 1px;
  border-color: transparent;
}

/* iOS Safari auto-zooms the viewport when a focused input's computed
   font-size is below 16px – floor every .field input/textarea/select at
   exactly 16px under the mobile breakpoint, without touching desktop
   typography (0.95rem stays above 720px). */
@media (max-width: 720px) {
  .field input,
  .field textarea,
  .field select {
    font-size: 16px;
  }
}

/* ---------- device code input ---------- */
.code-input {
  display: flex;
  align-items: center;
  gap: clamp(3px, 1.6vw, 8px);
  flex-wrap: nowrap;
  width: 100%;
}

.code-input input {
  font-family: 'JetBrains Mono';
  flex: 1 1 0;
  min-width: 0;
  max-width: 44px;
  box-sizing: border-box;
  padding: 0;
  height: 52px;
  text-align: center;
  text-transform: uppercase;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 10px;
  /* Flat 16px – autofocused on mount, so any lower value auto-zooms iOS. */
  font-size: 16px;
}

.code-input input:focus {
  outline: 2px solid var(--grape);
  outline-offset: 1px;
  border-color: transparent;
}

/* Locked/confirmed state (readOnly, not disabled) — full contrast kept,
   a settled-not-editable affordance instead of a greyed-out disabled look. */
.code-input input.locked,
.code-input input[readonly] {
  background: var(--lilac);
  border-color: var(--ink);
  color: var(--ink);
  cursor: default;
}

.code-input .sep {
  font-family: 'JetBrains Mono';
  color: var(--muted);
  user-select: none;
  flex: 0 0 auto;
}

/* ---------- console / mono link display ---------- */
.console {
  margin-top: 32px;
  background: var(--term);
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: 6px 6px 0 rgba(23, 20, 27, 0.16);
  overflow: hidden;
}

.pane {
  padding: 22px clamp(16px, 3vw, 28px);
  font-family: 'JetBrains Mono';
  font-size: 0.82rem;
  line-height: 1.85;
  color: var(--term-fg);
}

.link {
  color: #B79BFF;
  word-break: break-all;
}

/* ---------- status notes (success + error), ONE in-UI style ----------
   Same design language as the cards and .legal-notrack: full 1px border,
   var(--radius), a quiet tint, normal ink text (readable in both themes,
   no WCAG-failing accent-colored text). The tone lives in the border +
   tint only. Scoped to <p> so the .card.state-error border variant is
   untouched. Symmetric margins keep a note from touching the button or
   field next to it. */
p.ok,
p.state-error {
  font-size: 0.9rem;
  color: var(--ink);
  padding: 10px 14px;
  margin: 14px 0;
  border: 1px solid var(--ok);
  border-radius: var(--radius);
  background: rgba(84, 214, 160, 0.1);
}

/* Inside a card, `.card p { margin: 0 }` (below) would otherwise flatten the
   status-note spacing — keep the note separated from the button that follows. */
.card p.ok,
.card p.state-error {
  margin: 14px 0;
}

/* A quiet caption in the download card (one-time hint / "used up"). */
.dl-note {
  margin: 12px 0 0;
  text-align: center;
  font-size: 0.86rem;
  color: var(--muted);
}

p.state-error {
  border-color: #ff9bb0;
  background: rgba(255, 155, 176, 0.1);
}

/* ---------- dropzone ---------- */
.dropzone {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 36px 24px;
  text-align: center;
  cursor: pointer;
  background: var(--card);
  border: 2px dashed #C9C2B4;
  border-radius: var(--radius);
  transition: border-color 0.15s, background 0.15s, transform 0.12s;
}

.dropzone:hover,
.dropzone:focus-visible {
  border-color: var(--grape);
  background: #FBFAF6;
}

.dropzone.dragging {
  border-color: var(--grape);
  background: var(--lilac);
  transform: scale(1.01);
  border-style: solid;
}

/* ---------- share-the-app header trigger (ShareApp.tsx) ----------
   Deliberately soft: bare icon, no border, no background — it's a
   tertiary affordance, not a competing button next to Sign in. */
.share-app-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, background 0.15s, transform 0.15s;
}

.share-app-trigger:hover,
.share-app-trigger:focus-visible {
  color: var(--grape);
  background: var(--lilac);
  transform: translateY(-1px);
}

/* ---------- user menu (top-right account dropdown) ---------- */
.user-menu {
  position: relative;
  display: inline-block;
}

.user-menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  min-width: 180px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 8px;
}

.user-menu-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ONE item style for every entry – links (Profile, API keys) and the
   Log out button render identically: same size, weight, padding, hover. */
.user-menu-list a,
.user-menu-list button {
  display: flex;
  width: 100%;
  justify-content: flex-start;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
  background: none;
  border: 0;
  border-radius: 8px;
  padding: 7px 10px;
  cursor: pointer;
  transition: background 0.12s;
}

.user-menu-list a:hover,
.user-menu-list button:hover,
.user-menu-list a:focus-visible,
.user-menu-list button:focus-visible {
  background: var(--lilac);
}

/* The email line is context, not an action: quieter, separated from the
   items below it. */
.user-menu-email {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.74rem;
  color: var(--muted);
  padding: 4px 10px 8px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- landing: hero ---------- */
.menu-links {
  display: flex;
  align-items: center;
  gap: 28px;
}

.menu-links .lnk {
  font-size: 0.92rem;
  color: var(--muted);
  font-weight: 500;
  transition: color 0.15s;
}

.menu-links .lnk:hover {
  color: var(--ink);
}

.hero {
  /* Scales with viewport: ~36px on a phone, up to 72px on desktop, so the
     hero does not eat the whole first screen on smaller breakpoints. */
  padding-top: clamp(36px, 7vw, 72px);
  padding-bottom: 24px;
}

/* Above-the-fold hero top: ONE row — the small /agents/ text link
   (DISC-01's prominent, crawlable discovery entry) on the left, the single
   context chip pushed to the top-right so it stays out of the headline's
   way. Wraps back to a stack on narrow screens. */
.hero-chips {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.agents-link {
  font-family: 'JetBrains Mono';
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  color: var(--grape-deep);
  text-decoration: underline;
  text-decoration-color: #DCC9FF;
  text-underline-offset: 3px;
  transition: color 0.15s, text-decoration-color 0.15s;
}

.agents-link:hover {
  color: var(--grape);
  text-decoration-color: var(--grape);
}

h1 {
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: clamp(2.6rem, 7vw, 4.6rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  margin: 22px 0 0;
  /* Roughly half the content column on desktop – restricted enough to keep
     the tight ragged-right look, wide enough to break as two lines instead
     of three. Falls back to full width on small screens (media query near
     the bottom of this file). */
  max-width: 50%;
}

@media (max-width: 900px) {
  h1 {
    max-width: 100%;
  }
}

h1 .fade {
  color: var(--grape);
}

.lede {
  font-size: clamp(1.05rem, 2.2vw, 1.28rem);
  color: var(--muted);
  max-width: 52ch;
  margin: 22px 0 0;
  line-height: 1.55;
}

.lede b {
  color: var(--ink);
  font-weight: 600;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 32px;
  align-items: center;
}

.cta-note {
  font-size: 0.85rem;
  color: var(--muted);
  font-family: 'JetBrains Mono';
  /* Sits as its own line between the lede and the CTA buttons. */
  margin: 18px 0 0;
}

.cta-note + .cta-row {
  margin-top: 18px;
}

/* Inline "See how it works →" link that rides the end of the lede paragraph
   (replaced a ghost button to save a row). Same grape underline as the
   agents-docs link; nowrap keeps the arrow glued to the label. */
.inline-link {
  color: var(--grape-deep);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: #DCC9FF;
  text-underline-offset: 3px;
  white-space: nowrap;
  transition: color 0.15s, text-decoration-color 0.15s;
}

.inline-link:hover {
  color: var(--grape);
  text-decoration-color: var(--grape);
}

/* Lean "featured on" strip: a small label + the self-hosted badge, left-aligned
   to sit flush under the hero content and stay above the fold. */
.featured-on {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 30px;
}

.featured-on-label {
  font-family: 'JetBrains Mono';
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
}

.featured-badge {
  display: inline-flex;
  line-height: 0;
  border-radius: 8px;
  transition: opacity 0.15s, transform 0.15s;
}

.featured-badge:hover {
  opacity: 0.88;
  transform: translateY(-1px);
}

.featured-badge img {
  display: block;
}

/* Reassurance line under the hero primary CTA (finalized copy). */
.cta-reassure {
  font-size: 0.86rem;
  color: var(--muted);
  max-width: 52ch;
  margin: 12px 0 0;
  line-height: 1.5;
}

/* Trust section — the npm + MCP-registry link row. */
.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  margin-top: 24px;
}

/* FAQ list on the landing (conversion FAQ, distinct from the /faq page). */
.faq-list {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 28px;
}

.faq-item {
  border-top: 1px solid var(--line);
  padding-top: 18px;
}

.faq-item h3 {
  font-family: 'Space Grotesk';
  font-size: 1.05rem;
  color: var(--ink);
  margin: 0 0 6px;
}

.faq-item p {
  color: var(--muted);
  line-height: 1.6;
  margin: 0;
  max-width: 68ch;
}

.faq-item code {
  font-family: 'JetBrains Mono';
  font-size: 0.88em;
}

/* Final CTA — a centered block on the normal page background so the standard
   light-background buttons render correctly (deliberately not the dark .band). */
.cta-final {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: clamp(28px, 4vw, 44px) 0 8px;
  border-top: 1px solid var(--line);
}

.cta-final-sub {
  color: var(--muted);
  margin: 0 0 8px;
}

.cta-row-center {
  justify-content: center;
}

/* Real terminal recording under the stylised console in "Show it works".
   Dark frame + background so the gif's own dark terminal bg blends into the
   border instead of showing seams while it loops. */
.demo-clip {
  margin: 30px 0 0;
  text-align: center;
}

.demo-clip img {
  display: block;
  width: 100%;
  max-width: 640px;
  height: auto;
  margin: 0 auto;
  border: 1px solid var(--term-line);
  border-radius: var(--radius);
  background: var(--term);
}

.demo-clip figcaption {
  margin-top: 12px;
  font-size: 0.86rem;
  color: var(--muted);
}

/* the landing's larger, standalone hero dropzone (UploadPage's authed
   dropzone reuses the base .dropzone rules above without these extras) */
.hero-dropzone {
  margin-top: 40px;
  padding: 64px 32px;
  min-height: 320px;
  justify-content: center;
}

/* On mobile, lift the drop field up under the headline so it is present
   above the fold — order becomes chips, headline, dropzone, then the
   description + CTA below it. Desktop is untouched (source order, dropzone
   last). Scoped to the phone breakpoint; `order` only affects the flex
   items of .hero, so the global `h1` selector here is inert elsewhere. */
@media (max-width: 720px) {
  .hero {
    display: flex;
    flex-direction: column;
  }
  .hero > .hero-chips {
    order: -3;
  }
  .hero > h1 {
    order: -2;
  }
  .hero > .hero-dropzone {
    order: -1;
    /* Compact on phones: the desktop 320px floor + 64px padding made the
       drop field eat the whole first screen and pushed the description out
       of view. Shrink it so the top of the description peeks at the fold as
       a scroll cue. Desktop sizing (base rule) is unchanged. */
    margin-top: 24px;
    padding: 32px 24px;
    min-height: 0;
  }
}

.dz-ic {
  color: var(--grape);
}

.dz-text {
  font-size: 1.02rem;
  color: var(--ink);
}

.dz-text b {
  font-family: 'Space Grotesk';
  font-weight: 600;
}

.dz-sub {
  font-family: 'JetBrains Mono';
  font-size: 0.74rem;
  color: var(--muted);
  letter-spacing: 0.02em;
}

/* ---------- landing: console demo (handoff) ---------- */
.console-top {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--term-line);
}

.tl {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #3A3350;
}

.tl.g {
  background: #4B3E7A;
}

.console-title {
  margin-left: 8px;
  font-family: 'JetBrains Mono';
  font-size: 0.78rem;
  color: var(--term-dim);
}

.panes {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
}

.pane .host {
  color: var(--term-dim);
  font-size: 0.74rem;
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 12px;
}

.pane .host .badge-machine {
  color: #B9AEE6;
}

.prompt {
  color: #8E86FF;
}

.call {
  color: var(--term-fg);
}

.key {
  color: #C0B5F5;
}

.str {
  color: #8FE3B8;
}

.muted-line {
  color: var(--term-dim);
}

.term-link {
  color: #B79BFF;
  word-break: break-all;
}

.ok-inline {
  color: var(--ok);
}

.lock-ic {
  color: #E9C06A;
}

/* relay divider between the two panes */
.rings {
  position: relative;
  width: 64px;
  display: grid;
  place-items: center;
  border-left: 1px dashed var(--term-line);
  border-right: 1px dashed var(--term-line);
}

.rings .ring {
  position: absolute;
  border: 1px solid var(--term-line);
  border-radius: 50%;
  width: 14px;
  height: 14px;
  opacity: 0.5;
}

.rings .r2 {
  width: 30px;
  height: 30px;
  opacity: 0.3;
}

.rings .r3 {
  width: 46px;
  height: 46px;
  opacity: 0.18;
}

.rings .chev {
  font-family: 'JetBrains Mono';
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1;
  color: #B79BFF;
  text-shadow: 0 0 12px rgba(100, 37, 224, 0.55);
  position: relative;
  z-index: 2;
  user-select: none;
  animation: handoff 2.8s ease-in-out infinite;
}

/* right-headed angle: fades in, nudges toward the receiving pane, fades out */
@keyframes handoff {
  0% {
    transform: translateX(-14px);
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  65% {
    opacity: 1;
  }
  100% {
    transform: translateX(14px);
    opacity: 0;
  }
}

@keyframes handoffV {
  0% {
    transform: rotate(90deg) translateX(-12px);
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  65% {
    opacity: 1;
  }
  100% {
    transform: rotate(90deg) translateX(12px);
    opacity: 0;
  }
}

/* ---------- landing: section scaffolding ---------- */
/* Scoped to the landing's own <main class="landing"> – an unscoped `section`
   selector leaked these 84px bands into every subpage that used a semantic
   <section> (legal, about), blowing up their vertical rhythm. Subpages get
   the calmer .page-main section rule instead. */
.landing section {
  padding: 84px 0;
}

.sec-head {
  max-width: 52ch;
}

.kicker {
  font-family: 'JetBrains Mono';
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grape-deep);
  font-weight: 500;
}

h2 {
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: -0.03em;
  line-height: 1.08;
  margin: 14px 0 0;
}

.sec-head p {
  color: var(--muted);
  margin: 14px 0 0;
  font-size: 1.05rem;
}

/* ---------- landing: security cards grid ---------- */
.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px;
  margin-top: 40px;
}

.card .ic {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  background: var(--lilac);
  display: grid;
  place-items: center;
  margin-bottom: 16px;
  color: var(--grape-deep);
}

.card h3 {
  font-family: 'Space Grotesk';
  font-weight: 600;
  font-size: 1.12rem;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
}

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

.card code,
.step code {
  font-family: 'JetBrains Mono';
  font-size: 0.86em;
  background: var(--lilac);
  color: var(--grape-deep);
  padding: 0.1em 0.4em;
  border-radius: 5px;
}

/* ---------- landing: how-it-works steps ---------- */
/* "How it works": three steps sit in one plain rounded white card. Only STEP
   02's column is open at the bottom — its two dividers bracket a doorway that
   leaks straight down into the full-width install row below. No diagonals: the
   whole thing is the usual 1px --line border and var(--radius) corners. */
.flare {
  margin-top: 44px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

/* Top row: three equal columns. The middle one has no bottom border, and its
   two neighbours round their bottom borders at the opening — so the divider
   peels away in a smooth funnel-mouth and STEP 02 leaks into the full-width
   second row below. */
.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.step {
  padding: 30px 26px;
}

.step:nth-child(1) {
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-bottom-right-radius: var(--radius);
}

/* STEP 02: open at the bottom — flows straight into the second row. */
.step:nth-child(2) {
  border-bottom: none;
}

.step:nth-child(3) {
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-bottom-left-radius: var(--radius);
}

/* Bottom row: one full-width cell. No top border of its own — the neighbours'
   rounded bottom borders frame the opening; the card supplies sides + bottom. */
.install-panel {
  padding: 26px;
}

/* Mobile: the three columns stack into plain rows with bottom dividers; no
   opening, no rounding. */
@media (max-width: 720px) {
  .steps {
    grid-template-columns: 1fr;
  }

  .step:nth-child(1),
  .step:nth-child(2),
  .step:nth-child(3) {
    border-right: none;
    border-left: none;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
  }
}

/* STEP 03: the ready-to-run retrieval one-liner, styled as a small dark
   terminal chip so it reads as a real command, not body copy. */
.step-cmd {
  margin-top: 16px;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 11px 14px;
  background: var(--term);
  border: 1px solid var(--term-line);
  border-radius: 10px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.86rem;
  color: var(--term-fg);
  overflow-x: auto;
}

.step-cmd .scmd-dollar {
  color: var(--term-dim);
  user-select: none;
}

.step-cmd .scmd-body {
  white-space: nowrap;
}

.step-cmd .scmd-id {
  color: #b79bff;
}

.step-cmd .scmd-hash {
  color: var(--ok);
  font-weight: 700;
}

.step-cmd .scmd-key {
  color: var(--ok);
}

.step .num {
  font-family: 'JetBrains Mono';
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--grape);
  letter-spacing: 0.05em;
}

.step h3 {
  font-family: 'Space Grotesk';
  font-weight: 600;
  font-size: 1.15rem;
  margin: 14px 0 8px;
  letter-spacing: -0.01em;
}

.step p {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---------- landing: install band + command blocks (UNIF-07) ---------- */
.band {
  background: var(--ink);
  color: #F3F0FB;
  border-radius: 20px;
  padding: clamp(32px, 5vw, 56px);
}

.band .kicker {
  color: #B79BFF;
}

.band h2 {
  color: #fff;
}

.band .lede2 {
  color: #B3AAC8;
  max-width: 52ch;
  margin: 16px 0 0;
}

.band .lede2 code {
  font-family: 'JetBrains Mono';
  font-size: 0.9em;
  color: #E4DBFF;
}

/* A small heading, then a plain status list — no card, no borders, no
   background. Just a status label + feature per row; live rows get a green dot,
   planned a muted one. */
.roadmap-head {
  margin: 30px 0 14px;
  font-family: 'JetBrains Mono';
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.roadmap {
  list-style: none;
  margin: 0;
  padding: 0;
}

.roadmap li {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 6px 0;
}

.roadmap .st {
  flex: none;
  width: 84px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: 'JetBrains Mono';
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.roadmap .st::before {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted);
}

.roadmap .live .st {
  color: var(--ink);
}

.roadmap .live .st::before {
  background: var(--ok);
}

.roadmap .feat {
  font-size: 0.92rem;
  color: var(--ink);
}

.roadmap .planned .feat {
  color: var(--muted);
}

.install-blocks {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-top: 0;
}

.command-block {
  background: #211C2E;
  border: 1px solid #3A3350;
  border-radius: 10px;
  padding: 14px 16px;
}

.command-block-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.command-block-label {
  font-family: 'JetBrains Mono';
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #B3AAC8;
}

/* Copy controls sit together on the right of the head; the done-state block
   carries two (agent-command terminal glyph + the URL clipboard). */
.command-block-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Icon-only copy control on the dark command blocks (clipboard glyph,
   checkmark while in the copied state) — quieter than four labeled
   buttons competing in the install grid. */
.command-block-copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: transparent;
  border: 1px solid #3A3350;
  border-radius: 8px;
  color: #B3AAC8;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

.command-block-copy:hover {
  color: #E4DBFF;
  border-color: #6B5F8E;
  background: rgba(228, 219, 255, 0.06);
}

.command-block-copy.copied {
  color: var(--ok);
  border-color: var(--ok);
}

/* Hover-slide label: icon-only at rest, the label expands open on hover/focus
   so a two-button row (done-state: agent command + URL) is self-explanatory
   without a permanent text label. */
.command-block-copy.has-label {
  width: auto;
  padding: 0 8px;
}

.command-block-copy-text {
  display: inline-block;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  font-family: 'JetBrains Mono';
  font-size: 0.72rem;
  transition: max-width 0.22s ease, opacity 0.18s ease, margin-left 0.22s ease;
}

.command-block-copy.has-label:hover .command-block-copy-text,
.command-block-copy.has-label:focus-visible .command-block-copy-text {
  max-width: 130px;
  opacity: 1;
  margin-left: 6px;
}

.command-block-code {
  margin: 0;
  font-family: 'JetBrains Mono';
  font-size: 0.84rem;
  line-height: 1.6;
  color: #E4DBFF;
  white-space: pre-wrap;
  word-break: break-all;
}

/* ---------- drop field: the optional-settings group (password + one-time) ----------
   Groups the two idle-state options under the choose buttons, visually set
   apart from the upload group above with a divider – three clear sections
   instead of one crowded stack. */
.dz-options {
  width: 100%;
  max-width: 420px;
  margin-top: 18px;
  text-align: left;
}

/* Quiet, centered disclosure trigger – reads as an option, not a headline.
   The default triangle marker is removed for a cleaner line; a small caret
   is drawn instead so open/closed is still obvious. */
.dz-options > summary {
  list-style: none;
  cursor: pointer;
  text-align: center;
  font-size: 0.82rem;
  color: var(--muted);
  user-select: none;
  transition: color 0.15s;
}

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

.dz-options > summary::before {
  content: '+ ';
  font-weight: 600;
}

.dz-options[open] > summary::before {
  content: '– ';
}

.dz-options > summary:hover {
  color: var(--ink);
}

.dz-options-body {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ---------- drop field: in-field password ---------- */
.dz-password {
  width: 100%;
  text-align: left;
}

.dz-password .field {
  margin: 0;
}

.dz-password label {
  font-size: 0.85rem;
}

/* ---------- drop field: one-time (delete after first download) ---------- */
.dz-onetime {
  width: 100%;
  text-align: left;
}

.dz-onetime-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--ink);
}

.dz-onetime-hint {
  margin: 6px 0 0;
  font-size: 0.82rem;
  color: var(--muted);
}

/* ---------- drop field: done state (replaces the drop content in place) ---------- */
.dz-done {
  width: 100%;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  /* Same gap as .dz-working so the head→link-block distance is pixel-identical
     in both states (see .dz-foot) — the copy controls must not move when the
     upload finishes and this state replaces the working one. */
  gap: 12px;
  text-align: left;
}

.dz-done-head {
  text-align: center;
  font-size: 1.02rem;
  color: var(--ink);
  margin: 0 0 2px;
}

.dz-done-head b {
  color: #0f7a56;
  font-weight: 700;
}

@media (prefers-color-scheme: dark) {
  .dz-done-head b {
    color: #2fbd86;
  }
}

.dz-done-block {
  width: 100%;
}

/* Muted expiry line — metadata, not a headline. Sits in the footer slot BELOW
   the link block (not above it) so the copy controls keep their position. */
.dz-done-expiry {
  text-align: center;
  color: var(--muted);
  font-size: 0.84rem;
  margin: 0;
}

.dz-done-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
  margin: 0;
}

/* Working state that already carries the (link-ready, still-uploading) result
   widgets — same column shape as .dz-done so the link block, status line, and
   progress bar stack tidily instead of the bare centered percentage. */
.dz-working {
  width: 100%;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: center;
}

/* Fixed-height footer slot shared by the working (link-ready) and done states.
   The dropzone is vertically centered (min-height + justify-content:center), so
   a taller done state would otherwise re-center everything and slide the copy
   buttons upward the instant the upload lands — forcing a re-aim. Reserving the
   same height here for both footers (progress readout vs. expiry + "Send
   another") keeps the total block height constant, so the link + copy controls
   stay put. */
.dz-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  min-height: 64px;
  width: 100%;
  text-align: center;
}

/* .dz-foot centers its children, but the progress bar should still span the
   column the way it did as a direct .dz-working child (which stretched it). */
.dz-foot > progress {
  width: 100%;
}

/* The live percentage under the revealed link — quieter than the head. */
.dz-working-status {
  text-align: center;
  margin: 0;
}

/* ---------- API key rows: details left, Revoke inline right ---------- */
.key-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

.key-row:last-child {
  border-bottom: none;
}

.key-row-info {
  min-width: 0;
}

.key-row-info p {
  margin: 0;
}

.key-row-meta {
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 2px;
}

.key-row .btn {
  flex-shrink: 0;
}

/* ---------- landing: footer ---------- */
footer {
  border-top: 1px solid var(--line);
  padding: 44px 0;
}

.foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}

.foot .tag {
  color: var(--muted);
  font-size: 0.9rem;
  max-width: 34ch;
  margin-top: 10px;
}

.foot-links {
  display: flex;
  gap: 26px;
  flex-wrap: wrap;
}

.foot-links a {
  color: var(--muted);
  font-size: 0.9rem;
  transition: color 0.15s;
}

.foot-links a:hover {
  color: var(--grape);
}

/* ---------- global footer: grouped link columns (Footer.tsx) ---------- */
.foot-groups {
  display: flex;
  gap: 48px;
  flex-wrap: wrap;
}

.foot-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 120px;
}

.foot-group-title {
  font-family: 'JetBrains Mono';
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0.8;
  margin-bottom: 2px;
}

.foot-group a {
  color: var(--muted);
  font-size: 0.9rem;
  transition: color 0.15s;
}

.foot-group a:hover {
  color: var(--grape);
}

.fineprint {
  margin-top: 28px;
  font-family: 'JetBrains Mono';
  font-size: 0.75rem;
  color: #A59DB2;
}

.fineprint a {
  color: #8A8296;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.15s;
}

.fineprint a:hover {
  color: var(--grape);
}

/* ---------- sign-in modal (UNIF-03) ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(23, 20, 27, 0.5);
  backdrop-filter: blur(2px);
}

.modal {
  position: relative;
  width: 100%;
  max-width: 420px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
  animation: modal-in 0.18s ease;
}

.modal h2 {
  font-family: 'Space Grotesk';
  font-weight: 600;
  font-size: 1.3rem;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
}

.modal-copy {
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.5;
  margin: 0 0 20px;
}

.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: transparent;
  border: none;
  border-radius: 8px;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  color: var(--muted);
  transition: background 0.15s, color 0.15s;
}

.modal-close:hover {
  background: var(--lilac);
  color: var(--ink);
}

@keyframes modal-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .modal {
    animation: none;
  }
}

/* ---------- standalone app pages (/keys, /profile, /device, sign-in gate,
   /privacy) ---------- one shared main-column class instead of per-page
   inline maxWidth: comfortable width and real bottom padding so the global
   Footer never sits flush against the last card. */
.page-main {
  /* Full .wrap width (1080px) – the SAME content column as the landing, so
     no subpage reads narrower than the frontpage. Long-form text stays
     readable via per-block ch caps (legal/agents/about paragraph rules),
     exactly how the landing itself handles measure (.sec-head 52ch etc.). */
  padding-top: 48px;
  padding-bottom: 96px;
}

.page-main.narrow {
  max-width: 520px;
}

/* ONE shared section rhythm for every subpage (agents, about, legal, …):
   no landing-style padding bands, just a consistent gap between blocks. */
.page-main section,
.page-main .legal-section {
  padding: 0;
  margin-top: 52px;
}

/* ---------- /privacy (legal) ---------- */
/* Width/padding come from the shared .page-main scaffold – only legal-page
   typography lives here. */

.legal-h1 {
  font-size: clamp(2rem, 5vw, 2.6rem);
  margin: 6px 0 4px;
}

.legal-updated {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0 0 20px;
}

.legal-notrack {
  background: var(--lilac);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  padding: 14px 18px;
}

.legal-section h2 {
  font-size: 1.25rem;
  margin: 36px 0 10px;
}

/* Text measure inside the full-width column – the container matches the
   landing's 1080px, the reading line stays comfortable. */
.legal-section p,
.legal-section ul,
.legal-notrack {
  max-width: 72ch;
}

.legal-contact {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.92rem;
}

/* Quiet secondary picker link inside the dropzone ("or pick a whole
   folder") — the folder input rides a text link, not a second button. */
.dz-alt {
  margin-top: 10px;
  font-family: 'JetBrains Mono';
  font-size: 0.8rem;
  color: var(--muted);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color 0.15s;
}

.dz-alt:hover {
  color: var(--grape);
}

/* ---------- share-the-app modal grid (ShareApp.tsx) ---------- */
.share-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 10px;
  margin-top: 18px;
}

.share-grid-item {
  justify-content: center;
  text-align: center;
  text-decoration: none;
}

/* ---------- /about ---------- */
/* .about-main width/padding come from the shared .page-main scaffold. */

.about-head {
  max-width: none;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 40px;
}

.about-h1 {
  font-size: clamp(2rem, 5vw, 2.8rem);
  max-width: 18ch;
}

.about-section {
  padding: 0 0 40px;
  max-width: none;
}

.about-section .kicker {
  display: block;
  margin-bottom: 10px;
}

.about-section h2 {
  font-size: clamp(1.3rem, 3vw, 1.7rem);
  max-width: 30ch;
}

.about-section p {
  color: var(--muted);
  margin: 14px 0 0;
  font-size: 1rem;
  line-height: 1.65;
  max-width: 60ch;
}

.about-section p a {
  color: var(--grape-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.about-builder {
  color: var(--muted);
  margin: 14px 0 0;
  font-size: 1rem;
  line-height: 1.65;
  max-width: 60ch;
}

.about-cta-row {
  margin-top: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* ---------- receive page: small branded landing (redesign) ---------- */
/* .receive-main width/padding come from the shared .page-main scaffold. */

.receive-hero {
  text-align: center;
  padding-bottom: 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.receive-hero-mark {
  height: 40px;
  width: auto;
  margin-bottom: 18px;
  opacity: 0.9;
}

.receive-hero .kicker {
  margin-bottom: 14px;
}

.receive-h1 {
  font-size: clamp(2rem, 5vw, 2.8rem);
  max-width: 16ch;
  margin: 0;
}

.receive-lede {
  color: var(--muted);
  font-size: clamp(1rem, 2vw, 1.12rem);
  max-width: 46ch;
  margin: 18px 0 0;
  line-height: 1.55;
}

.receive-card-slot {
  max-width: 640px;
  margin: 0 auto;
}

/* ---------- receive page: why-YAFL framing (UNIF-05) ---------- */
.receive-framing {
  margin-top: 56px;
  padding-top: 40px;
  border-top: 1px solid var(--line);
}

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

.receive-benefit h3 {
  font-family: 'Space Grotesk';
  font-weight: 600;
  font-size: 1.02rem;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
}

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

.receive-cta-row {
  justify-content: center;
  margin-top: 32px;
}

@media (max-width: 720px) {
  .receive-benefit-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- whole-app drop takeover (DROP-01) ---------- */
.drop-takeover {
  position: fixed;
  inset: 0;
  z-index: 40; /* below .modal-backdrop's 50 – a logged-out drop's auth modal still wins */
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none; /* never intercepts clicks/keyboard – window drag listeners fire regardless */
  padding: 24px;
  background: color-mix(in srgb, var(--grape-deep) 90%, transparent);
  opacity: 0;
  transform: scale(0.98);
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.drop-takeover.visible {
  opacity: 1;
  transform: scale(1);
}

.drop-takeover-inner {
  padding: 48px 56px;
  border: 2px dashed rgba(255, 255, 255, 0.55);
  border-radius: var(--radius);
}

.drop-takeover-text {
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: -0.02em;
  color: #fff;
  margin: 0;
}

.drop-takeover-sub {
  margin: 10px 0 0;
  color: rgba(255, 255, 255, 0.85);
  font-size: 1rem;
}

/* When the immersive 3D world is rendering behind the overlay, drop the solid
   grape background so the world shows through — the dashed frame and text stay
   as the "release to send" affordance, now floating in the void. */
.drop-takeover.over-world {
  background: radial-gradient(
    ellipse at center,
    transparent 42%,
    color-mix(in srgb, #0d0a16 72%, transparent) 100%
  );
}
.drop-takeover.over-world .drop-takeover-inner {
  border-color: rgba(237, 228, 255, 0.5);
}

@media (prefers-reduced-motion: reduce) {
  .drop-takeover {
    transition: opacity 0.01s linear;
    transform: none;
  }
  .drop-takeover.visible {
    transform: none;
  }
}

/* ---------- immersive world stage: progress + result in space ---------- */
/* Floats above the 3D canvas (z 45 > world 39) and holds the upload progress
   readout, then the result widgets. Centered, its own click surface (the
   canvas below is pointer-events:none, so the copy buttons/Send another here
   are what receive clicks). */
.world-stage {
  position: fixed;
  inset: 0;
  z-index: 45;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  pointer-events: none;
}

.world-stage-progress,
.world-stage-result {
  pointer-events: auto;
  width: 100%;
  max-width: 460px;
  text-align: center;
  color: #fff;
}

.world-stage-pct {
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: clamp(2.6rem, 8vw, 4rem);
  letter-spacing: -0.02em;
  line-height: 1;
  color: #fff;
  text-shadow: 0 0 32px color-mix(in srgb, var(--world-accent, #8f6bff) 80%, transparent);
}

.world-stage-bar {
  margin: 18px auto 10px;
  width: 100%;
  max-width: 320px;
  height: 6px;
  border-radius: 999px;
  background: rgba(237, 228, 255, 0.18);
  overflow: hidden;
}

.world-stage-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--world-accent, #8f6bff), #ffffff);
  box-shadow: 0 0 16px color-mix(in srgb, var(--world-accent, #8f6bff) 85%, transparent);
  transition: width 0.2s ease;
}

.world-stage-caption {
  margin: 0;
  font-size: 0.9rem;
  color: rgba(237, 228, 255, 0.82);
}

/* Result widgets floating in the space — a translucent glass panel so the
   world still breathes behind the links. */
.world-stage-result {
  background: rgba(13, 10, 22, 0.55);
  border: 1px solid rgba(237, 228, 255, 0.18);
  border-radius: var(--radius);
  padding: 28px 26px;
  backdrop-filter: blur(10px);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.world-stage-head {
  margin: 0;
  font-family: 'Space Grotesk';
  font-weight: 700;
  font-size: 1.15rem;
  color: #fff;
}

.world-stage-expiry {
  margin: 0;
  font-size: 0.84rem;
  color: rgba(237, 228, 255, 0.7);
}

.world-stage-block {
  width: 100%;
}

/* Fixed-height footer slot shared by the link-ready and done panels. Swaps the
   upload progress readout for the expiry + "Send another" without changing the
   panel's total height, so the centered stage does not re-center and the copy
   controls stay put under the pointer when the upload lands. */
.world-stage-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  min-height: 64px;
  width: 100%;
}

/* The progress bar carries its own margins for the standalone dive readout;
   inside the footer the flex gap handles spacing, so neutralise them here. */
.world-stage-foot .world-stage-bar {
  margin: 0 auto;
}

.world-stage-again {
  align-self: center;
  margin: 0;
  color: #fff;
  border-color: rgba(237, 228, 255, 0.4);
}
.world-stage-again:hover {
  background: rgba(237, 228, 255, 0.12);
}

/* ---------- immersive drop world (WORLD-01) ---------- */
/* Full-viewport Three.js backdrop that fades in on drag. Sits above page
   content (z 39) but below the drop-takeover text (z 40) and the auth modal
   (z 50). pointer-events:none so it never blocks the drop or any click. */
.immersive-world {
  position: fixed;
  inset: 0;
  z-index: 39;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.immersive-world.engaged {
  opacity: 1;
}

.immersive-world-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

@media (prefers-reduced-motion: reduce) {
  /* Belt and suspenders: the component already renders null under
     reduced-motion, but keep the layer inert if that ever changes. */
  .immersive-world {
    display: none;
  }
}

/* ---------- responsive ---------- */
@media (max-width: 820px) {
  .app-bar nav .lnk {
    display: none;
  }

  .menu-links .lnk {
    display: none;
  }

  .grid {
    grid-template-columns: 1fr;
  }

  .panes {
    grid-template-columns: 1fr;
  }

  .rings {
    width: auto;
    height: 56px;
    border: none;
    border-top: 1px dashed var(--term-line);
    border-bottom: 1px dashed var(--term-line);
  }

  /* stacked panes: file flows downward – angle points down */
  .rings .chev {
    animation: handoffV 2.8s ease-in-out infinite;
  }

  .pane:first-of-type {
    border-bottom: 1px solid var(--term-line);
  }

  .install-blocks {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rings .chev {
    animation: none !important;
    opacity: 0.9 !important;
  }
}

/* ---------- /agents/ docs page ---------- */
/* AgentsPage.tsx (the former static public/agents/index.html, now an SPA
   route). Docs column: narrower 820px band under the same 1080px .wrap
   Header/Footer every page shares. Only rules app.css lacked are added
   here — .console/.console-top/.tl/.console-title/.kicker/.lede/.btn/.card
   all reuse the existing landing rules above. */
/* .agents-main width/padding come from the shared .page-main scaffold. */

.agents-main h1 {
  font-size: clamp(2rem, 5vw, 2.9rem);
  letter-spacing: -0.03em;
  line-height: 1.15;
  margin: 14px 0 6px;
  max-width: 16ch;
}

.agents-main .lede {
  font-size: 1.05rem;
  max-width: 56ch;
  margin: 14px 0 0;
}

/* Section rhythm comes from the shared .page-main section rule. */

.agents-main h2 {
  font-weight: 600;
  font-size: 1.4rem;
  letter-spacing: -0.02em;
  line-height: 1.3;
  margin: 0 0 6px;
}

.agents-main h2 .num {
  font-family: 'JetBrains Mono';
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--grape);
  letter-spacing: 0.05em;
  margin-right: 10px;
}

.agents-main section > p {
  margin: 0 0 16px;
  color: var(--muted);
  max-width: 70ch;
}

.agents-main section > p:first-of-type {
  margin-top: 6px;
}

.agents-main section > p b {
  color: var(--ink);
  font-weight: 600;
}

code.inline {
  font-family: 'JetBrains Mono';
  font-size: 0.88em;
  background: var(--lilac);
  color: var(--grape-deep);
  padding: 0.1em 0.4em;
  border-radius: 5px;
}

ul.plain-list {
  margin: 16px 0;
  padding-left: 22px;
}

ul.plain-list li {
  margin-bottom: 10px;
  color: var(--ink);
}

.agents-main .console {
  margin: 18px 0;
}

.agents-main .console pre {
  margin: 0;
  padding: 20px clamp(16px, 3vw, 26px);
  font-family: 'JetBrains Mono';
  font-size: 0.84rem;
  line-height: 1.7;
  color: var(--term-fg);
  overflow-x: auto;
  white-space: pre;
}

/* .key/.str token colors already exist (landing console demo); the docs
   page additionally dims punctuation and comments */
.agents-main .punc,
.agents-main .cmt {
  color: var(--term-dim);
}

.host-block {
  margin-top: 30px;
}

.host-block:first-of-type {
  margin-top: 20px;
}

.host-block h3 {
  font-family: 'Space Grotesk';
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.host-label {
  font-family: 'JetBrains Mono';
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 20px;
}

.host-label.verified {
  background: var(--lilac);
  color: var(--grape-deep);
  border: 1px solid #DCC9FF;
}

.host-label.docs-only {
  background: var(--card);
  color: var(--muted);
  border: 1px solid var(--line);
}

.host-block p {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 0.94rem;
}

.agents-main .host-block .console {
  margin: 12px 0;
}

.card-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 20px;
}

.card-row .card h3 {
  font-size: 1.05rem;
}

.card-row .card p {
  margin: 0 0 14px;
  font-size: 0.94rem;
}

.note {
  background: var(--lilac);
  border: 1px solid #DCC9FF;
  border-radius: var(--radius);
  padding: 16px 20px;
  margin: 20px 0;
  font-size: 0.94rem;
}

.note a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

@media (max-width: 640px) {
  .card-row {
    grid-template-columns: 1fr;
  }
}

/* ---------- SEO content-hub pages (/mcp, /faq, /compare/*, /guides/* + the
   /guides and /compare hub indexes) ----------
   The app's base `a` has `text-decoration: none`, so in-prose and hub links
   render with no affordance. Give content links a light-grey dotted underline
   (the same treatment as .dz-alt) so they read clearly as links on the cream
   paper without shouting, strengthening to the brand color on hover. Scoped to
   .page-main content + .hub-list; header/footer/CTA-button links keep their own
   styles (excluded via :not(.btn):not(.brand)). */
.page-main a:not(.btn):not(.brand):not(.lnk),
.hub-list a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--muted);
  text-underline-offset: 3px;
  transition: color 0.15s ease, text-decoration-color 0.15s ease;
}

.page-main a:not(.btn):not(.brand):not(.lnk):hover,
.hub-list a:hover {
  color: var(--grape);
  text-decoration-color: var(--grape);
}

/* External links (anything not on yafl.dev) get a small north-east arrow
   appended and open in a new tab (markdown-lite adds target/rel). Internal
   links (relative, or absolute yafl.dev) are excluded. */
.page-main a[href^="http"]:not([href*="//yafl.dev"]):not(.btn)::after {
  content: " \2197"; /* ↗ north-east arrow */
  font-size: 0.8em;
  color: var(--muted);
}

/* Hub index list: the /guides and /compare pages list their section's pages. */
.hub-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 14px;
}

.hub-list li {
  border-bottom: 1px dotted var(--line);
  padding-bottom: 14px;
}

.hub-list li:last-child {
  border-bottom: none;
}

.hub-list a {
  font-weight: 600;
}

.hub-list p {
  margin: 4px 0 0;
  color: var(--muted);
  max-width: 72ch;
}

/* Comparison tables: light formatting — thin --line row separators, a bolder
   header underline, comfortable padding, a very subtle zebra, and a muted
   semibold first column (the row label). Calm, not heavy-bordered. */
.page-main table {
  width: 100%;
  border-collapse: collapse;
  margin: 20px 0;
  font-size: 0.95rem;
}

.page-main thead th {
  text-align: left;
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2px solid var(--line);
  padding: 9px 12px;
}

.page-main tbody td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.page-main tbody tr:last-child td {
  border-bottom: none;
}

.page-main tbody tr:nth-child(even) td {
  background: rgba(23, 20, 27, 0.02);
}

.page-main tbody td:first-child {
  font-weight: 600;
  color: var(--muted);
}

@media (max-width: 640px) {
  .page-main table {
    font-size: 0.88rem;
  }
  .page-main thead th,
  .page-main tbody td {
    padding: 7px 9px;
  }
}

/* Profile email edit-in-place (PROF-02): a pencil toggle swaps the read-only
   address for an input; the pending state uses the shared .note box. */
.email-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.email-row p {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}
.icon-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border: none;
  background: none;
  color: inherit;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.12s ease;
}
.icon-btn:hover,
.icon-btn:focus-visible {
  opacity: 1;
}
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}

/* Fenced code blocks on the content-hub pages (e.g. the /mcp config block).
   Without this the block has no overflow handling and a wide line (the JSON
   config) pushes the whole page sideways on mobile. Contained as a terminal
   widget matching the /agents console: the box scrolls on its own, the page
   never does. Padding lives on the inner <code> so it scrolls with the
   content (a right pad that survives horizontal scroll). Theme-aware. */
.page-main pre {
  margin: 22px 0;
  background: var(--term);
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: 6px 6px 0 rgba(23, 20, 27, 0.16);
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.page-main pre code {
  display: block;
  background: none;
  padding: 20px clamp(16px, 3vw, 26px);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 0.84rem;
  line-height: 1.7;
  white-space: pre;
  color: var(--term-fg);
}

/* Copy button for content-hub code blocks (copy-code.js wraps each <pre>).
   The wrapper does not scroll, so the button holds the top-right corner while
   the <pre> inside scrolls. Light-on-dark to sit on the terminal box. */
.page-main .code-wrap {
  position: relative;
}
.copy-code-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--term-fg);
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.copy-code-btn:hover,
.copy-code-btn:focus-visible {
  opacity: 1;
  background: rgba(255, 255, 255, 0.16);
}
.copy-code-btn.copied {
  opacity: 1;
  color: #7cf5b0;
}
