/* OpenLabs landing page styles.
 *
 * Lifted from the original single-file document, then extended with the
 * multi-page layer: each former scroll section is now its own route, and
 * navigation between routes is a directional pane slide driven by the View
 * Transitions API (see the #content / page-content rules near the bottom).
 *
 * ---------------------------------------------------------------------
 * RESPONSIVE SYSTEM — deliberately identical to illuminodes-landing-page
 * ---------------------------------------------------------------------
 * That site is built on Tailwind v4, so its responsive behaviour is
 * Tailwind's defaults. We are hand-written CSS, so the same system is
 * reproduced explicitly here rather than inherited from a framework:
 *
 *   Breakpoints (min-width, mobile-first — Tailwind's defaults):
 *     sm  40rem / 640px
 *     md  48rem / 768px
 *     lg  64rem / 1024px
 *     xl  80rem / 1280px
 *
 *   Type scale (--fs-*): Tailwind's text-xs .. text-8xl, verbatim.
 *
 *   Layout model: `h-dvh overflow-hidden` app shell — the PAGE never
 *   scrolls. Nav and footer are `shrink-0`; #content is
 *   `flex-1 min-h-0 overflow-y-auto`, i.e. the only scroll container, and
 *   on md+ it doesn't scroll either (each route is one screen). This is
 *   what makes the pane-slide transition read as panels moving on a fixed
 *   canvas rather than as documents replacing each other.
 *
 *   Content padding: pl-6 pr-6 py-4 -> sm:pl-20 sm:pr-14 sm:py-8.
 *   Nav padding: px-4 py-2 -> sm:px-14 sm:py-3.
 *
 * The ONE intentional divergence is where the inline nav collapses into
 * the mobile stepper. Illuminodes switches at `sm` because it has three
 * nav links; we have six plus a CTA, which do not fit a 640px bar. Ours
 * switches at `lg` instead. Everything else — every breakpoint value,
 * every font step, every padding pair — matches.
 */

:root{
  --paper:#111111; --muted:#343434; --ink:#F8F9FA; --muted-fg:#E9ECEF;
  --bitcoin:#f7931a; --nostr:#662482; --nostr-light:#a334d5; --elsalvador:#0047ab;

  /* Tailwind's default type scale, reproduced verbatim so every step on
     this site lands on exactly the same size as the illuminodes one. */
  --fs-xs:0.75rem;   --lh-xs:1.3333;
  --fs-sm:0.875rem;  --lh-sm:1.4286;
  --fs-base:1rem;    --lh-base:1.5;
  --fs-lg:1.125rem;  --lh-lg:1.5556;
  --fs-xl:1.25rem;   --lh-xl:1.4;
  --fs-2xl:1.5rem;   --lh-2xl:1.3333;
  --fs-3xl:1.875rem; --lh-3xl:1.2;
  --fs-4xl:2.25rem;  --lh-4xl:1.1111;
  --fs-5xl:3rem;     --lh-5xl:1;
  --fs-6xl:3.75rem;  --lh-6xl:1;
  --fs-7xl:4.5rem;   --lh-7xl:1;
  --fs-8xl:6rem;     --lh-8xl:1;

  /* The content column's inset, flipped by the sm media query below.
     Asymmetric like illuminodes': a deep left gutter, a shallower right
     one, so copy sits off-centre the way the original does. */
  --pad-x-l:1.5rem;  /* pl-6  -> sm:pl-20 */
  --pad-x-r:1.5rem;  /* pr-6  -> sm:pr-14 */
  --pad-y:1rem;      /* py-4  -> sm:py-8  */

  /* Nav chrome inset: px-4 py-2 -> sm:px-14 sm:py-3. */
  --nav-x:1rem;
  --nav-y:0.5rem;
}

@media(min-width:40rem){
  :root{ --pad-x-l:5rem; --pad-x-r:3.5rem; --pad-y:2rem; --nav-x:3.5rem; --nav-y:0.75rem; }
}

