/* Eden Online — the site. THEME.md is law: cream, sage, honey, apricot,
   charcoal. Porch light. Quiet chrome. If it looks like a crypto app, it
   failed. */

:root {
  --meadow-h: clamp(64px, 11vh, 108px);
  /* The signs sit in the four true corners on one inset. They overlap the
     grass at the bottom on purpose (Wick, 2026-08-18); the meadow is scenery,
     not a boundary. Change these two and all four corners move together. */
  --corner-x: 20px;
  --corner-y: 20px;
  --cream: #f4ece0;
  --paper: #faf5ec;
  --offwhite: #f6efe4;
  --charcoal: #3a342c;
  --faded: #6f6759;
  --honey: #c4a060;
  --honey-deep: #a87f1e;
  --apricot: #e0a46a;
  --sage: #5c7248;
  --line: rgba(58, 52, 44, 0.14);
  --shadow: 0 14px 42px rgba(42, 30, 18, 0.14);
}

* { box-sizing: border-box; }

html {
  background: var(--cream) url(/assets/frame/meadow-tile.png) repeat;
  background-size: 320px 320px;
}

html, body {
  margin: 0;
  padding: 0;
  background-color: transparent;
  color: var(--charcoal);
  font-family: ui-rounded, "SF Pro Rounded", "Hiragino Sans", Nunito, system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--honey-deep); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

img { max-width: 100%; }

.wrap { max-width: 760px; margin: 0 auto; padding: 0 22px; }

/* --- landing ------------------------------------------------------------ */

.hero { background: #6b924e; text-align: center; line-height: 0; }
.hero img { display: block; width: 100%; height: auto; }
.hero canvas { display: inline-block; }
.heroBox { position: relative; line-height: 0; max-width: 100%; max-height: 100%; }
.hero { position: relative; }

.tagline {
  text-align: center;
  font-size: clamp(19px, 3.2vw, 26px);
  padding: 44px 22px 6px;
  margin: 0 auto;
  max-width: 640px;
}

.tagline-sub {
  text-align: center;
  color: var(--faded);
  font-size: 15px;
  margin: 10px 0 0;
}

section.prose { padding: 30px 0 6px; }
section.prose p { margin: 0 0 1.1em; }
section.prose p.last { margin-bottom: 0; }

.glass {
  background: rgba(250, 245, 236, 0.87);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow);
  padding: 26px 30px;
}
.glass.chip {
  display: inline-block;
  padding: 14px 22px;
  max-width: 560px;
}

.dissolve {
  height: 42px;
  background: url(/assets/frame/dissolve.png) repeat-x top left / auto 42px;
  margin-top: -2px;
}

.divider {
  display: block;
  width: min(100%, 1280px);
  height: auto;
  margin: 26px auto;
}

.verbs {
  text-align: center;
  padding: 14px 22px 22px;
}
.verbs .label {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--faded);
  margin-bottom: 10px;
}
.verbs .list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 22px;
  align-items: flex-end;
}
.verbs .list img { height: 30px; width: auto; }

.plate { margin: 22px 0 0; }
.plate img { display: block; width: 100%; height: auto; }
.plate figcaption {
  text-align: center;
  font-size: 14px;
  color: var(--faded);
  padding: 12px 22px 0;
}

.people { text-align: center; padding: 30px 22px 8px; }
.people p { margin: 0 auto 1.2em; }
.people img.sheet {
  width: 100%;
  max-width: 960px;
  border-radius: 16px;
  box-shadow: var(--shadow);
}
.people img.one {
  width: 128px;
  image-rendering: pixelated;
  margin-bottom: 6px;
}

.door {
  display: block;
  background: rgba(250, 245, 236, 0.85);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow);
  padding: 30px 34px;
  margin: 52px auto 0;
  max-width: 560px;
  color: var(--charcoal);
}
.door:hover { text-decoration: none; border-color: var(--honey); }
.door h2 { margin: 0 0 6px; font-size: 21px; }
.door p { margin: 0 0 12px; color: var(--faded); font-size: 15px; }
.door .go { color: var(--honey-deep); font-weight: 600; }

