/* ==========================================================================
   The Courtship of Miles Standish — Flip Book
   Theme: rustic wooden desk
   ========================================================================== */

:root {
  --room:      #17110c;   /* deep walnut dark */
  --room-warm: #241a11;   /* lamplit wall */
  --lamp:      #ffd9a0;   /* lamplight */
  --brass:     #b98d4f;   /* aged brass */
  --brass-dim: #7d5f38;
  --ink:       #e9dcc6;   /* warm parchment text */
  --ink-dim:   #a8946f;

  --btn-fill:       #c9a876;  /* light brown button fill */
  --btn-fill-hover: #d9bc8f;
  --btn-text:       #34210f;  /* dark walnut, for contrast on the fill */
  --btn-border:     #8a6a3f;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

html,
body {
  height: 100%;
  overscroll-behavior: none;
  touch-action: none;
}

body {
  font-family: Georgia, 'Palatino Linotype', Palatino, 'Book Antiqua', serif;
  color: var(--ink);
  background: #2b1c10 url('../img/woodenBG.webp') no-repeat center center / cover;
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  user-select: none;
}

/* --------------------------------------------------------------------------
   Stage & book
   -------------------------------------------------------------------------- */

#stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px 40px 10px;
}

/* lamplight pool behind the open book */
#stage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 46% 52% at 50% 46%,
    rgba(255, 217, 160, 0.13) 0%,
    rgba(255, 217, 160, 0.05) 45%,
    transparent 72%);
}

#book {
  position: relative;
  z-index: 1;
  transform: scale(0.93);
  filter: drop-shadow(0 26px 44px rgba(0, 0, 0, 0.65));
  transition: transform 1s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* pre-"Touch to Begin" state — book sits closed on its cover, larger
   and more prominent; settles to its normal reading scale as it opens
   (see beginReading in app.js, which removes this class) */
#stage.bookIntro #book {
  transform: scale(1.1);
}

/* animated "swipe here" reminder, positioned via JS near the current
   page's outer edge — fades out once the visitor turns a page */
#swipeHint {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  pointer-events: none;
  transition: opacity 0.6s ease;
}

#swipeHint.gone {
  opacity: 0;
}

#swipeHintIcon {
  width: 140px;
  height: 140px;
  animation: swipeHandMove 1.6s ease-in-out infinite;
}

#swipeHintIcon .swipeHandShape {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--btn-text);
  filter: drop-shadow(0 2px 4px rgba(255, 255, 255, 0.35));
  transform: rotate(-30deg);
  transform-origin: 50% 50%;
}

@keyframes swipeHandMove {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-35px); }
}

/* an inverted button.nav — dark fill, light text — so the hint reads
   clearly against page images of any tone, rather than blending in */
#swipeHintBubble {
  font-style: italic;
  font-size: 15px;
  color: var(--ink);
  background: linear-gradient(180deg, var(--room), var(--room-warm));
  border: 1px solid var(--brass-dim);
  padding: 8px 18px;
  border-radius: 999px;
  white-space: nowrap;
  margin-top: -30px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.5),
              inset 0 1px 0 rgba(255, 255, 255, 0.08),
              inset 0 -2px 3px rgba(0, 0, 0, 0.25);
}

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

.page img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

/* subtle inner-gutter shading on every page for a bound feel */
.page::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.page.--left::after {
  background: linear-gradient(to left, rgba(60, 40, 15, 0.20), transparent 9%);
}

.page.--right::after {
  background: linear-gradient(to right, rgba(60, 40, 15, 0.20), transparent 9%);
}

/* deckled paper edge — faint irregular nibble on the three cut edges
   (spine stays sharp). Applied to img/::after, not .page — StPageFlip
   overwrites .page's own clip-path every flip frame then wipes it,
   which made a jagged edge "pop" on and off. Hard covers stay straight. */