*{box-sizing:border-box;margin:0;padding:0}

/* App shell: the document itself never scrolls. Only #content does, and
   only below md — see the #content rules. Matches illuminodes'
   `h-dvh w-dvw overflow-hidden` body. */
html,body{height:100dvh}
body{
  background:var(--paper);color:var(--ink);
  font-family:"SF Pro Text",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  line-height:1.6;-webkit-font-smoothing:antialiased;
  display:flex;flex-direction:column;overflow:hidden;
}
a{color:inherit;text-decoration:none}
.mono{font-family:"SF Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

/* The content column's inset. Replaces the old centred `max-width` wrap:
   illuminodes has no centred container, it runs full-bleed with an
   asymmetric gutter, and the vertical rhythm comes from the flex shell. */
.wrap{width:100%;padding:var(--pad-y) var(--pad-x-r) var(--pad-y) var(--pad-x-l)}

.eyebrow{display:inline-flex;align-items:center;font-size:0.65rem;letter-spacing:0.08em;
  text-transform:uppercase;padding:0.125rem 0.625rem;border:1px solid var(--ink);color:var(--ink);
  width:fit-content;user-select:none}
@media(min-width:40rem){
  .eyebrow{font-size:var(--fs-xs);padding:0.25rem 0.75rem}
}

/* Brand wordmark */
.brand{display:flex;align-items:center;margin-right:auto;cursor:pointer}
.ollogo{height:auto;display:block;width:auto;object-fit:contain}
nav.site .ollogo{height:22px}
footer .ollogo{height:18px}
@media(min-width:40rem){
  nav.site .ollogo{height:26px}
  footer .ollogo{height:22px}
}

/* Nav — `shrink-0` chrome, never swapped by htmx. */
nav.site{
  flex:none;position:relative;z-index:50;background:var(--paper);
  border-bottom:1px solid rgba(248,249,250,0.12);
  display:flex;align-items:center;gap:0.75rem;
  padding:var(--nav-y) var(--nav-x);
}
@media(min-width:40rem){nav.site{gap:1.5rem}}
nav.site .links{display:none;gap:1.5rem;font-size:var(--fs-sm);color:rgba(248,249,250,0.7)}
nav.site .links a:hover{color:var(--nostr-light)}
/* Current page in the nav: brightened and bolded. Set by markActiveNav()
   after every swap, since the nav itself is never re-rendered. */
nav.site .links a[aria-current="page"]{color:var(--ink);font-weight:700}

/* Buttons: text-xs px-4 py-2 -> sm:text-sm sm:px-5 sm:py-3, as illuminodes. */
.btn{display:inline-flex;align-items:center;gap:0.5rem;font-weight:700;
  font-size:var(--fs-xs);padding:0.5rem 1rem;
  transition:all .15s ease;cursor:pointer;border:1px solid transparent}
@media(min-width:40rem){.btn{font-size:var(--fs-sm);padding:0.75rem 1.25rem}}
.btn.solid{background:var(--ink);color:var(--paper)}
.btn.solid:hover{background:var(--nostr);color:#fff}
.btn.outline{background:transparent;color:var(--ink);border:1px solid rgba(248,249,250,0.4)}
.btn.outline:hover{border-color:var(--bitcoin);color:var(--bitcoin)}
/* The nav CTA keeps the tighter px-4 py-2 at every size (illuminodes'
   nav Contact button never grows to the hero button's padding). */
nav.site .btn{font-size:var(--fs-sm);padding:0.5rem 1rem}

/* Inline nav vs. mobile stepper. See the header note: we diverge from
   illuminodes' `sm` here only because seven items cannot fit a 640px bar. */
@media(min-width:64rem){
  nav.site .links{display:flex}
}
@media(max-width:63.999rem){
  nav.site .btn{margin-left:auto}
}

/* Hero.
 *
 * grid-cols-1 md:grid-cols-[1.2fr_0.8fr] — copy column wider than the
 * terminal aside, splitting only at md, exactly like illuminodes' home. */
.hero{display:grid;grid-template-columns:1fr;min-height:0}
@media(min-width:48rem){
  .hero{grid-template-columns:1.2fr 0.8fr}
}
.hero-copy{display:flex;flex-direction:column;justify-content:center;
  padding:var(--pad-y) var(--pad-x-r) var(--pad-y) var(--pad-x-l)}

/* h1: text-3xl -> sm:text-6xl -> lg:text-7xl, leading-[0.94].
   Illuminodes' hero h1 uses these three explicit steps rather than the
   base h1 scale, so we mirror the hero's steps, not the base ones. */
.hero h1{font-size:var(--fs-3xl);line-height:0.94;letter-spacing:-0.03em;
  font-weight:800;margin:0.5rem 0 0;text-wrap:balance;user-select:none}
@media(min-width:40rem){.hero h1{font-size:var(--fs-6xl);margin-top:0.75rem}}
@media(min-width:64rem){.hero h1{font-size:var(--fs-7xl)}}

/* Lead copy: text-xs sm:text-base lg:text-lg, max-w-[52ch]. */
.hero p.lead{font-size:var(--fs-xs);line-height:1.55;color:rgba(248,249,250,0.85);
  max-width:52ch;text-wrap:balance;margin-top:1.35rem}
@media(min-width:40rem){.hero p.lead{font-size:var(--fs-base)}}
@media(min-width:64rem){.hero p.lead{font-size:var(--fs-lg)}}

/* Action row: gap-2 sm:gap-3. */
.hero-actions{display:flex;gap:0.5rem;flex-wrap:wrap;margin-top:1.35rem}
@media(min-width:40rem){.hero-actions{gap:0.75rem}}

/* Terminal aside. Below md it stacks UNDER the copy with a top border;
   at md+ it becomes the right column with a left border — the same
   border-t-2 md:border-t-0 md:border-l-2 flip illuminodes uses. */
.hero-aside{background:var(--muted);
  border-top:2px solid var(--nostr);border-left:none;
  display:flex;flex-direction:column;justify-content:center;
  padding:1.75rem;position:relative;overflow:hidden;min-height:11rem}
@media(min-width:48rem){
  .hero-aside{border-top:none;border-left:2px solid var(--nostr);padding:2.5rem;min-height:0}
}
.term-label{font-size:0.65rem;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--nostr-light);margin-bottom:1rem}
@media(min-width:40rem){.term-label{font-size:var(--fs-xs);margin-bottom:1.5rem}}

/* Aside title: text-lg sm:text-2xl lg:text-3xl. Body: text-xs sm:text-base
   lg:text-lg with reserved min-heights so the typing effect doesn't reflow
   the panel — same three-step min-height ladder as illuminodes. */
.term h4{font-size:var(--fs-lg);font-weight:800;color:var(--muted-fg);
  margin-bottom:0.375rem;min-height:1.75rem}
.term p{font-size:var(--fs-xs);line-height:1.5;color:rgba(233,236,239,0.8);min-height:3.5rem}
@media(min-width:40rem){
  .term h4{font-size:var(--fs-2xl);margin-bottom:0.75rem;min-height:2.25rem}
  .term p{font-size:var(--fs-base);min-height:6.5rem}
}
@media(min-width:64rem){
  .term h4{font-size:var(--fs-3xl);min-height:2.75rem}
  .term p{font-size:var(--fs-lg);min-height:5rem}
}
.term .cursor{display:inline-block;width:0.5em;height:1.05em;background:var(--nostr-light);
  vertical-align:text-bottom;margin-left:0.08em;animation:blink .9s step-end infinite}
@keyframes blink{0%,100%{opacity:1}50%{opacity:0}}

/* Slide dots: h-1.5 w-6 pills, gap-2, pinned bottom-left of the aside on
   md+ (bottom-6 left-10) and in flow below that. */
.dots{display:flex;gap:0.5rem;margin-top:1.5rem}
.dots span{width:1.5rem;height:0.375rem;background:rgba(233,236,239,0.3);cursor:pointer;
  transition:background .15s ease}
.dots span:hover{background:var(--nostr)}
.dots span.on{background:var(--nostr-light)}
@media(min-width:48rem){
  .dots{position:absolute;bottom:1.5rem;left:2.5rem;margin-top:0}
}

/* Sections.
 *
 * Each section is a whole page rather than a slice of one long scroll, so
 * it fills the content area and centres vertically. Padding comes from
 * .wrap, i.e. the same pl-6/sm:pl-20 gutter the hero copy uses. */
section.blk{display:flex;align-items:center;min-height:100%}
section.blk > .wrap{width:100%}

/* Section label: text-[0.65rem] sm:text-xs, tracking-wide. */
.sec-label{font-size:0.65rem;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--bitcoin);margin-bottom:0.5rem;font-weight:700}
@media(min-width:40rem){.sec-label{font-size:var(--fs-xs);margin-bottom:0.75rem}}
.sec-label.purple{color:var(--nostr-light)}