footer {
  text-align: center;
  color: var(--faded);
  font-size: 14px;
  padding: 72px 22px 46px;
}
footer .mark { color: var(--sage); }
footer .status {
  margin-top: 14px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--faded);
}

/* --- the space between things is the garden ------------------------------ */


.gcritter {
  position: fixed;
  z-index: 4;
  image-rendering: pixelated;
  pointer-events: none;
}

/* --- the temple, taken back ---------------------------------------------- */

.glass, .chapter { position: relative; }
.retired-ivy {
  content: "";
  position: absolute;
  top: -12px;
  right: -10px;
  width: 96px;
  height: 96px;
  background: url(/assets/frame/ivy-a.png) no-repeat top right / contain;
  pointer-events: none;
}


.liana {
  position: fixed;
  top: 0;
  z-index: 68;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size: contain;
  transform-origin: top center;
  animation: sway 7s ease-in-out infinite alternate;
}
.liana.l1 { left: 9%; width: 26px; height: 122px; background-image: url(/assets/frame/liana-1.png); animation-duration: 8.5s; }
.liana.l2 { left: 46%; width: 26px; height: 170px; background-image: url(/assets/frame/liana-2.png); animation-delay: -3s; }
.liana.l3 { right: 7%; width: 26px; height: 206px; background-image: url(/assets/frame/liana-3.png); animation-duration: 9.5s; animation-delay: -6s; }
@keyframes sway {
  from { transform: rotate(-0.9deg); }
  to { transform: rotate(1.1deg); }
}
@media (max-width: 700px) {
  .liana.l1, .liana.l2 { display: none; }
  .liana.l3 { height: 140px; }
}
@media (prefers-reduced-motion: reduce) {
  .liana { animation: none; }
}

/* --- the garden engulfs the page ---------------------------------------- */

.frame {
  position: fixed;
  z-index: 70;
  pointer-events: none;
  image-rendering: pixelated;
}
.frame-top {
  top: 0; left: 0; right: 0; height: 34px;
  background: url(/assets/frame/canopy.png) repeat-x top left / auto 34px;
}
.frame-bottom {
  bottom: 0; left: 0; right: 0; height: 26px;
  background: url(/assets/frame/grass.png) repeat-x bottom left / auto 26px;
}
.frame-left, .frame-right { top: 0; bottom: 0; width: 22px; display: none; }
.frame-left { left: 0; background: url(/assets/frame/vine-left.png) repeat-y top left / 22px auto; }
.frame-right { right: 0; background: url(/assets/frame/vine-right.png) repeat-y top right / 22px auto; }
@media (min-width: 1100px) {
  .frame-left, .frame-right { display: block; }
}
@media (max-width: 700px) {
  .frame-top { height: 24px; background-size: auto 24px; }
  .frame-bottom { height: 18px; background-size: auto 18px; }
}

#life {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 65;
  pointer-events: none;
  image-rendering: pixelated;
}
@media (prefers-reduced-motion: reduce) { #life { display: none; } }

.stone { margin: 0 0 14px; }
.stone img { image-rendering: auto; width: auto; }

.meadow {
  height: 64px;
  margin-top: 70px;
  background: url(/assets/frame/footer-garden.png) repeat-x bottom center / auto 64px;
  image-rendering: pixelated;
}
footer { padding-top: 26px; }

/* --- the CRT pane -------------------------------------------------------- */

.crt-scan { /* retired on the landing: the CRT is the monitor object now */
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  background: repeating-linear-gradient(0deg,
    rgba(16, 12, 6, 0.09) 0px, rgba(16, 12, 6, 0.09) 1px,
    transparent 1px, transparent 3px);
  animation: crtflicker 9s steps(1) infinite;
}
.crt-roll {
  position: fixed;
  left: 0;
  right: 0;
  top: -140px;
  height: 120px;
  z-index: 90;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(246, 239, 228, 0) 0%,
    rgba(246, 239, 228, 0.05) 45%,
    rgba(16, 12, 6, 0.04) 60%,
    rgba(246, 239, 228, 0) 100%);
  animation: crtroll 17s linear infinite;
}
.crt-vignette {
  position: fixed;
  inset: 0;
  z-index: 91;
  pointer-events: none;
  background: radial-gradient(115% 115% at 50% 48%,
    rgba(26, 22, 18, 0) 62%,
    rgba(26, 22, 18, 0.10) 86%,
    rgba(26, 22, 18, 0.30) 100%);
}
@keyframes crtroll {
  from { transform: translateY(0); }
  to { transform: translateY(calc(100vh + 280px)); }
}
@keyframes crtflicker {
  0%, 100% { opacity: 1; }
  7% { opacity: 0.92; }
  8% { opacity: 1; }
  43% { opacity: 0.95; }
  44% { opacity: 1; }
  71% { opacity: 0.9; }
  72% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .crt-scan { animation: none; }
  .crt-roll { display: none; }
}