.page.--left:not([data-density="hard"]) img,
.page.--left:not([data-density="hard"])::after {
  clip-path: polygon(100% 0%, 92.31% 0.01%, 84.62% 0.01%, 76.92% 0.33%, 69.23% 0.38%, 61.54% 0.55%, 53.85% 0.07%, 46.15% 0.3%, 38.46% 0.33%, 30.77% 0.36%, 23.08% 0.47%, 15.38% 0.02%, 7.69% 0.45%, 0% 0%, 0.68% 5.26%, 0.05% 10.53%, 0.49% 15.79%, 0.32% 21.05%, 0.28% 26.32%, 0.67% 31.58%, 0.28% 36.84%, 0.67% 42.11%, 0.7% 47.37%, 0.46% 52.63%, 0.3% 57.89%, 0.35% 63.16%, 0.2% 68.42%, 0.3% 73.68%, 0.47% 78.95%, 0.11% 84.21%, 0.06% 89.47%, 0.6% 94.74%, 0% 100%, 7.69% 99.81%, 15.38% 100%, 23.08% 99.72%, 30.77% 99.82%, 38.46% 99.66%, 46.15% 99.42%, 53.85% 99.99%, 61.54% 99.53%, 69.23% 99.82%, 76.92% 99.81%, 84.62% 99.43%, 92.31% 99.67%, 100% 100%);
}

.page.--right:not([data-density="hard"]) img,
.page.--right:not([data-density="hard"])::after {
  clip-path: polygon(0% 0%, 7.69% 0.33%, 15.38% 0.09%, 23.08% 0.4%, 30.77% 0.43%, 38.46% 0.47%, 46.15% 0.43%, 53.85% 0.27%, 61.54% 0.16%, 69.23% 0.11%, 76.92% 0.46%, 84.62% 0.14%, 92.31% 0.38%, 100% 0%, 99.49% 5.26%, 99.45% 10.53%, 99.93% 15.79%, 99.5% 21.05%, 99.76% 26.32%, 99.82% 31.58%, 99.81% 36.84%, 99.87% 42.11%, 99.71% 47.37%, 99.31% 52.63%, 99.65% 57.89%, 99.58% 63.16%, 99.9% 68.42%, 99.43% 73.68%, 99.79% 78.95%, 99.76% 84.21%, 99.74% 89.47%, 99.68% 94.74%, 100% 100%, 92.31% 99.54%, 84.62% 99.83%, 76.92% 99.61%, 69.23% 99.78%, 61.54% 99.57%, 53.85% 99.97%, 46.15% 99.75%, 38.46% 99.49%, 30.77% 99.68%, 23.08% 99.62%, 15.38% 99.55%, 7.69% 99.43%, 0% 100%);
}

/* brief navigation note printed on the home spread's blank left leaf —
   styled like a faint period inscription rather than modern UI copy */
.homeInstructions {
  position: absolute;
  left: 10%;
  right: 10%;
  top: 36%;
  text-align: center;
  color: #4a3319;
  pointer-events: none;
  user-select: none;
}

.homeInstructions h3 {
  font-size: 19px;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 16px;
  opacity: 0.8;
}

.homeInstructions p {
  font-size: 15px;
  line-height: 1.7;
  margin: 8px 0;
  font-style: italic;
  opacity: 0.7;
}

.homeInstructions strong {
  font-style: normal;
  font-weight: 700;
}

/* magnifying-glass trigger overlaid on each illustration plate (see
   buildPages() in app.js) — small and corner-tucked like #infoBtn.
   img has pointer-events: none, so this opts back in to receive taps. */
.zoomTrigger {
  position: absolute;
  right: 4%;
  bottom: 4%;
  z-index: 2;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--lamp);
  background: rgba(23, 17, 12, 0.7);
  border: 1px solid var(--brass);
  border-radius: 50%;
  cursor: pointer;
  touch-action: manipulation;
  opacity: 1;
  transition: opacity 0.15s, color 0.15s, border-color 0.15s, background 0.15s;
}

/* touch has no hover to reveal this — bright by default instead, and
   dims on press as tap feedback (there's no separate :hover look). */
.zoomTrigger:active {
  opacity: 0.55;
  color: var(--ink-dim);
  border-color: rgba(185, 141, 79, 0.35);
  background: rgba(23, 17, 12, 0.45);
}

.zoomTrigger:focus-visible {
  outline: 2px solid var(--lamp);
  outline-offset: 2px;
}

.zoomTrigger svg {
  width: 20px;
  height: 20px;
}

/* --------------------------------------------------------------------------
   Controls
   -------------------------------------------------------------------------- */

/* the whole nav reads as one mounted brass-and-leather console rather
   than buttons floating loose on the desk photo — a self-contained
   pill sitting just above the bottom edge of the screen */