/* Section title mirrors the base h2 ladder: text-4xl md:text-5xl lg:text-6xl.
   (Capped at 5xl on lg rather than following on to 6xl/7xl, because these
   titles share a screen with a dense grid below them, where illuminodes'
   h2 sits alone above prose.) */
.sec-title{font-size:var(--fs-3xl);line-height:1.05;letter-spacing:-0.02em;
  font-weight:800;margin-bottom:0.75rem;max-width:20ch;text-wrap:balance}
@media(min-width:48rem){.sec-title{font-size:var(--fs-4xl);margin-bottom:1rem}}
@media(min-width:64rem){.sec-title{font-size:var(--fs-5xl)}}

/* Body prose: text-base md:text-lg lg:text-xl — the base `p` ladder. */
.sec-desc{font-size:var(--fs-sm);line-height:1.6;color:rgba(248,249,250,0.78);
  max-width:60ch;margin-bottom:1.5rem;text-wrap:pretty}
@media(min-width:48rem){.sec-desc{font-size:var(--fs-base);margin-bottom:2rem}}
@media(min-width:64rem){.sec-desc{font-size:var(--fs-lg);margin-bottom:2.5rem}}

/* Two-up panels — single column until md, matching the hero's split. */
.two{display:grid;grid-template-columns:1fr;gap:0.75rem}
@media(min-width:48rem){.two{grid-template-columns:1fr 1fr;gap:1.25rem}}
.panel{border:1px solid rgba(248,249,250,0.18);padding:1.25rem}
@media(min-width:40rem){.panel{padding:1.75rem}}
.panel.bad{background:transparent}
.panel h3{font-size:var(--fs-base);font-weight:700;margin-bottom:0.5rem}
@media(min-width:40rem){.panel h3{font-size:var(--fs-lg)}}
.panel.bad h3{color:rgba(248,249,250,0.65)}
.panel.good h3{color:var(--bitcoin)}
.panel.plum{border-color:rgba(163,52,213,0.4)}
.panel.plum h3{color:var(--nostr-light)}
.panel p{font-size:var(--fs-xs);color:rgba(248,249,250,0.72)}
@media(min-width:40rem){.panel p{font-size:var(--fs-sm)}}

