/* Reader Beware -- advertisement site (github.io) */
:root {
  --ink: #f2ecf5;
  --ink-dim: #c3b9cc;
  /* Every text/background pair on the site must clear WCAG 2.2 AA (4.5:1
     for normal text); site/scripts/contrast_audit.py re-checks them in CI,
     which is why --ink-faint sits at #9c95ad and not a dimmer lilac-grey. */
  --ink-faint: #9c95ad;
  --black: #0b0a10;
  --grey: #17161f;
  --grey-2: #211e29;
  --line: #3a3348;
  --pink: #ff6ec7;
  --pink-soft: #ffb0df;
  --purple: #a06ae8;
  --purple-deep: #7b4fd0;
  --lilac: #c9a8ff;
  --danger: #ff5c7a;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--black);
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", serif;
  font-size: 18px;
  line-height: 1.65;
}
code, pre, .mono, button, input { font-family: "DejaVu Sans Mono", Menlo, monospace; }
a { color: var(--pink-soft); text-decoration: none; }
a:hover { color: var(--pink); text-decoration: underline; }
h1, h2, h3 { color: var(--lilac); font-weight: 600; line-height: 1.2; }

nav.topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 1rem;
  padding: .7rem 1.4rem;
  background: rgba(11, 10, 16, .92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
nav.topbar a.brand { font-weight: bold; color: var(--ink); font-size: 1.05rem; }
nav.topbar a.brand b { color: var(--pink); }
nav.topbar .links { display: flex; gap: .9rem; margin-left: auto; font-size: .9rem; }
/* the nav links are hidden below 760px, which strands them on a phone with
   no way to reach the sections; show them as a wrapping strip instead */
nav.topbar { flex-wrap: wrap; }
/* keyboard-only entry point, visually hidden until focused */
.skip-link {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}
.skip-link:focus, .skip-link:focus-visible {
  position: fixed; left: .8rem; top: .6rem; z-index: 100;
  width: auto; height: auto; padding: .5rem .9rem;
  background: var(--grey-2); color: var(--pink-soft);
  border: 1px solid var(--pink); border-radius: 6px;
}
:focus-visible { outline: 2px solid var(--pink); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

.hero {
  position: relative; overflow: hidden;
  padding: 5rem 1.4rem 4rem; text-align: center;
}
.hero::before {
  content: ""; position: absolute; inset: -20% 0 0 0; height: 130%;
  background:
    radial-gradient(900px 420px at 85% 12%, #4a2f6e55 0%, transparent 60%),
    radial-gradient(700px 380px at 10% 30%, #7b4fd040 0%, transparent 55%),
    radial-gradient(500px 300px at 50% 90%, #ff6ec722 0%, transparent 60%);
  pointer-events: none;
}
.hero h1 { font-size: clamp(2.4rem, 7vw, 4.4rem); margin: .2em 0; letter-spacing: .02em; }
.hero h1 .pink { color: var(--pink); }
.hero .tagline { color: var(--ink-dim); font-size: clamp(1.05rem, 2.4vw, 1.4rem); max-width: 60ch; margin: 1rem auto; }
.hero .cta-row { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; margin-top: 2rem; }
.btn {
  display: inline-block; padding: .65rem 1.3rem; border-radius: 6px;
  /* white text on the #a06ae8 top stop measured 3.7:1; #8a55d6 carries the
     same violet at 4.8:1, so the button clears AA across its whole face */
  background: linear-gradient(180deg, #8a55d6, var(--purple-deep));
  color: #fff !important; border: 1px solid rgba(255, 110, 199, .4);
  font-size: .95rem;
}
.btn:hover { background: var(--pink); color: #140712 !important; }
.btn.ghost { background: transparent; color: var(--ink-dim) !important; border-color: var(--line); }

section.wrap { max-width: 1040px; margin: 0 auto; padding: 3rem 1.4rem; }
section.wrap > h2 { font-size: 2rem; }
section.wrap > h2 .num { color: var(--pink); }
.lede { color: var(--ink-dim); max-width: 68ch; }
.card-panel {
  background: var(--grey); border: 1px solid var(--line);
  border-radius: 10px; padding: 1.4rem 1.6rem; margin: 1.2rem 0;
}
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; }
.grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.4rem; }
.feature h3 { margin-top: 0; color: var(--pink-soft); font-size: 1.1rem; }
.feature p { color: var(--ink-dim); font-size: .95rem; }

figure.shot { margin: 1.6rem 0; text-align: center; }
figure.shot img,
figure.shot iframe.embed {
  width: 100%; height: auto; border-radius: 8px;
  border: 1px solid var(--line); box-shadow: 0 12px 40px rgba(0,0,0,.6);
  background: #0b0a10;
}
figure.shot.device img { width: auto; max-width: 320px; border: none; box-shadow: none; }
figure.shot figcaption { color: var(--ink-faint); font-size: .85rem; margin-top: .6rem; }
/* Rendered examples embed the real build output via srcdoc.  Each embed
   carries its own aspect ratio inline (one per example, written by the
   render script) and no height of its own: width fills the figure, height
   follows the ratio.  Height must stay unset here -- an explicit height:
   auto on a replaced element falls back to the user agent default (~150px)
   before the ratio gets any say, which is what collapsed every demo to a
   letterbox strip.  overflow: hidden keeps a scrolled page inside the
   rounded frame instead of drawing a scrollbar across it. */
iframe.embed {
  display: inline-block; vertical-align: bottom;
  width: min(920px, 100%); max-width: 100%;
  border: 1px solid var(--line); border-radius: 8px;
  background: #0b0a10; overflow: hidden;
}
/* the framed e-reader embeds: small and centred like the cover image */
figure.shot.device iframe.embed {
  width: min(420px, 90vw); max-width: 100%;
  aspect-ratio: 420 / 760;
  border: none; box-shadow: none; background: transparent;
}
.figrow { display: flex; gap: 1.4rem; align-items: center; flex-wrap: wrap; justify-content: center; }
.figrow figure.shot { flex: 1 1 300px; }

pre.code, code.inline {
  background: var(--grey-2); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink-dim); font-size: .85rem; overflow-x: auto;
}
pre.code { padding: 1rem 1.2rem; }
code.inline { padding: .1rem .4rem; font-size: .9em; color: var(--pink-soft); }
pre.code .cm { color: var(--ink-faint); }
pre.code .hl { color: var(--pink-soft); }

.steps ol { counter-reset: step; padding-left: 0; list-style: none; }
.steps li { counter-increment: step; position: relative; padding: .9rem 0 .9rem 3.2rem; border-bottom: 1px dashed var(--line); }
.steps li::before {
  content: counter(step); position: absolute; left: 0; top: .85rem;
  width: 2rem; height: 2rem; border-radius: 50%;
  background: var(--grey-2); border: 1px solid var(--pink); color: var(--pink-soft);
  display: flex; align-items: center; justify-content: center; font-weight: bold;
}
.steps li b { color: var(--ink); }

.booklist { list-style: none; padding: 0; }
.booklist li { padding: .5rem 0; border-bottom: 1px dashed var(--line); display: flex; gap: .6rem; align-items: baseline; }
.booklist li::before { content: "\2724"; color: var(--pink); }

footer {
  border-top: 1px solid var(--line); padding: 2.5rem 1.4rem; text-align: center;
  color: var(--ink-faint); font-size: .9rem;
}
footer .big { font-size: 1.2rem; color: var(--pink-soft); }

/* the embeds are dark-themed documents; declaring that keeps a reader
   agent from dropping its own light form-control defaults over them */
iframe.embed { color-scheme: dark; }

/* Zoom-on-click lightbox (see zoom.js).  The authored sizing above is
   only the no-javascript fallback: once zoom.js runs it lays every
   embed out as a thumbnail of one uniform height (width following the
   capture's true aspect ratio), because the inline ratios alone made
   the tall portrait captures tower over the page and the wide studio
   captures flatten into strips.  Clicking a thumbnail -- on a
   transparent button covering the figure, so exactly one click is
   swallowed before the live demos become interactive -- expands that
   same iframe almost full screen above a dark backdrop; clicking the
   backdrop anywhere outside the frame, or escape, closes it again.
   The !important declarations outvote the inline width/height the
   script writes on thumbnails and the authored aspect-ratio alike. */
figure.shot { position: relative; }
button.zoom-button {
  position: absolute; inset: 0; margin: 0; padding: 0;
  background: transparent; border: 0; cursor: zoom-in; z-index: 1;
}
button.zoom-button:focus-visible {
  outline: 2px solid var(--pink); outline-offset: -3px;
}
#zoom-backdrop {
  position: fixed; inset: 0; display: none;
  background: rgba(8, 7, 12, .8); cursor: zoom-out; z-index: 1000;
}
body.zoom-open { overflow: hidden; }
iframe.embed.zoomed {
  aspect-ratio: auto !important;
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(1400px, 95vw) !important; height: 92vh !important;
  z-index: 1001; box-shadow: 0 30px 90px rgba(0, 0, 0, .85);
}
/* the mock e-readers zoom as phones: a device-shaped box just large
   enough for the framed screen, not a wide browser frame */
iframe.embed.zoomed[data-device] {
  width: min(480px, 95vw) !important; height: min(94vh, 860px) !important;
}

@media (max-width: 760px) {
  .grid2, .grid3 { grid-template-columns: 1fr; }
}