.corner { position: fixed; z-index: 92; }
.corner.tl { top: var(--corner-y); left: var(--corner-x); }
.corner.tr { top: var(--corner-y); right: var(--corner-x); }
.corner.bl { bottom: var(--corner-y); left: var(--corner-x); }
.corner.br { bottom: var(--corner-y); right: var(--corner-x); }
.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.online {
  border: 0;
  padding: 0;
  width: 112px;
  height: 32px;
  background: url(/assets/signs/online.png?v=2) no-repeat center / 100% 100%;
  image-rendering: pixelated;
  filter: drop-shadow(0 3px 5px rgba(42, 30, 18, 0.3));
}

.player {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  filter: drop-shadow(0 3px 5px rgba(42, 30, 18, 0.3));
}
.player .p-row { display: flex; gap: 6px; }
.player button {
  border: 0;
  padding: 0;
  width: 30px;
  height: 36px;
  background: no-repeat center / 100% 100%;
  image-rendering: pixelated;
  cursor: pointer;
}
.player .p-toggle { background-image: url(/assets/signs/btn-play.png); }
.player .p-toggle.on { background-image: url(/assets/signs/btn-pause.png); }
.player .p-skip { background-image: url(/assets/signs/btn-skip.png); }
.player .p-back { background-image: url(/assets/signs/btn-back.png); }
/* Back and skip mean nothing with one procedural hum and no playlist. */
.player .p-skip,
.player .p-back { display: none; }
.player.has-tracks .p-skip,
.player.has-tracks .p-back { display: block; }

/* The console is the plain readout until there are tracks, then it grows a
   second board for the times and the seek groove. */
.player .p-console {
  width: 150px;
  height: 36px;
  background: url(/assets/signs/plate-track.png) no-repeat center / 100% 100%;
  image-rendering: pixelated;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
}
.player.has-tracks .p-console {
  width: 232px;
  height: 56px;
  background-image: url(/assets/signs/plate-console.png);
  justify-content: flex-start;
  padding: 7px 13px 0;
  gap: 4px;
}
.player .p-title {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: #d8cab2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  text-shadow: 0 1px 0 rgba(20, 14, 6, 0.85);
}
.player.playing .p-title { color: #e8d080; }

.player .p-bar { display: none; }
.player.has-tracks .p-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  margin-top: 5px;
}
.player .p-elapsed,
.player .p-total {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 9px;
  letter-spacing: 0.04em;
  color: #b7a68c;
  text-shadow: 0 1px 0 rgba(20, 14, 6, 0.85);
  font-variant-numeric: tabular-nums;
  min-width: 22px;
}
.player .p-elapsed { text-align: right; }
.player .p-total { text-align: left; }

/* The groove is cut, not drawn on: a dark channel with the lit wall along
   its lower edge, the same low west sun as every carved letter. */
.player .p-seek {
  position: relative;
  flex: 1;
  height: 7px;
  cursor: pointer;
  background: linear-gradient(
    180deg,
    #241a10 0, #241a10 4px,
    #9a7a50 4px, #9a7a50 6px,
    #6a5232 6px, #6a5232 7px
  );
  touch-action: none;
}
.player .p-seek:focus-visible { outline: 1px solid var(--honey); outline-offset: 2px; }
.player .p-fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 4px;
  width: 0;
  background: var(--honey);
}
.player .p-bead {
  position: absolute;
  top: -4px;
  left: 0;
  width: 7px;
  height: 15px;
  margin-left: -3px;
  background: url(/assets/signs/bead.png) no-repeat center / 100% 100%;
  image-rendering: pixelated;
  pointer-events: none;
}