/* Sheet — the single-screen two-column split for dense routes.
 *
 * Stacks below md (where #content scrolls anyway); at md+ the argument sits
 * left and the artifact right, so a page that would overflow a height-locked
 * pane fits one screen. Tightens the shared type/spacing ladder inside
 * itself, since these blocks share a screen instead of owning one. */
.sheet{display:grid;grid-template-columns:1fr;gap:1.5rem;align-items:center}
@media(min-width:48rem){.sheet{grid-template-columns:1.05fr 1fr;gap:1.75rem}}
@media(min-width:64rem){.sheet{grid-template-columns:1fr 1.15fr;gap:3rem}}
.sheet-art{display:flex;flex-direction:column;gap:0.5rem;min-width:0}
@media(min-width:64rem){.sheet-art{gap:0.85rem}}
.sheet .sec-desc{margin-bottom:1.25rem}
@media(min-width:48rem){
  .sheet .sec-title{font-size:var(--fs-3xl)}
  .sheet .sec-desc{font-size:var(--fs-sm);margin-bottom:1rem}
}
@media(min-width:64rem){
  .sheet .sec-title{font-size:var(--fs-4xl)}
  .sheet .sec-desc{font-size:var(--fs-base);margin-bottom:1.5rem}
}
.sheet .hero-actions{margin-top:0}
.sheet .layer{padding:0.7rem 1rem;gap:0.15rem}
@media(min-width:48rem){.sheet .layer{grid-template-columns:1fr;padding:0.55rem 0.9rem}}
@media(min-width:64rem){.sheet .layer{padding:0.85rem 1.35rem}}
.sheet .layer .lname{font-size:var(--fs-sm);min-width:0}
.sheet .layer .ldesc{font-size:var(--fs-xs);line-height:1.4}
.sheet .panel{padding:0.7rem 0.9rem}
@media(min-width:64rem){.sheet .panel{padding:1.1rem 1.35rem}}
.sheet .panel h3{font-size:var(--fs-sm);margin-bottom:0.3rem}
.sheet .panel p{font-size:var(--fs-xs);line-height:1.4}