#navPanel {
  flex: 0 0 auto;
  align-self: center;
  margin-bottom: 20px;
  display: flex;
  justify-content: center;
  padding: 10px;
  background: linear-gradient(180deg, rgba(36, 26, 17, 0.75) 0%, rgba(23, 17, 12, 0.75) 100%);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  border-radius: 999px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}

/* revealed once "Touch to Begin" starts the book opening, alongside
   it rather than being visible underneath the start screen the whole
   time and then just appearing the instant that overlay is gone */
#navPanel.shown {
  opacity: 1;
  transform: translateY(0);
}

/* small credits/contact trigger, tucked in a corner rather than taking
   a seat in the main nav console — revealed alongside #navPanel (same
   "shown" trigger from beginReading in app.js) rather than sitting
   exposed on top of the start screen */
#infoBtn {
  position: fixed;
  top: 22px;
  right: 22px;
  z-index: 50;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-dim);
  background: rgba(23, 17, 12, 0.45);
  border: 1px solid rgba(185, 141, 79, 0.35);
  border-radius: 50%;
  cursor: pointer;
  touch-action: manipulation;
  opacity: 0;
  transition: opacity 0.8s ease, color 0.15s, border-color 0.15s, background 0.15s;
}

#infoBtn.shown {
  opacity: 0.6;
}

#infoBtn:hover,
#infoBtn:active,
#infoBtn:focus-visible {
  opacity: 1;
  color: var(--lamp);
  border-color: var(--brass);
  background: rgba(23, 17, 12, 0.7);
}

#infoBtn:focus-visible {
  outline: 2px solid var(--lamp);
  outline-offset: 2px;
}

#infoBtn svg {
  width: 20px;
  height: 20px;
}

#controls {
  display: flex;
  align-items: center;
  gap: 22px;
  touch-action: manipulation;
}

/* shared "brass pill" chrome — the real nav buttons (button.nav) and
   the scrub track's page-readout tag (#scrubTag below), which isn't a
   <button> but is deliberately styled to match so it reads as part of
   the same control family */
button.nav,
#scrubTag {
  color: var(--btn-text);
  background: linear-gradient(180deg, var(--btn-fill-hover), var(--btn-fill));
  border: 1px solid var(--btn-border);
  border-radius: 999px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.5),
              inset 0 1px 0 rgba(255, 255, 255, 0.4),
              inset 0 -2px 3px rgba(0, 0, 0, 0.15);
}

button.nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 64px;
  font-family: inherit;
  font-size: 15px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0 28px;
  cursor: pointer;
  touch-action: manipulation;
  transition: color 0.15s, background 0.15s, box-shadow 0.15s, transform 0.15s;
}

.navIcon {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
}

/* Back/Next: icon-only, circular, and a touch bigger than the text
   buttons since the arrow alone has to read clearly at a glance */
button.nav.navIconBtn {
  width: 64px;
  height: 64px;
  padding: 0;
  justify-content: center;
  border-radius: 50%;
}

.navIconLg {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
}

button.nav:hover,
button.nav:active {
  color: var(--btn-text);
  background: linear-gradient(180deg, #e6cda3, var(--btn-fill-hover));
}

button.nav:active {
  transform: translateY(1px);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5),
              inset 0 1px 0 rgba(255, 255, 255, 0.3),
              inset 0 -1px 2px rgba(0, 0, 0, 0.15);
}

button.nav:focus-visible {
  outline: 2px solid var(--lamp);
  outline-offset: 2px;
}

#scrubWrap {
  position: relative;
  width: 560px;
  height: 34px;
  /* no extra margin — the shared #controls gap alone spaces this from
     prev/next, matching the home-to-prev and next-to-chapters gaps */
}

/* dim background rail, carved into the panel */
#scrubTrackBg {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 6px;
  transform: translateY(-50%);
  background: var(--ink);
  border-radius: 3px;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
}

/* brass fill showing how far into the book the current page is */
#scrubFill {
  position: absolute;
  left: 0;
  top: 50%;
  width: 0;
  height: 6px;
  transform: translateY(-50%);
  background: linear-gradient(to right, var(--brass-dim), var(--brass));
  border-radius: 3px;
  pointer-events: none;
}

/* small marks showing where each chapter begins */
#scrubTicks {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  pointer-events: none;
}