@media (max-width: 700px) { .player .p-console { display: none; } }

.server {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  filter: drop-shadow(0 4px 7px rgba(42, 30, 18, 0.34));
}
.server img {
  display: block;
  image-rendering: pixelated;
}
.server .worlds { width: 238px; height: auto; }
.server { transform-origin: bottom left; }
@media (max-width: 1240px) { .server { transform: scale(0.86); } }
@media (max-width: 1000px) { .server { transform: scale(0.72); } }
@media (max-width: 760px)  { .server { transform: scale(0.58); } }


body.one, body.one a, body.one button {
  cursor: url(/assets/cursors/apple.png?v=4) 4 2, auto;
}
body.one a, body.one button:not([disabled]) {
  cursor: url(/assets/cursors/apple-bite.png?v=4) 4 2, pointer;
}
.online .dot {
  width: 6px;
  height: 6px;
  background: #8a8478;
  animation: onlinepulse 3.4s ease-in-out infinite;
}
@keyframes onlinepulse {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .online .dot { animation: none; } }
@media (max-width: 700px) { .online { top: 10px; right: 10px; font-size: 10px; } }

/* the hero's own resting scanline retires; the whole pane is the CRT now */
.hero .scan.rest { opacity: 0; }

/* --- the glass ------------------------------------------------------------

   Everything a live tube does that a still image cannot, sitting on the
   screen rect hero.js publishes. Layer order is the order light meets the
   eye: phosphor bloom deepest, then the shadow mask, then the two moving
   refresh bands, then flicker, then the reflection on the outside of the
   glass. Nothing here costs a canvas repaint; the bands are composited
   transforms. Keep every alpha low. The tube should feel alive, not busy. */

.crtglass {
  position: absolute;
  z-index: 4;
  overflow: hidden;
  pointer-events: none;
}
.crtglass > * {
  position: absolute;
  inset: 0;
}

/* phosphor glow pooling at the centre, tube shadow closing the corners */
.crt-bloom {
  box-shadow:
    inset 0 0 26px rgba(6, 10, 4, 0.42),
    inset 0 0 70px rgba(120, 190, 100, 0.09);
}

/* the shadow mask: vertical triads, the tube's own grain. Only above a
   size where the stripes can resolve without moire against the raster. */
.crt-grille {
  background-image: repeating-linear-gradient(
    90deg,
    rgba(255, 40, 40, 0.045) 0 1px,
    rgba(40, 255, 90, 0.045) 1px 2px,
    rgba(60, 90, 255, 0.045) 2px 3px
  );
}
@media (max-width: 700px) { .crt-grille { display: none; } }

/* the slow refresh roll: a wide, soft brightening that walks down the
   glass, the artifact you get filming a CRT slightly out of sync */
.crt-roll {
  bottom: auto;
  height: 42%;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(214, 255, 214, 0.035) 34%,
    rgba(226, 255, 226, 0.07) 50%,
    rgba(214, 255, 214, 0.035) 66%,
    rgba(255, 255, 255, 0) 100%
  );
  will-change: transform;
  animation: crtroll 7.5s linear infinite;
}
@keyframes crtroll {
  from { transform: translateY(-100%); }
  to   { transform: translateY(238%); }   /* 100/42: clears the glass */
}

/* the fast sweep: the thin dark seam where the beam is between fields */
.crt-sweep {
  bottom: auto;
  height: 9%;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0) 0%,
    rgba(2, 6, 2, 0.14) 48%,
    rgba(2, 6, 2, 0.05) 62%,
    rgba(0, 0, 0, 0) 100%
  );
  will-change: transform;
  animation: crtsweep 2.6s linear infinite;
}
@keyframes crtsweep {
  from { transform: translateY(-100%); }
  to   { transform: translateY(1111%); }  /* 100/9 */
}