/* Sheet modifier: artifact left, argument right. Same grid, mirrored, so a
   second sheet route does not read as the first one again. */
@media(min-width:48rem){
  .sheet.mirror{grid-template-columns:1fr 1.05fr}
  .sheet.mirror .sheet-copy{order:2}
  .sheet.mirror .sheet-art{order:1}
}
@media(min-width:64rem){.sheet.mirror{grid-template-columns:1.15fr 1fr}}

/* Flow — a stage sequence read left to right.
 *
 * For content that is a pipeline rather than a list: the copy sits above,
 * narrow, and the stages run across the full width beneath it, so the page
 * reads horizontally where .sheet reads as two columns. Collapses to 2-up at
 * md and stacks below that. */
.flow-copy{max-width:64ch;margin-bottom:1.5rem}
.flow-copy .sec-desc{margin-bottom:1.25rem}
.flow-copy .hero-actions{margin-top:0}
@media(min-width:64rem){
  .flow-copy{max-width:72ch;margin-bottom:2rem}
  .flow-copy .sec-title{font-size:var(--fs-4xl)}
}
.flow{display:grid;grid-template-columns:1fr;gap:1px;
  background:rgba(248,249,250,0.18);border:1px solid rgba(248,249,250,0.18)}
@media(min-width:40rem){.flow{grid-template-columns:1fr 1fr}}
@media(min-width:64rem){.flow{grid-template-columns:repeat(4,1fr)}}
.flow .step{background:var(--paper);padding:0.85rem 1rem;display:flex;flex-direction:column}
@media(min-width:64rem){.flow .step{padding:1.15rem 1.25rem}}
.flow .step .num{font-size:0.65rem;letter-spacing:0.1em;color:var(--nostr-light);
  font-weight:700;margin-bottom:0.5rem}
.flow .step h3{font-size:var(--fs-sm);font-weight:700;margin-bottom:0.3rem}
@media(min-width:64rem){.flow .step h3{font-size:var(--fs-base)}}
.flow .step p{font-size:var(--fs-xs);line-height:1.45;color:rgba(248,249,250,0.7)}
/* The terminal stage is where the chain-specific part lives — tinted like
   .layer.hot so the sequence visibly lands somewhere. */
