:root {
  color-scheme: light;

  /* Surfaces. A warm gallery paper rather than pure white: #fff glares on
     large screens and drains the warmth out of the artwork sitting on it.

     The dark theme separated surfaces by nudging luminance a few percent and
     letting a faint hairline do the rest. That only works against black,
     where the eye has enormous headroom above the ground. On paper the same
     trick collapses -- every panel reads as the same blank sheet. So the
     ground is pushed DOWN and raised surfaces UP, far enough apart that a
     card is obviously sitting on top of the page before any border is drawn.
     Shadows then do the work the darkness used to. */
  --bg: #e6dfd1;         /* page ground -- the deepest surface */
  --bg-raised: #faf7f1;  /* cards, panels, anything lifted off the page */
  --bg-sunken: #ded6c5;  /* wells and recesses, below the ground */
  --bg-veil: rgba(230, 223, 209, 0.86);

  /* A field has to look typeable at a glance, so it goes near-white and gets
     a border with real weight rather than a whisper. */
  --field: #fffdf9;
  --field-edge: rgba(28, 26, 22, 0.3);

  /* The resting surface of a button. Kept separate from --bg-raised because
     controls also live inside the dark islands, where a card surface and a
     button surface need to go opposite ways. */
  --control: #faf7f1;
  --control-hover: #fffdf9;

  /* Ink on paper. Secondary text is a genuinely lighter INK, not the same
     black at lower alpha -- transparency over a warm ground turns text milky
     and kills the letterforms long before it reads as "secondary". These are
     7.6:1 and 5.1:1 on the page ground, so small caps still hold together. */
  --fg: #14120e;
  --fg-dim: #4a453b;
  --fg-faint: #635d50;

  /* Borders carry structure on paper the way glow did on black. */
  --hairline: rgba(28, 26, 22, 0.2);
  --hairline-strong: rgba(28, 26, 22, 0.34);

  --shadow-sm: 0 1px 2px rgba(46, 38, 20, 0.06), 0 2px 8px rgba(46, 38, 20, 0.05);
  --shadow-md: 0 2px 4px rgba(46, 38, 20, 0.07), 0 10px 28px rgba(46, 38, 20, 0.09);
  --shadow-lg: 0 26px 64px rgba(46, 38, 20, 0.2);

  /* Gold splits in two on a light ground: the accent has to be deep enough
     to read as text on paper, which then makes it too dark to sit dark text
     on -- so fills that carry text use the brighter tone. */
  --gold: #7d6018;
  --gold-fill: #c8a349;
  --gold-soft: rgba(125, 96, 24, 0.13);
  --gold-edge: rgba(125, 96, 24, 0.5);
  --on-gold: #241f14;

  /* Washes of the page ground. Every scrim laid over a photograph -- the
     wallpaper, the hero, the sticky nav -- is this colour at some opacity.
     They are tokens rather than literal rgba() so that changing the ground in
     Settings carries them along; written as literals, a new background colour
     left the photograph behind it veiled in the old one, which is the single
     most visible way a themed site falls apart. */
  --veil-faint: rgba(230, 223, 209, 0.34);
  --veil-light: rgba(230, 223, 209, 0.62);
  --veil-mid: rgba(230, 223, 209, 0.72);
  --veil-strong: rgba(230, 223, 209, 0.88);
  --veil-heavy: rgba(230, 223, 209, 0.92);
  --veil-solid: rgba(230, 223, 209, 0.97);
  --nav-bg: rgba(245, 241, 233, 0.88);
  --nav-panel: rgba(250, 247, 241, 0.98);

  /* Status inks, deep enough to read as text on paper. */
  --danger: #9d332d;
  --ok: #2c6647;

  /* Anything laid directly over a photograph keeps the dark treatment,
     because a photo can be any colour. Applied via .on-media below. */
  --on-media: #f4f1ea;
  --on-media-dim: rgba(244, 241, 234, 0.74);
  --on-media-faint: rgba(244, 241, 234, 0.5);
  --media-hairline: rgba(244, 241, 234, 0.16);
  --media-gold: #d8b25c;

  --display: "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
  --body: "Inter", "Helvetica Neue", Arial, sans-serif;

  --gutter: clamp(20px, 5vw, 80px);
  --measure: 1440px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

*, *::before, *::after { box-sizing: border-box; }

/* The UA [hidden] rule loses to any class that declares display, so several
   panels below would stay visible when toggled. Make the attribute win. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.65;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }
a { color: inherit; }

::selection { background: var(--gold-fill); color: var(--on-gold); }

/* ---------- Dark islands ----------
   The page is light, but a few regions sit on top of imagery we don't
   control -- a caption burned into a thumbnail, the full-screen viewer, the
   comic reader. Re-pointing the palette tokens here flips everything inside
   back to light-on-dark without touching the individual rules.

   Every surface token has to be re-pointed, not just the ink. A field left
   at the paper value is a white slab punched into a black reader; a well
   left at the paper value vanishes entirely. The islands get translucent
   equivalents that read the same way against whatever is underneath. */
.on-media,
.tile,
.index-card-body,
.story-cover,
.lightbox,
.reader,
.thumb,
.m-badge {
  --fg: var(--on-media);
  --fg-dim: var(--on-media-dim);
  --fg-faint: var(--on-media-faint);
  --hairline: var(--media-hairline);
  --hairline-strong: rgba(244, 241, 234, 0.34);
  --gold: var(--media-gold);
  --gold-edge: rgba(216, 178, 92, 0.55);
  --bg-sunken: rgba(244, 241, 234, 0.07);
  --field: rgba(244, 241, 234, 0.09);
  --field-edge: rgba(244, 241, 234, 0.28);
  --control: rgba(244, 241, 234, 0.08);
  --control-hover: rgba(244, 241, 234, 0.16);
  --danger: #e8827c;
  --shadow-sm: none;
  --shadow-md: none;
  color: var(--fg);
}

.eyebrow {
  font-size: 0.68rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 500;
}

.shell {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}


/* ---------- Photographic backdrop ----------
   Sits above the page canvas but behind all content, so the artwork
   wallpaper shows through every transparent section. */
.wallpaper {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: var(--page-bg);
  background-size: cover;
  background-position: var(--page-bg-pos, center);
  background-repeat: no-repeat;
}

.wallpaper::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(130% 90% at 50% 0%, var(--veil-mid), var(--veil-heavy) 70%),
    linear-gradient(180deg, var(--bg-veil) 0%, var(--veil-heavy) 100%);
}