/* Mains flicker. Deliberately slow and shallow: the swing is under two
   percent of luminance and nowhere near the 3-30 Hz photosensitive band.
   A faster strobe would be more "authentic" and is not worth the risk. */
.crt-flick {
  background: rgba(206, 255, 206, 0.035);
  animation: crtflick 1.1s ease-in-out infinite;
}
@keyframes crtflick {
  0%, 100% { opacity: 0.30; }
  40%      { opacity: 0.85; }
  70%      { opacity: 0.50; }
}

/* Power-on. One line of light that opens into the full field, once, when
   the loader hands the page over. html.booted is set for every visitor at
   reveal; if the glass is built after that (slow logo-grid fetch), the
   animation simply plays the moment the layer exists. Single flash, under
   a second, never repeated: nowhere near the photosensitive band. */
.crt-boot {
  opacity: 0;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
  background:
    radial-gradient(100% 60% at 50% 50%,
      rgba(234, 255, 226, 0.95) 0%,
      rgba(190, 235, 178, 0.55) 55%,
      rgba(130, 200, 110, 0.18) 100%);
}
html.booted .crt-boot {
  animation: crtboot 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) 1 forwards;
}
@keyframes crtboot {
  0%   { opacity: 0;   transform: scaleY(0.012); }
  14%  { opacity: 1;   transform: scaleY(0.03); }
  46%  { opacity: 0.6; transform: scaleY(1); }
  100% { opacity: 0;   transform: scaleY(1); }
}

/* the room, reflected in the outside of the glass */
.crt-glare {
  background:
    linear-gradient(148deg,
      rgba(255, 255, 255, 0.11) 0%,
      rgba(255, 255, 255, 0.035) 20%,
      rgba(255, 255, 255, 0) 44%),
    radial-gradient(120% 80% at 50% 0%,
      rgba(255, 255, 255, 0.05) 0%,
      rgba(255, 255, 255, 0) 60%);
}

@media (prefers-reduced-motion: reduce) {
  .crt-roll, .crt-sweep { display: none; }
  .crt-flick { animation: none; opacity: 0.4; }
  html.booted .crt-boot { animation: none; }
}

/* --- one screen ---------------------------------------------------------- */

body.one {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* The stage owns the whole viewport and insets itself equally top and
   bottom by the meadow's height. Symmetric padding is what makes centering
   inside it land on the true middle of the screen, and it also keeps the
   monitor from growing down into the grass. */
body.one .stage {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--meadow-h) 18px;
}

/* The hero band is all the space between canopy and meadow. The monitor and
   the tagline live inside it as one column, centered, so the composition
   sits in the middle of the screen at every viewport. Pinning it to the
   bottom looked right only when the canvas filled the band; in a portrait
   window the canvas is width-limited and the group sank. hero.js subtracts
   the tagline's height from the canvas budget. */
body.one .hero {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(10px, 2.4vh, 26px);
  background: transparent;
}
body.one .hero > img { max-height: 100%; width: auto; max-width: 100%; }

body.one .tagline {
  padding: 0;
  margin: 0;
  line-height: 0;
  width: 100%;
  text-align: center;
}
body.one .tagline img {
  width: min(92%, 620px);
  height: auto;
  image-rendering: pixelated;
}
body.one .whisper {
  margin: 0;
  color: var(--faded);
  font-size: clamp(12px, 1.8vh, 15px);
}

.doorsign {
  display: block;
  filter: drop-shadow(0 4px 7px rgba(42, 30, 18, 0.34));
}
.doorsign img {
  display: block;
  width: 186px;
  height: auto;
  image-rendering: pixelated;
}
.doorsign:hover { filter: drop-shadow(0 6px 10px rgba(42, 30, 18, 0.45)); }

/* Scenery, not layout. Fixed to the floor like the canopy and the corner
   signs, so it takes no space from the stage; if it sat in the flow it
   would push the centered group up off the middle of the screen by half
   its height. z below the critters that walk on it and the signs that
   overlap it. garden.js reads its rect, which still reports correctly. */