.scrubTick {
  position: absolute;
  top: 50%;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--room);
  border: 1px solid var(--brass-dim);
  transform: translate(-50%, -50%);
  transition: background 0.2s, border-color 0.2s;
}

.scrubTick.passed {
  background: var(--lamp);
  border-color: var(--brass);
}

#scrub {
  position: relative;
  width: 100%;
  display: block;
  appearance: none;
  height: 34px;
  background: transparent;
  cursor: pointer;
  touch-action: manipulation;
}

#scrub::-webkit-slider-runnable-track {
  height: 6px;
  background: transparent;
}

#scrub::-moz-range-track {
  height: 6px;
  background: transparent;
}

/* the real thumb stays interactive (it's what actually drags) but is
   rendered invisible — the parchment box below is the visible stand-in */
#scrub::-webkit-slider-thumb {
  appearance: none;
  width: 30px;
  height: 30px;
  margin-top: -12px;
  border-radius: 50%;
  background: transparent;
  border: none;
  box-shadow: none;
  opacity: 0;
}

#scrub::-moz-range-thumb {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: transparent;
  border: none;
  opacity: 0;
}

/* page box — this IS the scrub thumb, centered on the track (shared
   pill chrome above) */
#scrubTag {
  position: absolute;
  top: 50%;
  left: 0;
  z-index: 2;
  transform: translate(-50%, -50%);
  pointer-events: none;
  white-space: nowrap;
  font-family: Georgia, 'Palatino Linotype', Palatino, serif;
  font-style: italic;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  padding: 8px 18px;
}

/* --------------------------------------------------------------------------
   Overlays — shared by the chapter menu, idle prompt, and credits modal.
   Fade/pop via overlayFadeIn/panelPopIn; `.leaving` (set by app.js's
   closeOverlayAnimated()) reverses it. Start screen opts out separately.
   -------------------------------------------------------------------------- */

.overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 6, 3, 0.72);
  touch-action: manipulation;
  animation: overlayFadeIn 0.2s ease-out;
}

.overlay.leaving {
  animation: overlayFadeIn 0.2s ease-in reverse forwards;
}

.overlay[hidden] {
  display: none;
}

.paperPanel {
  background-image: url('../img/paperInfoBoxBG.webp');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  filter: drop-shadow(0 25px 55px rgba(0, 0, 0, 0.6));
  animation: panelPopIn 0.25s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.overlay.leaving .paperPanel {
  animation: panelPopIn 0.2s cubic-bezier(0.4, 0, 0.8, 0.2) reverse forwards;
}

.paperPanel h2 {
  font-weight: 400;
  color: var(--btn-text);
}

@keyframes overlayFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes panelPopIn {
  from { opacity: 0; transform: scale(0.94) translateY(14px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* shared dialog header (title + × close button), used by the chapter
   menu and credits modal — identical in both, so styled once here
   rather than duplicated per dialog */
.dialogHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 32px 40px 18px;
  border-bottom: 1px solid rgba(90, 60, 30, 0.4);
  margin: 0 8px;
  flex: 0 0 auto;
}

.dialogHead h2 {
  font-size: 22px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.dialogClose {
  background: none;
  border: none;
  color: var(--btn-text);
  font-size: 30px;
  line-height: 1;
  padding: 0 6px;
  cursor: pointer;
  touch-action: manipulation;
  transition: color 0.15s;
}

.dialogClose:hover,
.dialogClose:active {
  color: var(--brass-dim);
}

@media (prefers-reduced-motion: reduce) {
  .overlay,
  .overlay.leaving,
  .paperPanel,
  .overlay.leaving .paperPanel {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Start screen — the book's real title page, shown once on first load.
   First-touch gate only — doesn't reappear on idle (an ignored idle
   prompt reloads instead, see app.js). Sits above every other overlay.
   -------------------------------------------------------------------------- */

#startOverlay {
  --start-corner-inset: 34px; /* how far the corner brackets sit from the screen edge */
  --start-frame-gap: 8px;     /* gap between the gold frame and the brackets */
  z-index: 300;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: none; /* opts out of the shared .overlay entrance fade — see the Overlays section above */
}

/* walnut wash over the same desk texture as the body background. Lives
   on ::before, not #startOverlay's own background, so blur() can soften
   just this layer. A negative z-index child paints *above* its parent's
   own background (counter-intuitively) — so this must be the only
   background layer here, not layered under one on #startOverlay itself. */
#startOverlay::before {
  content: "";
  position: absolute;
  inset: -20px; /* larger than the element so the blur doesn't fringe at the edges */
  z-index: -1;
  background:
    radial-gradient(ellipse at center, rgba(255, 224, 178, 0.16) 0%, rgba(255, 224, 178, 0) 45%, rgba(0, 0, 0, 0.55) 100%),
    linear-gradient(rgba(23, 17, 12, 0.65), rgba(23, 17, 12, 0.65)),
    url('../img/Paper_0029_Layer 7.webp') center center / contain no-repeat;
  filter: blur(4px);
  pointer-events: none;
}

/* no entrance animation (present at full opacity from page load) —
   only this exit dissolve, reusing startOverlayIn in reverse. JS
   holds off on hiding it until this finishes (see dismissStartScreen). */
#startOverlay.leaving {
  animation: startOverlayIn 0.35s ease-in reverse forwards;
}

/* thin gold rule just inside the screen edge, framing the whole
   overlay (corner brackets included) rather than leaving them to
   float unbounded */
#startOverlay::after {
  content: "";
  position: absolute;
  inset: calc(var(--start-corner-inset) - var(--start-frame-gap));
  border: 2px solid var(--brass);
  opacity: 0.85;
  pointer-events: none;
}

/* ornate corner brackets — a period picture-frame cue at the screen's
   edges (cornerBracket2.png, rotated per corner). Earlier hand-drawn
   SVG versions live in git history if we want a code-only look again. */
#startCorners {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.startCorner {
  position: absolute;
  width: 110px;
  height: auto;
  opacity: 0.85;
}