/* Phones render a much larger backdrop relative to the viewport, so the
   image is dimmed further to keep body copy legible. */
@media (max-width: 700px) {
  .wallpaper::after {
    background: linear-gradient(180deg, var(--veil-heavy) 0%, var(--veil-solid) 100%);
  }
}

/* ---------- Navigation ---------- */
.site-nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 22px var(--gutter);
  transition: background 0.5s var(--ease), backdrop-filter 0.5s var(--ease),
              border-color 0.5s var(--ease), padding 0.5s var(--ease);
  border-bottom: 1px solid transparent;
}

.site-nav.is-stuck {
  padding-block: 14px;
  background: var(--nav-bg);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom-color: var(--hairline);
  box-shadow: var(--shadow-sm);
}

.site-nav .wordmark {
  font-family: var(--display);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  margin: 0;
  text-decoration: none;
  white-space: nowrap;
}

.site-nav .wordmark span { color: var(--gold); }

/* The name is wrapped so the settings page can rewrite it without touching
   the gold full stop beside it. It is a <b> only because it needed to be an
   element -- the weight still comes from .wordmark. */
.site-nav .wordmark b { font-weight: inherit; }

/* When the owner uploads a logo it replaces the wordmark in place, so it is
   capped to the height the text occupied rather than setting its own. */
.site-nav .wordmark.has-logo { display: flex; align-items: center; }
.site-nav .wordmark img {
  height: clamp(24px, 3.4vh, 38px);
  width: auto;
  object-fit: contain;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.4vw, 34px);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  position: relative;
  text-decoration: none;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-dim);
  padding-block: 4px;
  transition: color 0.35s var(--ease);
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease-out);
}

.nav-links a:hover,
.nav-links a[aria-current="page"] { color: var(--fg); }

.nav-links a:hover::after,
.nav-links a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Understated, not invisible. At 0.5 on paper this washed out to nothing and
   the way into the studio became a guessing game. */
.nav-links a.admin-link { opacity: 0.72; }
.nav-links a.admin-link:hover { opacity: 1; }

.nav-toggle {
  display: none;
  background: var(--control);
  border: 1px solid var(--hairline-strong);
  color: var(--fg);
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
}

@media (max-width: 820px) {
  .nav-toggle { display: block; }
  .nav-links {
    position: fixed;
    inset: 0 0 auto 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 96px var(--gutter) 36px;
    background: var(--nav-panel);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--shadow-md);
    transform: translateY(-102%);
    transition: transform 0.6s var(--ease-out);
  }
  .nav-links.is-open { transform: translateY(0); }
  .nav-links a { font-size: 1rem; padding-block: 16px; letter-spacing: 0.14em; }
}