.flow .step.hot{background:rgba(102,36,130,0.14)}
.flow .step.hot .num{color:var(--bitcoin)}
/* Status line under the sequence: keeps the alpha caveat attached to the
   mechanism it qualifies. */
.flow-note{font-size:var(--fs-xs);line-height:1.5;color:rgba(248,249,250,0.6);
  margin-top:0.9rem;max-width:80ch}
.flow-note b{color:rgba(248,249,250,0.85);font-weight:700}

/* Pillars — 1 col, 2 at md, 3 at lg. */
.pillars{display:grid;grid-template-columns:1fr;gap:0;border:1px solid rgba(248,249,250,0.18)}
.pillar{padding:1.25rem;border-bottom:1px solid rgba(248,249,250,0.18)}
.pillar:last-child{border-bottom:none}
@media(min-width:40rem){.pillar{padding:1.9rem}}
@media(min-width:64rem){
  .pillars{grid-template-columns:repeat(3,1fr)}
  .pillar{border-bottom:none;border-right:1px solid rgba(248,249,250,0.18)}
  .pillar:last-child{border-right:none}
}
.pillar .num{font-size:var(--fs-xs);letter-spacing:0.1em;color:var(--nostr-light);
  margin-bottom:0.9rem;font-weight:700}
.pillar h3{font-size:var(--fs-base);font-weight:700;margin-bottom:0.5rem;line-height:1.2}
@media(min-width:40rem){.pillar h3{font-size:var(--fs-lg)}}
.pillar p{font-size:var(--fs-xs);color:rgba(248,249,250,0.72);margin-bottom:0.9rem}
@media(min-width:40rem){.pillar p{font-size:var(--fs-sm)}}
.pillar .prim{font-size:var(--fs-xs);color:rgba(248,249,250,0.5)}

/* Stack — the label column collapses above its description below sm. */
.stack{display:flex;flex-direction:column;border:1px solid rgba(248,249,250,0.18)}
.layer{display:grid;grid-template-columns:1fr;gap:0.35rem;padding:1rem 1.25rem;
  border-bottom:1px solid rgba(248,249,250,0.18)}
.layer:last-child{border-bottom:none}
@media(min-width:40rem){
  .layer{grid-template-columns:auto 1fr;gap:1.5rem;padding:1.35rem 1.75rem;align-items:baseline}
}
.layer .lname{font-weight:700;font-size:var(--fs-sm);min-width:10rem}
@media(min-width:40rem){.layer .lname{font-size:var(--fs-base)}}
.layer .ldesc{font-size:var(--fs-xs);color:rgba(248,249,250,0.7)}
@media(min-width:40rem){.layer .ldesc{font-size:var(--fs-sm)}}
.layer.hot{background:rgba(102,36,130,0.14)}
.layer.hot .lname{color:var(--nostr-light)}

/* Principles — 1 col, 2 at sm, 4 at lg. */
.princ{display:grid;grid-template-columns:1fr;gap:1px;
  background:rgba(248,249,250,0.18);border:1px solid rgba(248,249,250,0.18)}
@media(min-width:40rem){.princ{grid-template-columns:1fr 1fr}}
@media(min-width:64rem){.princ{grid-template-columns:repeat(4,1fr)}}
.princ div{background:var(--paper);padding:1rem;font-size:var(--fs-xs)}
@media(min-width:40rem){.princ div{padding:1.4rem;font-size:var(--fs-sm)}}
.princ div b{display:block;color:var(--bitcoin);font-size:var(--fs-xs);
  margin-bottom:0.35rem;letter-spacing:0.04em}

/* CTA */
.cta{text-align:center;background:linear-gradient(180deg,transparent,rgba(102,36,130,0.10))}
.cta h2{font-size:var(--fs-3xl);line-height:1;letter-spacing:-0.02em;font-weight:800;
  margin-bottom:1rem;text-wrap:balance}