body.one .meadow {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  height: var(--meadow-h);
  margin: 0;
  background-size: auto 100%;
}
@media (max-height: 600px) {
  body.one { overflow-y: auto; }
  body.one .whisper { display: none; }
}

/* the book is a reading room: gentler pane, no roll */
body.crt-lite .crt-scan {
  background: repeating-linear-gradient(0deg,
    rgba(16, 12, 6, 0.05) 0px, rgba(16, 12, 6, 0.05) 1px,
    transparent 1px, transparent 3px);
  animation: none;
}
body.crt-lite .crt-vignette {
  background: radial-gradient(120% 120% at 50% 45%,
    rgba(26, 22, 18, 0) 70%,
    rgba(26, 22, 18, 0.16) 100%);
}

/* --- book --------------------------------------------------------------- */

.book {
  display: grid;
  grid-template-columns: 235px minmax(0, 1fr);
  gap: 46px;
  max-width: 1060px;
  margin: 0 auto;
  padding: 30px 22px 70px;
}

.crumb {
  font-size: 14px;
  color: var(--faded);
  padding: 18px 22px 0;
  max-width: 1060px;
  margin: 0 auto;
}

.toc {
  position: sticky;
  top: 26px;
  align-self: start;
  font-size: 14.5px;
  line-height: 1.5;
}
.toc a { display: block; padding: 3.5px 0; color: var(--faded); }
.toc a:hover { color: var(--charcoal); text-decoration: none; }
.toc a.here { color: var(--honey-deep); font-weight: 600; }

.chapter {
  max-width: 720px;
  background: #f2e8d5 url(/assets/scroll/parchment-tile.png) repeat;
  border: 0;
  border-radius: 2px;
  box-shadow: 0 10px 34px rgba(42, 30, 18, 0.18);
  padding: 40px 42px 44px;
  margin: 22px 0 26px;
}
.chapter::before, .chapter::after {
  content: "";
  position: absolute;
  left: -8px;
  right: -8px;
  height: 22px;
  background-repeat: repeat-x;
  background-size: auto 22px;
  image-rendering: pixelated;
  pointer-events: none;
  filter: drop-shadow(0 3px 4px rgba(42, 30, 18, 0.22));
}
.chapter::before { top: -14px; background-image: url(/assets/scroll/scroll-top.png); }
.chapter::after { bottom: -14px; background-image: url(/assets/scroll/scroll-bottom.png); }
.chapter code { background: rgba(90, 68, 44, 0.12); }
.chapter th { background: rgba(90, 68, 44, 0.08); }
.chapter h1 { font-size: clamp(27px, 4vw, 33px); line-height: 1.2; margin: 8px 0 20px; }
.chapter h2 { font-size: 21px; margin: 34px 0 10px; }
.chapter h3 { font-size: 17.5px; margin: 26px 0 8px; }
.chapter p { margin: 0 0 1.05em; }
.chapter hr { border: 0; border-top: 1px solid var(--line); margin: 34px 0; }

.chapter code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.86em;
  background: rgba(58, 52, 44, 0.07);
  border-radius: 6px;
  padding: 0.12em 0.38em;
}

.chapter table {
  border-collapse: collapse;
  width: 100%;
  margin: 18px 0 24px;
  font-size: 15px;
}
.chapter th {
  text-align: left;
  background: var(--paper);
  border-bottom: 2px solid var(--line);
  padding: 8px 12px;
}
.chapter td { border-bottom: 1px solid var(--line); padding: 8px 12px; vertical-align: top; }

.chapter ul, .chapter ol { margin: 0 0 1.1em; padding-left: 1.4em; }
.chapter li { margin: 0.28em 0; }

pre.mermaid {
  display: flex;
  justify-content: center;
  overflow-x: auto;
  margin: 26px 0 30px;
  background: transparent;
}

.prevnext {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  margin-top: 54px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 15px;
}

@media (max-width: 880px) {
  .book { display: block; }
  .toc {
    position: static;
    display: flex;
    overflow-x: auto;
    gap: 16px;
    white-space: nowrap;
    padding-bottom: 12px;
    margin-bottom: 26px;
    border-bottom: 1px solid var(--line);
  }
  .toc a { padding: 2px 0; }
}