/* ---------- Buttons ---------- */
.link-btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  font-size: 0.74rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg);
  padding: 15px 30px;
  /* A transparent pill edged at 16% black was invisible on paper -- nothing
     announced it as a control. It gets a real edge and a surface now. */
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  background: var(--control);
  cursor: pointer;
  font-family: inherit;
  overflow: hidden;
  position: relative;
  /* The fill sweep below sits at z-index -1. Now that the button paints its
     own background, it needs a stacking context or the sweep would slide in
     behind that background and never be seen. */
  isolation: isolate;
  box-shadow: var(--shadow-sm);
  transition: color 0.45s var(--ease), border-color 0.45s var(--ease),
              box-shadow 0.45s var(--ease);
}

.link-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gold-fill);
  transform: translateY(101%);
  transition: transform 0.55s var(--ease-out);
  z-index: -1;
}

.link-btn:hover { color: var(--on-gold); border-color: var(--gold); box-shadow: var(--shadow-md); }
.link-btn:hover::before { transform: translateY(0); }
.link-btn .arrow { transition: transform 0.45s var(--ease-out); }
.link-btn:hover .arrow { transform: translateX(5px); }

.link-btn.is-solid { background: var(--gold-fill); color: var(--on-gold); border-color: var(--gold); }
/* The solid button inverts to dark ink on hover, so its label has to flip
   light -- the shared :hover rule above leaves it dark-on-dark otherwise. */
.link-btn.is-solid::before { background: var(--fg); }
.link-btn.is-solid:hover { color: var(--bg); border-color: var(--fg); }

/* ---------- Reveal primitives ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(38px);
  transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal="fade"] { transform: none; }
[data-reveal="scale"] { transform: scale(0.94); }
[data-reveal="left"] { transform: translateX(-44px); }
[data-reveal="right"] { transform: translateX(44px); }

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

.reveal-mask {
  display: block;
  overflow: hidden;
  padding-bottom: 0.08em;
  margin-bottom: -0.08em;
}
.reveal-mask > * {
  display: block;
  transform: translateY(105%);
  transition: transform 1.05s var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal-mask.is-revealed > * { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal], .reveal-mask > * { opacity: 1; transform: none; }
}

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--hairline);
  padding: 72px var(--gutter) 46px;
  background: var(--bg);
}

.footer-grid {
  max-width: var(--measure);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 48px;
  align-items: start;
}

.footer-grid h4 {
  font-family: var(--display);
  font-size: 1.6rem;
  font-weight: 500;
  margin: 0 0 12px;
}

.footer-grid p { color: var(--fg-faint); max-width: 34ch; margin: 0; font-size: 0.9rem; }

.footer-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

.footer-col a {
  text-decoration: none;
  color: var(--fg-dim);
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  transition: color 0.35s var(--ease);
}

.footer-col a:hover { color: var(--gold); }

.footer-col .col-title {
  font-size: 0.66rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0 0 18px;
}

.footer-base {
  max-width: var(--measure);
  margin: 56px auto 0;
  padding-top: 24px;
  border-top: 1px solid var(--hairline);
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  color: var(--fg-faint);
}

@media (max-width: 760px) {
  .footer-grid { grid-template-columns: 1fr; gap: 36px; }
}

/* ================= TOUCH & SMALL SCREENS ================= */

/* Anything a finger has to hit gets a real target on touch devices. */
@media (pointer: coarse) {
  .nav-toggle,
  .link-btn,
  .like-btn,
  .comment-toggle,
  .chip {
    min-height: 44px;
  }

  .nav-links a { min-height: 44px; display: flex; align-items: center; }
}

@media (max-width: 700px) {
  :root { --gutter: 18px; }

  body { font-size: 15px; }

  .site-nav { padding: 14px var(--gutter); }
  .site-nav.is-stuck { padding-block: 12px; }
  .site-nav .wordmark { font-size: 1.15rem; }

  .nav-toggle {
    padding: 10px 16px;
    font-size: 0.68rem;
  }

  .footer-grid { gap: 30px; }
  .site-footer { padding: 52px var(--gutter) 34px; }
  .footer-base { margin-top: 34px; font-size: 0.68rem; }
}

@media (max-width: 380px) {
  :root { --gutter: 14px; }
  .site-nav .wordmark { font-size: 1.05rem; }
}

/* Landscape phones are short: stop full-height blocks from trapping content. */
@media (max-height: 480px) and (orientation: landscape) {
  .nav-links { padding-top: 72px; overflow-y: auto; max-height: 100vh; }
}