@media(min-width:48rem){.cta h2{font-size:var(--fs-4xl);margin-bottom:1.25rem}}
@media(min-width:64rem){.cta h2{font-size:var(--fs-5xl)}}
.cta p{font-size:var(--fs-sm);color:rgba(248,249,250,0.75);max-width:46ch;margin:0 auto 1.5rem}
@media(min-width:48rem){.cta p{font-size:var(--fs-base);margin-bottom:2rem}}
@media(min-width:64rem){.cta p{font-size:var(--fs-lg)}}
.cta .hero-actions{justify-content:center}

/* Footer — `shrink-0` chrome like the nav. Deliberately compact: in the
   fixed-viewport shell every pixel it takes is a pixel the page content
   loses, so it scales down hard on narrow screens. */
footer.site{flex:none;font-size:var(--fs-xs);color:rgba(248,249,250,0.5);
  border-top:1px solid rgba(248,249,250,0.12);
  padding:0.75rem var(--nav-x)}
@media(min-width:40rem){footer.site{font-size:var(--fs-sm);padding:1.25rem var(--nav-x)}}
footer.site .wrap{display:flex;justify-content:space-between;align-items:flex-start;
  gap:1rem;flex-wrap:wrap;padding:0}
@media(min-width:40rem){footer.site .wrap{gap:2rem}}
footer .brand{margin-bottom:0.4rem}
.fam{display:flex;gap:1rem;flex-wrap:wrap}
@media(min-width:40rem){.fam{gap:1.5rem}}
.fam a:hover{color:var(--nostr-light)}
.tag{font-size:0.65rem;letter-spacing:0.05em;color:rgba(248,249,250,0.45)}
@media(min-width:40rem){.tag{font-size:var(--fs-xs)}}
.social{display:flex;gap:0.6rem;margin-top:0.6rem}
@media(min-width:40rem){.social{gap:0.85rem;margin-top:1rem}}
.social a{display:inline-flex;align-items:center;justify-content:center;
  width:1.75rem;height:1.75rem;border:1px solid rgba(248,249,250,0.25);border-radius:50%;
  color:rgba(248,249,250,0.7);transition:all .15s ease}
@media(min-width:40rem){.social a{width:2.1rem;height:2.1rem}}
.social svg{width:0.9rem;height:0.9rem;fill:currentColor}
@media(min-width:40rem){.social svg{width:1.05rem;height:1.05rem}}

/* Below sm the footer's secondary column (family links) is dead weight in a
   viewport-locked layout — hide it and keep only the brand row. */
@media(max-width:39.999rem){
  footer.site .wrap > div:last-child{display:none}
}

/* ---------------------------------------------------------------------
   Pane navigation
   ---------------------------------------------------------------------

   #content is the only element htmx swaps. Naming it for the View
   Transitions API lets the browser animate the outgoing and incoming
   documents as two panes on a canvas instead of cross-fading them in
   place.

   It is also the app shell's only flexible row: `flex:1; min-height:0`
   makes it absorb whatever the nav and footer leave, and scroll
   internally below md. At md+ it does not scroll — every route is meant
   to fit one screen there, exactly like illuminodes' `md:overflow-hidden`. */

#content{
  position:relative;z-index:1;flex:1 1 auto;min-height:0;
  overflow-y:auto;overscroll-behavior:contain;
  view-transition-name:page-content;
}
/* Routes carrying the full argument opt out of the md+ height lock: they are
   meant to scroll, unlike the single-screen routes. */
#content.long{overflow-y:auto}

/* Marks a forward-looking claim as roadmap rather than shipped. */
.soon{font-size:0.72em;letter-spacing:0.06em;text-transform:uppercase;
  color:var(--bitcoin);border:1px solid currentColor;border-radius:2px;
  padding:0.1em 0.4em;margin-left:0.6rem;vertical-align:middle;font-weight:400}