/* rotated into place rather than mirrored — the source image's
   floral detail and shading read as "backwards" when flipped. The
   image's own right-angle sits at its top-right, so that corner
   needs no rotation; the other three are derived from it. */
.startCorner--tl { top: var(--start-corner-inset); left: var(--start-corner-inset); transform: rotate(-90deg); }
.startCorner--tr { top: var(--start-corner-inset); right: var(--start-corner-inset); }
.startCorner--bl { bottom: var(--start-corner-inset); left: var(--start-corner-inset); transform: rotate(180deg); }
.startCorner--br { bottom: var(--start-corner-inset); right: var(--start-corner-inset); transform: rotate(90deg); }

/* drifting dust motes — a handful of soft lamplit specks generated by
   JS (see spawnStartMotes in app.js) with randomized position, size,
   drift distance, and timing so they read as ambient rather than a
   repeating pattern */
#startMotes {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.startMote {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 217, 160, 0.9) 0%, rgba(255, 217, 160, 0) 70%);
  animation: moteDrift var(--mote-duration) ease-in-out infinite,
             moteFade var(--mote-duration) ease-in-out infinite;
  animation-delay: var(--mote-delay);
}

@keyframes moteDrift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(var(--mote-drift-x), var(--mote-drift-y2)); }
  50%  { transform: translate(var(--mote-drift-x2), var(--mote-drift-y)); }
  75%  { transform: translate(var(--mote-drift-x3), var(--mote-drift-y3)); }
  100% { transform: translate(0, 0); }
}

@keyframes moteFade {
  0%, 100% { opacity: 0; }
  50%      { opacity: var(--mote-peak); }
}

#startPanel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 36px;
  animation: startPanelIn 0.5s cubic-bezier(0.2, 0.8, 0.3, 1);
}

#startOverlay.leaving #startPanel {
  animation: startPanelIn 0.35s cubic-bezier(0.4, 0, 0.8, 0.2) reverse forwards;
}

/* warm lamplight glow behind the title page, echoing #stage::before —
   breathes slowly while the screen waits for a touch */
#startPanel::before {
  content: "";
  position: absolute;
  inset: -10% -20%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 55% 60% at 50% 42%,
    rgba(255, 217, 160, 0.22) 0%,
    rgba(255, 217, 160, 0.08) 45%,
    transparent 72%);
  animation: startGlowBreathe 5s ease-in-out infinite;
}

@keyframes startGlowBreathe {
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 1; }
}

#startTitleImage {
  max-height: 74vh;
  width: auto;
  filter: drop-shadow(0 30px 70px rgba(0, 0, 0, 0.7));
  animation: startBookFloat 3.5s ease-in-out infinite;
}