/* ================= PREVIEW ==================
   Shown only on a page loaded with ?preview=1. Its whole job is to make it
   impossible to mistake a draft for the live site -- so it is fixed, it is
   loud, and it does not scroll away. The nav sits at the top of the viewport,
   so the banner takes the bottom edge and the page gets padding to match
   rather than having its last line covered. */
.preview-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  padding: 9px var(--gutter);
  background: var(--gold-fill);
  color: var(--on-gold);
  font-family: var(--body);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  box-shadow: 0 -2px 14px rgba(0, 0, 0, 0.18);
}

.preview-banner.is-denied {
  background: var(--danger);
  color: #fff;
}

body.is-previewing { padding-bottom: 40px; }

@media (max-width: 560px) {
  .preview-banner { font-size: 0.62rem; letter-spacing: 0.05em; padding: 8px 12px; }
}

/* ================= BACKGROUND MUSIC ==================
   A small control, bottom left, opposite the scroll cue and out of the way of
   everything else. Quiet enough to ignore, always obvious enough to switch
   off -- which matters more than anything else about it, because the visitor
   who wants it off wants it off now. */
/* Bottom right, not bottom left.
   Every heading, paragraph and button on this site is left-aligned, so a
   control parked in the bottom-left corner eventually lands on top of one --
   it was sitting squarely on "Read the full story". A floating control has to
   overlap something as the page scrolls under it; the right-hand side is
   where that something is never a button. */
.ambient {
  position: fixed;
  right: var(--gutter);
  bottom: 20px;
  z-index: 800;
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 9px 13px;
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  background: var(--nav-bg);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  color: var(--fg-dim);
  font-family: var(--body);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease),
              background 0.3s var(--ease);
}

.ambient:hover { color: var(--fg); border-color: var(--gold-edge); }

.ambient:focus-visible {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-soft);
}

.ambient svg { width: 17px; height: 17px; flex: none; }

/* Silent by default: the speaker wears a cross, and the waves only appear
   once it is actually making sound. */
.ambient .wave { opacity: 0; }
.ambient .cross { opacity: 1; }

.ambient.is-playing { color: var(--gold); border-color: var(--gold-edge); }
.ambient.is-playing .cross { opacity: 0; }
.ambient.is-playing .wave { opacity: 1; }

.ambient.is-playing .wave-1 { animation: ambientPulse 2.4s var(--ease) infinite; }
.ambient.is-playing .wave-2 { animation: ambientPulse 2.4s var(--ease) 0.3s infinite; }

@keyframes ambientPulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

/* The track name is an announcement, not a label. It slides out when a piece
   begins, sits for a few seconds, and folds away again -- long enough to
   answer "what is this?", short enough never to become furniture. Collapsing
   the width rather than hiding it keeps the control from jumping. */
.ambient-label {
  max-width: 0;
  margin-left: 0;
  opacity: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: max-width 0.55s var(--ease-out), opacity 0.4s var(--ease),
              margin-left 0.55s var(--ease-out);
}

/* Silent: the word "Music" is the only thing that says what the button does. */
.ambient:not(.is-playing) .ambient-label,
.ambient.is-naming .ambient-label,
.ambient.is-unavailable .ambient-label {
  max-width: 18ch;
  margin-left: 9px;
  opacity: 1;
}

/* A pointer-less device gets no hover, so the name stays a moment longer. */
@media (hover: none) {
  .ambient.is-naming .ambient-label { max-width: 22ch; }
}

/* The preview banner owns the bottom edge, so the control steps above it. */
body.is-previewing .ambient { bottom: 58px; }

/* Icon-only at rest on anything narrower than a desktop.
   The word "Music" tripled the control's width for no information the speaker
   symbol does not already carry, and every pixel of a floating control is a
   pixel of something underneath it -- here it was landing on the comic genre
   chips. The track name still slides out when a piece starts, which is when
   there is actually something to say. */
@media (max-width: 900px) {
  .ambient:not(.is-naming):not(.is-unavailable) .ambient-label {
    max-width: 0;
    margin-left: 0;
    opacity: 0;
  }

  .ambient.is-naming .ambient-label { max-width: 14ch; }
}

@media (max-width: 700px) {
  .ambient { right: 12px; bottom: 12px; padding: 9px; font-size: 0.6rem; }
  .ambient.is-naming .ambient-label { max-width: 11ch; }
}

@media (prefers-reduced-motion: reduce) {
  .ambient .wave { animation: none !important; }
}

.ambient.is-unavailable {
  opacity: 0.55;
  cursor: default;
  border-style: dashed;
}