@media(min-width:48rem){
  #content{overflow:hidden}
  #content.long{overflow-y:auto}
  /* The hero is a grid that must fill the pane at md+ so its aside column
     runs full height; below md it's content-sized and stacks. */
  #content > .hero{height:100%}
}

/* The mobile prev/next cluster is fixed chrome living OUTSIDE #content.
   Without its own transition name it'd be swept into the default
   ::view-transition-*(root) pair, which the UA paints in the top layer
   above the document for the transition's duration — so no z-index can
   save it and it visibly flashes on every navigation. Naming it promotes
   it to its own group, which we then explicitly de-animate so it simply
   stays put. */
.pane-nav-arrows{view-transition-name:pane-nav-arrows}
::view-transition-group(pane-nav-arrows){animation:none}
::view-transition-old(pane-nav-arrows),
::view-transition-new(pane-nav-arrows){animation:none;mix-blend-mode:normal}

::view-transition-group(page-content){overflow:hidden}
::view-transition-old(page-content),
::view-transition-new(page-content){
  animation-duration:.32s;
  animation-timing-function:cubic-bezier(0.22,1,0.36,1);
  mix-blend-mode:normal;
}

/* NOTE: no space before the pseudo-element. View-transition pseudos are
   rooted at <html> itself (they are not real DOM descendants), so these
   must be compound selectors — `html[attr] ::pseudo` matches nothing and
   silently falls back to the default cross-fade. JS sets data-direction
   from the nav order before each request; absent (first paint) = forward. */
html:not([data-direction='back'])::view-transition-old(page-content){animation-name:pane-out-left}
html:not([data-direction='back'])::view-transition-new(page-content){animation-name:pane-in-right}
html[data-direction='back']::view-transition-old(page-content){animation-name:pane-out-right}
html[data-direction='back']::view-transition-new(page-content){animation-name:pane-in-left}

@keyframes pane-out-left{to{transform:translateX(-100%)}}
@keyframes pane-in-right{from{transform:translateX(100%)}to{transform:translateX(0)}}
@keyframes pane-out-right{to{transform:translateX(100%)}}
@keyframes pane-in-left{from{transform:translateX(-100%)}to{transform:translateX(0)}}

/* Below md the layout stacks vertically, so a vertical slide matches it
   better than a horizontal one. Same names, different axis — and the same
   `max-width: 768px` cutover illuminodes uses for this exact rule. */
@media(max-width:768px){
  @keyframes pane-out-left{to{transform:translateY(-100%)}}
  @keyframes pane-in-right{from{transform:translateY(100%)}to{transform:translateY(0)}}
  @keyframes pane-out-right{to{transform:translateY(100%)}}
  @keyframes pane-in-left{from{transform:translateY(-100%)}to{transform:translateY(0)}}
}

@media(prefers-reduced-motion:reduce){
  ::view-transition-old(page-content),
  ::view-transition-new(page-content){animation:none}
  .term .cursor{animation:none}
}

/* Mobile prev/next stepper: shown exactly where the inline nav is hidden
   (see the lg divergence note at the top of this file), so there is always
   one and only one way to move between pages. */
.pane-nav-arrows{position:fixed;bottom:0.5rem;right:0.5rem;z-index:60;
  display:flex;flex-direction:column;gap:0.25rem}
@media(min-width:64rem){.pane-nav-arrows{display:none}}
.pane-nav-arrows button{
  display:grid;place-items:center;width:2rem;height:2rem;border-radius:50%;
  background:rgba(17,17,17,0.7);backdrop-filter:blur(4px);
  border:1px solid rgba(248,249,250,0.15);color:rgba(248,249,250,0.5);
  cursor:pointer;transition:color .15s ease,border-color .15s ease;
}
.pane-nav-arrows button:hover{color:var(--nostr-light);border-color:rgba(163,52,213,0.4)}
.pane-nav-arrows button:disabled{opacity:0;pointer-events:none}
.pane-nav-arrows svg{width:1rem;height:1rem;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