#startBegin {
  margin-top: -25px;
  animation: startBeginPulse 2.4s ease-in-out infinite;
}

@keyframes startOverlayIn {
  from { opacity: 0; filter: blur(16px); }
  to   { opacity: 1; filter: blur(0); }
}

@keyframes startPanelIn {
  from { opacity: 0; transform: scale(0.96) translateY(10px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes startBeginPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

@keyframes startBookFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-20px) rotate(0.8deg); }
}

@media (prefers-reduced-motion: reduce) {
  #startOverlay,
  #startOverlay.leaving,
  #startPanel,
  #startOverlay.leaving #startPanel,
  #startPanel::before,
  #startBegin,
  #startTitleImage,
  #book,
  #navPanel,
  #infoBtn {
    animation: none;
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   Idle "still there?" prompt
   -------------------------------------------------------------------------- */

#idleOverlay {
  z-index: 200;
}

#idlePanel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  width: min(480px, 90vw);
  padding: 52px 40px 44px;
  text-align: center;
}

#idlePanel h2 {
  font-size: 24px;
  letter-spacing: 0.06em;
}

#idlePanel p {
  font-size: 16px;
  color: var(--btn-text);
  opacity: 0.85;
  margin: -8px 0 6px;
}

/* Countdown bar — width set to 0 with a linear transition timed to
   cfg.idleWarning (see showIdleWarning() in app.js), so it depletes
   at the same rate the "still there?" prompt is actually counting
   down. Reset to full width with no transition before each show. */
#idleTimerTrack {
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: rgba(52, 33, 15, 0.15);
  overflow: hidden;
}

#idleTimerFill {
  height: 100%;
  width: 100%;
  background: var(--brass);
}

/* --------------------------------------------------------------------------
   Chapter menu
   -------------------------------------------------------------------------- */

#chapterOverlay {
  z-index: 100;
}

#chapterPanel {
  display: flex;
  flex-direction: column;
  width: min(640px, 90vw);
  max-height: 80vh;
  overflow: hidden;
}

#chapterList {
  overflow-y: auto;
  padding: 8px 16px 28px;
}

.chapterRow {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  text-align: left;
  font-family: inherit;
  font-size: 18px;
  color: var(--btn-text);
  background: none;
  border: none;
  border-bottom: 1px solid rgba(90, 60, 30, 0.3);
  padding: 18px 18px;
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.15s, color 0.15s;
}

.chapterRowTitle {
  flex: 0 1 auto;
}

/* dotted leader filling the gap between title and page number, same
   idea as a printed table of contents */
.chapterRowDots {
  flex: 1 1 auto;
  min-width: 20px;
  border-bottom: 1px dotted rgba(90, 60, 30, 0.55);
  margin-bottom: 5px;
}

.chapterRowPage {
  flex: 0 0 auto;
  font-style: italic;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

.chapterRow:last-child {
  border-bottom: none;
}

.chapterRow:hover,
.chapterRow:active {
  background: rgba(139, 90, 43, 0.18);
  color: var(--room);
}

.chapterRow:focus-visible {
  outline: 2px solid var(--brass-dim);
  outline-offset: -2px;
}

/* --------------------------------------------------------------------------
   Credits / info modal
   -------------------------------------------------------------------------- */

/* only these two dialogs blur the book behind them (the idle prompt
   doesn't) — grouped here since #infoOverlay is the second and last
   place that needs it */
#chapterOverlay,
#infoOverlay,
#debugOverlay {
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

#infoOverlay {
  z-index: 250;
}

#infoPanel {
  display: flex;
  flex-direction: column;
  width: min(520px, 90vw);
  max-height: 80vh;
  overflow: hidden;
}

/* shared "scrollable rich content area inside a dialog" — the credits
   body and the debug tools panel below both use it */
.dialogBody {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 24px 40px 36px;
  color: var(--btn-text);
}

.dialogBody p {
  font-size: 16px;
  line-height: 1.7;
  margin: 0 0 16px;
}

.dialogBody p:last-child {
  margin-bottom: 0;
}

.dialogBody h3 {
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.7;
  margin: 24px 0 8px;
}

.dialogBody h3:first-child {
  margin-top: 0;
}

.dialogBody a {
  color: inherit;
}

/* separate from the credits text, always visible — an escape hatch to
   bring the start screen back up between kiosk visitors, without
   waiting on idle. Kept deliberately quiet (plain icon, not button.nav). */
#infoFooter {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  padding: 14px 40px 20px;
  border-top: 1px solid rgba(90, 60, 30, 0.4);
  margin: 0 8px;
}

#infoRestart {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px;
  color: var(--btn-text);
  background: none;
  border: none;
  opacity: 0.4;
  cursor: pointer;
  touch-action: manipulation;
  transition: opacity 0.15s;
}

#infoRestart:hover,
#infoRestart:active,
#infoRestart:focus-visible {
  opacity: 0.85;
}

#infoRestart:focus-visible {
  outline: 2px solid var(--brass-dim);
  outline-offset: 2px;
}

#infoRestart svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  transition: transform 0.15s;
}

#infoRestart:active svg {
  transform: rotate(-45deg);
}

#infoRestart span {
  font-size: 13px;
  font-style: italic;
}

/* --------------------------------------------------------------------------
   Debug tools — hidden developer panel, see index.html and the "Debug
   tools" section of app.js. Highest z-index of any dialog, reached via
   an 8-second hold on #infoBtn.
   -------------------------------------------------------------------------- */

#debugOverlay {
  z-index: 350;
}

#debugPanel {
  display: flex;
  flex-direction: column;
  width: min(560px, 92vw);
  max-height: 82vh;
  overflow: hidden;
}

/* shared layout for the panel's two "number field + submit" rows
   (jump-to-page, idle-timeout) */
.debugInlineForm {
  display: flex;
  gap: 12px;
  align-items: center;
}

.debugInlineForm input[type="number"] {
  flex: 1 1 auto;
  min-width: 0;
  font-family: inherit;
  font-size: 15px;
  padding: 10px 14px;
  border-radius: 8px;
  border: 1px solid var(--btn-border);
  background: rgba(255, 255, 255, 0.5);
  color: var(--btn-text);
}

#debugPageReadout {
  font-style: italic;
  opacity: 0.75;
}

.debugHint {
  font-size: 13px;
  font-style: italic;
  opacity: 0.65;
}

#debugSoundToggle {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  cursor: pointer;
}

#debugSoundToggle input {
  width: 18px;
  height: 18px;
  accent-color: var(--brass);
  cursor: pointer;
}

#debugConfigList {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 16px;
  font-size: 14px;
}

#debugConfigList dt {
  font-weight: 700;
  opacity: 0.7;
}

#debugConfigList dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

#debugConsoleLog {
  max-height: 160px;
  overflow-y: auto;
  font-family: 'Courier New', monospace;
  font-size: 12px;
  line-height: 1.5;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 8px;
  padding: 10px 12px;
}

.debugLogEntry {
  padding: 2px 0;
}

.debugLogEntry--warn {
  color: #8a5a00;
}

.debugLogEntry--error {
  color: #b3261e;
}

.debugLogEmpty {
  opacity: 0.6;
  font-style: italic;
}

/* --------------------------------------------------------------------------
   Illustration zoom — reuses .overlay for the shared fade/[hidden]
   behavior, but skips .paperPanel: a plain image lightbox, not a text
   dialog, so it gets its own darker backdrop and close-button styling.
   -------------------------------------------------------------------------- */

#zoomOverlay {
  z-index: 150;
  background: rgba(8, 5, 2, 0.9);
}

#zoomImage {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
  filter: drop-shadow(0 25px 55px rgba(0, 0, 0, 0.6));
  /* pinch-zoom/rotate is handled ourselves (see attachPinchZoom in
     app.js) rather than left to the browser's native pinch-zoom,
     which is off kiosk-wide — touch-action: none here just makes
     sure the browser doesn't also try to scroll/zoom the page
     underneath our own two-finger tracking */
  touch-action: none;
  transform-origin: center center;
}

#zoomClose {
  position: absolute;
  top: 26px;
  right: 36px;
  background: none;
  border: none;
  color: var(--ink-dim);
  font-size: 34px;
  line-height: 1;
  padding: 0 6px;
  cursor: pointer;
  touch-action: manipulation;
  transition: color 0.15s;
}

#zoomClose:hover,
#zoomClose:active {
  color: var(--lamp);
}

