:root {
  color-scheme: light;
  --paper: #FBF4E6;
  --panel: #FFFDF6;
  --ink: #3A2A20;
  --ink-soft: #6E5647;
  --honey-soft: #FCEBC6;
  --rose: #D9486F;
  --rose-text: #B23358;
  --moss: #6B7F4F;
  --terra: #B36A4C;
  --line: #E4D3B0;
  --serif: "Songti TC", "Noto Serif TC", serif;
  --sans: "PingFang TC", system-ui, sans-serif;
  /* W16 world shell defaults: noon, the paper as it was drawn. Every screen
     reads through these four, so a beat only has to restate them once. */
  --shell-glow: #FFF7E6;
  --shell-nav: rgba(255, 253, 246, .88);
  --shell-veil-soft: rgba(251, 244, 230, .78);
  --shell-veil-strong: rgba(251, 244, 230, .94);
  --shell-scene-light: none;
  --shell-map-desk: #FCEBC6;
}

/* W16 world shell: the whole village is read on paper that follows the beat.
   The shift stays inside a few percent — enough that arriving at midnight is
   not the same page as arriving at breakfast, small enough that nothing
   becomes harder to read. The beat is written once, at the screen entrance. */
body[data-beat="morning"] {
  --paper: #FDF7E9;
  --panel: #FFFEF9;
  --line: #E8D9BA;
  --shell-glow: #FFFAEE;
  --shell-nav: rgba(255, 254, 249, .88);
  --shell-veil-soft: rgba(253, 247, 233, .78);
  --shell-veil-strong: rgba(253, 247, 233, .94);
  --shell-scene-light: saturate(1.02) brightness(1.03);
  --shell-map-desk: #FDF0D2;
}

body[data-beat="noon"] {
  --paper: #FBF4E6;
  --panel: #FFFDF6;
  --line: #E4D3B0;
  --shell-glow: #FFF7E6;
  --shell-nav: rgba(255, 253, 246, .88);
  --shell-veil-soft: rgba(251, 244, 230, .78);
  --shell-veil-strong: rgba(251, 244, 230, .94);
  --shell-scene-light: none;
  --shell-map-desk: #FCEBC6;
}

body[data-beat="dusk"] {
  --paper: #F6EBD8;
  --panel: #FDF6E9;
  --line: #DFC9A0;
  --shell-glow: #FDF0DC;
  --shell-nav: rgba(253, 246, 233, .88);
  --shell-veil-soft: rgba(246, 235, 216, .8);
  --shell-veil-strong: rgba(246, 235, 216, .95);
  --shell-scene-light: sepia(.12) saturate(1.05) brightness(.9);
  --shell-map-desk: #E8CFA6;
}

body[data-beat="night"] {
  --paper: #E8E1D6;
  --panel: #F3EDE2;
  --line: #D2C3A4;
  --shell-glow: #F2EADC;
  --shell-nav: rgba(243, 237, 226, .88);
  --shell-veil-soft: rgba(232, 225, 214, .82);
  --shell-veil-strong: rgba(232, 225, 214, .95);
  --shell-scene-light: saturate(.74) brightness(.66) contrast(1.03) hue-rotate(-8deg);
  --shell-map-desk: #2E2C38;
}

@font-face {
  font-family: "ChenYuluoyan";
  src: url("/assets/fonts/chenyuluoyan-2.0-thin.woff2") format("woff2");
  font-display: swap;
}

* { box-sizing: border-box; }

html,
body {
  width: 100%;
  height: 100%;
  min-width: 20rem;
  overflow: hidden;
}

body {
  margin: 0;
  background: radial-gradient(75rem 44rem at 20% -10%, var(--shell-glow) 0, transparent 60%), var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  line-height: 1.65;
}

body::after {
  position: fixed;
  inset: 0;
  z-index: 12;
  background-image: radial-gradient(rgba(120, 90, 60, .06) 1px, transparent 1px);
  background-size: 4px 4px;
  content: "";
  opacity: .3;
  pointer-events: none;
}

button,
input,
textarea { font: inherit; }

button { white-space: nowrap; }

button,
a { -webkit-tap-highlight-color: transparent; }

button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 3px solid var(--moss);
  outline-offset: 3px;
}

button:disabled { cursor: not-allowed; opacity: .55; }

h1,
h2,
h3,
h4,
p { margin-block-start: 0; }

h1,
h2,
h3,
h4,
.brand,
.chip,
.primary-button,
.secondary-button,
.choice-button {
  font-family: var(--serif);
}

h1,
h2,
h3,
h4 { line-height: 1.35; text-wrap: balance; }

p,
li { text-wrap: pretty; }

h1 { margin-bottom: .55rem; font-size: clamp(1.75rem, 2.2vw, 2rem); }
h2 { margin-bottom: .5rem; font-size: clamp(1.25rem, 1.8vw, 1.55rem); }
h3 { margin-bottom: .25rem; font-size: .95rem; }
h4 { margin-bottom: .25rem; font-size: .9rem; }

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

.skip-link {
  position: fixed;
  top: .5rem;
  left: .5rem;
  z-index: 40;
  transform: translateY(-160%);
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--panel);
  color: var(--ink);
  padding: .6rem 1rem;
}

.skip-link:focus { transform: none; }

.site-header {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 26px;
  pointer-events: none;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  color: var(--ink);
  text-decoration: none;
  pointer-events: auto;
}

.brandmark {
  display: flex;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--rose);
  box-shadow: 2px 2px 0 var(--ink);
  color: #fff;
  font-family: var(--serif);
  font-size: 22px;
}

.brand { font-size: 22px; }
.brand small { color: var(--ink-soft); font-family: var(--sans); font-size: 11px; letter-spacing: 2px; }

body[data-tone="scenic"] .brand {
  color: #FFF8EA;
  text-shadow: 0 1px 3px rgba(58, 42, 32, .55);
}

body[data-tone="scenic"] .brand small { color: inherit; opacity: .9; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 3px;
  margin-left: auto;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--shell-nav);
  padding: 2px 6px;
  pointer-events: auto;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.nav-button {
  border: 0;
  background: transparent;
  color: var(--rose-text);
  cursor: pointer;
  padding: 6px 8px;
  font-family: var(--serif);
  font-size: 13px;
}

body[data-screen="guest"] .main-nav { display: none; }

.audio-controls {
  position: relative;
  display: flex;
  align-items: center;
  pointer-events: auto;
}

body[data-screen="guest"] .audio-controls { margin-left: auto; }

.audio-toggle {
  border: 1px solid rgba(58, 42, 32, .28);
  border-radius: 999px;
  background: rgba(255, 253, 246, .9);
  color: var(--rose-text);
  cursor: pointer;
  padding: 6px 10px;
  font-family: var(--serif);
  font-size: 12px;
  box-shadow: 1px 1px 0 rgba(58, 42, 32, .18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.audio-toggle[aria-pressed="true"] { background: var(--moss); color: #fff; }

.app-version {
  margin-left: 6px;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  cursor: copy;
  padding: 4px 2px;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .03em;
  opacity: .76;
}

.app-version:hover,
.app-version:focus-visible { opacity: 1; }

.app-update-notice {
  position: absolute;
  top: calc(100% - 8px);
  right: 26px;
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid rgba(58, 42, 32, .22);
  border-radius: 999px;
  background: rgba(255, 253, 246, .96);
  box-shadow: 2px 2px 0 rgba(58, 42, 32, .14);
  color: var(--ink-soft);
  padding: 6px 7px 6px 13px;
  font-size: 11px;
  line-height: 1.4;
  pointer-events: none;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.app-update-notice button {
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--honey-soft);
  color: var(--rose-text);
  cursor: pointer;
  padding: 4px 9px;
  font-family: var(--serif);
  font-size: 11px;
  pointer-events: auto;
}

.audio-mix-toggle {
  margin-left: 6px;
  border: 1px solid rgba(58, 42, 32, .22);
  border-radius: 999px;
  background: rgba(255, 253, 246, .76);
  color: var(--ink-soft);
  cursor: pointer;
  padding: 4px 7px;
  font-family: var(--serif);
  font-size: 11px;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.audio-mix-toggle[aria-expanded="true"] { background: var(--honey-soft); }

.audio-mix {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  display: grid;
  width: min(20rem, calc(100vw - 2rem));
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 12px;
  border: 1.5px solid var(--line);
  border-radius: 13px;
  background: rgba(255, 253, 246, .97);
  box-shadow: 3px 3px 0 rgba(58, 42, 32, .18);
  padding: 12px;
}

.audio-mix label { display: grid; gap: 2px; color: var(--ink-soft); font-size: 11px; }
.audio-mix input { min-height: 20px; padding: 0; accent-color: var(--rose); }
.audio-status { position: fixed; right: 1rem; bottom: 1rem; z-index: 35; max-width: min(24rem, calc(100% - 2rem)); margin: 0; border-radius: 999px; background: rgba(255, 253, 246, .9); color: var(--ink-soft); padding: 5px 12px; font-size: 11px; line-height: 1.45; pointer-events: none; transition: opacity .35s ease; }
.audio-status:empty { opacity: 0; }

.check-row { display: flex; align-items: center; gap: .55rem; padding: .35rem 0; color: var(--ink); }
.check-row input { width: 1rem; height: 1rem; accent-color: var(--rose); }
.paired-arrival-names { display: flex; align-items: center; justify-content: center; gap: .75rem; margin: 1.25rem 0; color: var(--rose-text); font-family: var(--serif); font-size: clamp(1.25rem, 4vw, 1.7rem); }

#game {
  position: fixed;
  inset: 0;
  width: 100dvw;
  height: 100dvh;
  overflow: hidden;
  outline: none;
}

.screen {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  gap: 13px;
  overflow: hidden;
  padding: 78px 26px 24px;
  animation: page-arrive .32s ease-out both;
}

.screen::before {
  position: absolute;
  inset: 0;
  z-index: -2;
  background: radial-gradient(75rem 44rem at 20% -10%, var(--shell-glow) 0, transparent 60%), var(--paper);
  content: "";
}

/* A picture drawn one morning still hangs under the light of the hour the
   player actually arrived in. The light lands on the picture itself and on
   nothing else — never a sheet laid over the page, which would sooner or later
   end up over somebody's words. At midday it is left exactly as it was drawn. */
.scene-backed > img,
.scene-backed > .scene-composition-background,
.scene-figure > img { filter: var(--shell-scene-light); }

.scene-backed { padding: 0; }

.scene-backed > img,
.scene-backed > .image-fallback:first-child,
.scene-backed > .scene-composition-background {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

.scene-backed > .image-fallback:first-child { display: grid; place-items: center; }

.scene-vignette,
.paper-vignette {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.scene-vignette {
  background: linear-gradient(90deg, rgba(58, 42, 32, .43) 0, rgba(58, 42, 32, .16) 40%, transparent 64%), linear-gradient(180deg, rgba(58, 42, 32, .14), transparent 25%, transparent 68%, rgba(58, 42, 32, .36));
}

.paper-vignette { background: linear-gradient(var(--shell-veil-soft), var(--shell-veil-strong)); }

.eyebrow {
  margin-bottom: .35rem;
  color: var(--rose-text);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 3px;
}

.lede { margin-bottom: 0; color: var(--ink-soft); font-size: .95rem; line-height: 1.8; }
.lede.compact { max-width: 56ch; font-size: .8rem; }
.muted { color: var(--ink-soft); }

.chip {
  display: inline-flex;
  width: fit-content;
  align-items: center;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: var(--honey-soft);
  color: var(--ink-soft);
  padding: 4px 13px;
  font-size: 12px;
  line-height: 1.35;
}

.card,
.floating-panel {
  border: 2px solid var(--ink);
  border-radius: 14px;
  background: var(--panel);
  box-shadow: 3px 3px 0 rgba(58, 42, 32, .18);
  padding: 14px 16px;
}

.primary-button,
.secondary-button,
.choice-button {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--ink);
  border-radius: 12px;
  box-shadow: 2px 2px 0 rgba(58, 42, 32, .2);
  cursor: pointer;
  padding: 10px 16px;
  transition: transform .18s ease, box-shadow .18s ease;
  white-space: nowrap;
}

.primary-button { background: var(--rose); color: #fff; }
.secondary-button,
.choice-button { background: var(--paper); color: var(--rose-text); }

.primary-button:hover,
.secondary-button:hover,
.choice-button:hover { transform: translate(-1px, -1px); box-shadow: 3px 3px 0 rgba(58, 42, 32, .22); }
.primary-button:active,
.secondary-button:active,
.choice-button:active { transform: translate(1px, 1px); box-shadow: none; }

.actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }

.image-fallback {
  display: grid;
  min-height: 9rem;
  place-items: center;
  background: var(--honey-soft);
  color: var(--ink-soft);
  padding: 1.5rem;
  text-align: center;
}

/* G14 landing */
.landing-screen { padding: 0; }
.landing-screen > img { object-position: center 30%; }

.landing-hero {
  position: absolute;
  top: clamp(9.5rem, 22dvh, 12.5rem);
  left: clamp(1.5rem, 4vw, 4rem);
  z-index: 2;
  width: min(35rem, calc(100% - 3rem));
}

.landing-hero h1 {
  margin-bottom: 16px;
  color: #FFF8EA;
  font-size: clamp(2.6rem, 3.25vw, 3.25rem);
  line-height: 1.3;
  text-shadow: 0 2px 8px rgba(58, 42, 32, .6);
}

.landing-subtitle {
  color: #FFF3E0;
  font-family: var(--serif);
  font-size: clamp(1rem, 1.25vw, 1.25rem);
  line-height: 1.8;
  text-shadow: 0 1px 4px rgba(58, 42, 32, .6);
  white-space: pre-line;
}

.landing-actions { display: flex; gap: 14px; margin-top: 34px; }
.landing-actions button { min-height: 52px; padding: 12px 24px; font-size: 18px; }
.landing-actions + .village-return-card { margin-top: 16px; }
.landing-resume-actions { margin-top: 12px; }
.landing-resume-button {
  min-height: 38px;
  border-color: rgba(255, 243, 224, .72);
  background: rgba(58, 42, 32, .48);
  box-shadow: none;
  color: #FFF3E0;
  padding: 8px 15px;
  font-size: 14px;
}
.landing-note,
.scene-footnote,
.visitor-banner {
  width: fit-content;
  border-radius: 999px;
  background: rgba(58, 42, 32, .5);
  color: #FFF3E0;
  padding: 5px 14px;
  font-size: 12px;
}

.landing-note { margin-top: 22px; font-family: var(--sans); font-size: 13px; }
.scene-footnote { position: absolute; bottom: 34px; left: clamp(1.5rem, 4vw, 4rem); z-index: 3; margin: 0; }
.scene-footnote.centered { right: 1rem; left: 1rem; margin-inline: auto; text-align: center; }

/* G1 routes */
.routes-screen > img { object-position: center 30%; }
.routes-content {
  z-index: 2;
  width: min(67.5rem, calc(100% - 3rem));
  margin: 0 auto;
  padding: 6.7rem 0 2.25rem;
}
.routes-intro { text-align: center; }
.routes-intro h1 { font-size: clamp(1.8rem, 2.3vw, 2.15rem); letter-spacing: 2px; }
.routes-screen { overflow: auto; }
.companion-route-card {
  position: relative;
  overflow: hidden;
  margin-top: 1.8rem;
  border: 2.5px solid var(--ink);
  border-radius: 22px;
  background: var(--panel);
  box-shadow: 6px 8px 0 rgba(58, 42, 32, .17);
  padding: 2.45rem 2.5rem 1.85rem;
  text-align: center;
}
.companion-route-card::before {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 7px;
  background: linear-gradient(90deg, var(--rose) 0 50%, var(--moss) 50% 100%);
  content: "";
}
.admission-pair { display: flex; align-items: center; justify-content: center; gap: .85rem; margin-bottom: .8rem; }
.admission-badge {
  display: inline-grid;
  width: 3.5rem;
  height: 3.5rem;
  place-items: center;
  border: 2px solid var(--ink);
  border-radius: 50%;
  box-shadow: 2px 2px 0 rgba(58, 42, 32, .18);
  color: #fff;
  font-family: var(--serif);
  font-size: 1.1rem;
  line-height: 1;
}
.admission-badge-human { background: var(--terra); }
.admission-badge-ai { background: var(--moss); }
.admission-pair-plus { color: var(--ink-soft); font-family: var(--serif); font-size: 1.45rem; }
.companion-route-card h2 { margin-bottom: .4rem; color: var(--ink); font-size: clamp(1.4rem, 2.35vw, 1.75rem); letter-spacing: .08em; }
.companion-route-lead { max-width: 50rem; margin: 0 auto 1.35rem; color: var(--ink); font-size: .98rem; line-height: 1.85; }
.companion-route-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .85rem; margin-bottom: 1.45rem; text-align: left; }
.companion-route-step { min-width: 0; border: 1.5px solid var(--line); border-radius: 14px; background: var(--honey-soft); padding: .8rem .9rem; }
.companion-route-step strong { display: block; margin-bottom: .2rem; color: var(--rose-text); font-family: var(--serif); font-size: .9rem; letter-spacing: .04em; }
.companion-route-step p { margin: 0; color: var(--ink); font-size: .82rem; line-height: 1.7; }
.companion-route-cta {
  min-height: 48px;
  border: 2px solid var(--ink);
  border-radius: 14px;
  background: var(--rose);
  box-shadow: 3px 4px 0 rgba(58, 42, 32, .25);
  color: #fff;
  cursor: pointer;
  padding: .65rem 2.85rem;
  font-family: var(--serif);
  font-size: 1.08rem;
  letter-spacing: .14em;
  transition: transform .18s ease, box-shadow .18s ease;
  white-space: nowrap;
}
.companion-route-cta:hover:not(:disabled) { transform: translate(-1px, -1px); box-shadow: 4px 5px 0 rgba(58, 42, 32, .25); }
.companion-route-cta:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: none; }
.companion-route-cta.dim { border-style: dashed; box-shadow: none; }
.companion-route-note { margin: .7rem 0 0; color: var(--ink-soft); font-size: .78rem; }
.secondary-route-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.1rem; margin-top: 1.6rem; }
.secondary-route-card {
  width: 100%;
  min-width: 0;
  border: 2px solid var(--ink);
  border-radius: 16px;
  background: var(--panel);
  box-shadow: 4px 5px 0 rgba(58, 42, 32, .1);
  color: var(--ink);
  cursor: pointer;
  padding: 1.05rem 1.15rem;
  text-align: left;
  white-space: normal;
}
.secondary-route-card:hover:not(:disabled) { border-color: var(--rose-text); transform: translate(-1px, -1px); box-shadow: 5px 6px 0 rgba(58, 42, 32, .14); }
.secondary-route-card:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: 2px 2px 0 rgba(58, 42, 32, .1); }
.secondary-route-card .secondary-route-badge { width: auto; height: auto; border: 0; border-radius: 999px; box-shadow: none; padding: .17rem .6rem; font-family: var(--sans); font-size: .7rem; letter-spacing: .14em; }
.secondary-route-title { display: block; margin: .55rem 0 .25rem; color: var(--rose-text); font-family: var(--serif); font-size: 1rem; font-weight: 700; letter-spacing: .035em; }
.secondary-route-card p { margin: 0; color: var(--ink); font-size: .8rem; line-height: 1.7; }
.secondary-route-card.dim { border-style: dashed; box-shadow: none; opacity: .62; }
.secondary-route-card:disabled { cursor: default; }
.route-availability-copy { margin-top: 6px !important; color: var(--rose-text) !important; font-weight: 700; }
.routes-footnote { margin: 1.7rem auto 0; max-width: 56rem; color: var(--ink-soft); font-size: .8rem; line-height: 1.7; text-align: center; }

@media (max-width: 860px) {
  .companion-route-card { padding: 2.1rem 1.1rem 1.35rem; }
  .companion-route-steps { grid-template-columns: 1fr; gap: .65rem; }
  .secondary-route-grid { grid-template-columns: 1fr; gap: .8rem; }
  .secondary-route-card { padding: .95rem 1rem; }
}

/* G15 application and shared floating panels */
.application-screen > img,
.interview-screen > img,
.portraits-screen > img,
.handbook-screen > img { object-position: left 32%; }
.application-screen .scene-vignette,
.interview-screen .scene-vignette,
.portraits-screen .scene-vignette,
.handbook-screen .scene-vignette { background: linear-gradient(90deg, transparent 0, transparent 36%, rgba(58, 42, 32, .32) 100%); }
.floating-panel { z-index: 3; }
.application-card,
.status-screen .floating-panel,
.leave-screen .floating-panel {
  position: absolute;
  top: 50%;
  right: clamp(1.5rem, 4.5vw, 4.5rem);
  width: min(32.5rem, calc(100% - 3rem));
  max-height: calc(100dvh - 7rem);
  overflow: auto;
  transform: translateY(-50%);
  border-radius: 18px;
  padding: 24px 28px;
}
.application-card h1,
.handbook-panel h1,
.leave-screen h1 { font-size: 22px; }
.field { display: grid; gap: 5px; margin-top: 13px; }
.field label { font-family: var(--serif); font-size: 14px; }
.field small { color: var(--ink-soft); font-size: 11px; }
input,
textarea { width: 100%; border: 1.5px solid var(--line); border-radius: 11px; background: var(--paper); color: var(--ink); padding: 10px 13px; }
textarea { min-height: 7rem; resize: vertical; }
.consent-note { margin: 15px 0 0; border: 1.5px dashed var(--line); border-radius: 12px; background: rgba(252, 245, 228, .6); color: var(--ink-soft); padding: 10px 13px; font-size: 12px; line-height: 1.7; }
.keep-note { margin: 12px 0 0; color: var(--ink-soft); font-size: 11px; }

/* 03A / 03B */
.floating-layout { position: absolute; right: 3rem; bottom: 3rem; z-index: 3; display: grid; width: min(58rem, calc(100% - 6rem)); grid-template-columns: minmax(0, 1fr) 14rem; gap: 14px; }
.hearth-question { max-height: calc(100dvh - 9rem); overflow: auto; padding: 20px 22px; }
.hearth-question h1 { font-size: 22px; }
.hearth-question h2 { font-size: 19px; }
.action-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
.portrait-side { text-align: center; }
.villager-portrait { width: 7rem; aspect-ratio: 1; margin: 0 auto 8px; overflow: hidden; border: 2px solid var(--ink); border-radius: 50%; background: var(--honey-soft); }
.villager-portrait img { width: 100%; height: 100%; object-fit: cover; }
.portrait-panel { position: absolute; inset: 78px 26px 24px; z-index: 3; display: flex; min-height: 0; flex-direction: column; overflow: auto; border: 2px solid var(--ink); border-radius: 18px; background: rgba(255, 253, 246, .96); box-shadow: 4px 4px 0 rgba(58, 42, 32, .22); padding: 16px 20px; }
.portrait-head { text-align: center; }
.portrait-head h1 { font-size: 24px; }
.portrait-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.portrait-choice { text-align: center; }
.candidate-portrait { width: min(10rem, 70%); aspect-ratio: 1; margin: 6px auto 8px; overflow: hidden; border: 2px solid var(--ink); border-radius: 14px; background: var(--honey-soft); }
.candidate-portrait img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
.portrait-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 12px; }
.portrait-tool { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: 8px; }
.portrait-tool h3,
.portrait-tool .muted { grid-column: 1 / -1; }

/* G4 */
.trial-screen > img { object-position: center 40%; }
.trial-screen .scene-vignette { background: rgba(251, 244, 230, .88); }
.trial-layout { position: absolute; inset: 82px 4vw 28px; z-index: 3; display: grid; min-height: 0; grid-template-columns: minmax(0, 1fr) 16rem; align-items: center; gap: 14px; }
.certificate-card { position: relative; overflow: hidden; border: 2.5px solid var(--ink); border-radius: 24px; background: #FCF5E4; box-shadow: 8px 8px 0 rgba(58, 42, 32, .18); padding: 24px 28px; }
.certificate-card::before { position: absolute; inset: 10px; border: 1.5px dashed var(--line); border-radius: 16px; content: ""; pointer-events: none; }
.certificate-head { position: relative; display: flex; align-items: center; }
.certificate-head h2 { margin: 0; letter-spacing: 3px; }
.certificate-head p { margin: 0; font-size: 12px; }
.certificate-stamp { display: grid; width: 64px; height: 64px; margin-left: auto; place-items: center; border: 2.5px solid var(--rose); border-radius: 50%; color: var(--rose); font-family: var(--serif); font-size: 13px; line-height: 1.3; text-align: center; white-space: pre-line; transform: rotate(-12deg); }
.certificate-body { position: relative; display: grid; grid-template-columns: minmax(9rem, 15rem) minmax(15rem, 1fr) minmax(14rem, 19rem); gap: 22px; margin-top: 16px; }
.certificate-portrait { overflow: hidden; border: 2px solid var(--ink); border-radius: 16px; background: var(--honey-soft); box-shadow: 3px 3px 0 rgba(58, 42, 32, .15); }
.certificate-portrait img { width: 100%; aspect-ratio: 1; object-fit: cover; object-position: center top; }
.certificate-key { margin: 8px 0 0; color: var(--rose-text); font-size: 11px; font-weight: 700; letter-spacing: 2.5px; }
.certificate-details h1 { margin: 0; font-size: 2rem; }
.certificate-details p:not(.certificate-key) { margin-bottom: 5px; font-family: var(--serif); }
.certificate-rights { align-self: start; font-size: 12px; }
.trial-task { align-self: center; }

/* G20 world overview */
.world-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px 14px; }
.world-head .eyebrow { margin: 0; }
.world-head h1 { margin: 0; font-size: 32px; }
.world-head .chip { margin: 0; }
.world-main { display: grid; min-height: 0; flex: 1; grid-template-columns: minmax(0, 1fr) 430px; gap: 14px; }
.today-guidance { margin: 0; }
.today-guidance .eyebrow { margin-bottom: 8px; }
.today-guidance-list { display: grid; gap: 8px; }
.today-guidance-card { width: 100%; border: 1.5px solid var(--moss); border-radius: 11px; background: rgba(107, 127, 79, .1); color: var(--ink); cursor: pointer; padding: .55rem .7rem; font: inherit; font-size: .82rem; line-height: 1.45; text-align: left; }
.today-guidance-card:hover { background: rgba(107, 127, 79, .18); }
.micro-event-status { color: var(--ink-soft); font-size: .86rem; line-height: 1.7; }
.scene-figure { position: relative; min-height: 0; overflow: hidden; margin: 0; border: 2px solid var(--ink); border-radius: 16px; background: var(--honey-soft); box-shadow: 4px 4px 0 rgba(58, 42, 32, .18); }
.scene-figure > img { width: 100%; height: 100%; object-fit: cover; }
.scene-figure > .image-fallback { width: 100%; height: 100%; }
.scene-caption { position: absolute; bottom: 12px; left: 14px; width: fit-content; max-width: calc(100% - 28px); border: 1.5px solid var(--line); border-radius: 999px; background: rgba(255, 253, 246, .93); color: var(--ink-soft); padding: 5px 14px; font-family: var(--serif); font-size: 12px; }
.scene-caption h3:empty { display: none; }
.scene-caption h3,
.scene-caption p { margin: 0; }

/* SceneCompositionPlanV1 interface-first fixture harness. */
.composer-demo-screen {
  display: grid;
  grid-template: auto auto minmax(22rem, 1fr) / minmax(0, 1fr) minmax(17rem, 24rem);
  gap: 12px 16px;
  overflow: auto;
  padding-bottom: 20px;
}
.composer-demo-head { grid-column: 1 / -1; }
.composer-demo-head h1 { margin-bottom: 5px; }
.composer-demo-head p { margin-bottom: 0; }
.composer-demo-controls {
  display: flex;
  grid-column: 1 / -1;
  flex-wrap: wrap;
  align-items: end;
  gap: 9px;
  border: 1.5px solid var(--line);
  border-radius: 13px;
  background: var(--panel);
  padding: 9px 12px;
}
.composer-control { display: flex; align-items: center; gap: 7px; margin: 0; color: var(--ink-soft); font-size: 11px; }
.composer-control select { min-height: 34px; border: 1px solid var(--line); border-radius: 8px; background: var(--paper); color: var(--ink); padding: 4px 8px; }
fieldset.composer-control { min-width: 0; border: 0; padding: 0; }
.composer-control legend { float: left; margin-right: 7px; }
.composer-control label { display: inline-flex; align-items: center; gap: 3px; }
.composer-control input { width: auto; margin: 0; accent-color: var(--rose); }
.composer-residents { margin-left: auto !important; }
.scene-composition {
  display: grid;
  min-height: 22rem;
  overflow: hidden;
  margin: 0;
  border: 2px solid var(--ink);
  border-radius: 16px;
  background: var(--honey-soft);
  box-shadow: 4px 4px 0 rgba(58, 42, 32, .18);
  grid-template-rows: minmax(0, 1fr) auto;
}
.scene-composition-canvas {
  position: relative;
  min-height: 20rem;
  overflow: hidden;
  isolation: isolate;
  container: scene-stage / size;
}
.scene-composition-background {
  min-height: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  grid-template-rows: minmax(0, 1fr);
}
.scene-composition-background .scene-composition-canvas { width: 100%; height: 100%; min-height: 0; }

/**
 * The stage frame is the coordinate system. Every placement percentage was
 * measured on the 1536x1024 empty base, so the frame keeps that 3:2 ratio and
 * everything standing in the scene — villagers, guest tokens, weather, light —
 * is a child of the frame. One transform crops the picture and the people in it
 * together, so a crop can never move somebody off the mark they were measured
 * on; cropping the background on its own used to shift the ground line by up to
 * 22 percentage points and leave the figures behind.
 *
 * The frame covers the canvas. Of the two ways a 3:2 picture can meet the
 * screen it always takes the larger one and lets the surplus be clipped by the
 * canvas, so no screen ever shows a strip of paper down the side of the
 * picture. This is the sizing the phone was already using: the same two lines
 * now run everywhere rather than a second set of numbers for the desktop.
 */
.scene-stage-frame {
  position: absolute;
  left: 50%;
  top: 50%;
  aspect-ratio: 3 / 2;
  width: auto;
  height: 100cqh;
  margin: auto;
  transform: translate(-50%, -50%);
}
/* Wider than the picture: meet the width instead, and the height overflows. */
@container scene-stage (min-aspect-ratio: 3 / 2) {
  .scene-stage-frame { width: 100cqw; height: auto; }
}
.scene-composition-base-asset,
.scene-composition-base-fallback { position: absolute; inset: 0; width: 100%; height: 100%; }
.scene-composition-base-asset { object-fit: contain; }
.scene-environment-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}
.scene-composition-base-fallback {
  display: grid;
  place-items: center;
  background: linear-gradient(155deg, #DCE7C8, #F7DCA7 62%, #AFC4B1);
  color: var(--ink);
  padding: 2rem;
  font-family: var(--serif);
  text-align: center;
}
.scene-composition[data-visual-time="noon"] .scene-composition-base-fallback { background: linear-gradient(155deg, #BFD9D1, #FAE7AF 58%, #88AA87); }
.scene-composition[data-visual-time="dusk"] .scene-composition-base-fallback { background: linear-gradient(155deg, #D99A79, #F1C58E 55%, #806D7C); }
.scene-composition[data-visual-time="night"] .scene-composition-base-fallback { background: linear-gradient(155deg, #28354B, #4F5872 55%, #172438); color: #FFF3E0; }
.scene-composition-base-fallback[hidden],
.scene-resident-fallback[hidden] { display: none !important; }
/**
 * z-index is written by the composer from the figure's foot line, not by this
 * file: painter's order has to follow where somebody is standing.
 */
.scene-resident-layer {
  position: absolute;
  height: 115%;
  transform: translate(-50%, var(--resident-foot-y-offset, -100%));
  transform-origin: bottom center;
}
/**
 * A sprite cut from the scene carries its own contact surface, so the alpha
 * drop-shadow traced the outline of whatever the villager was standing on and
 * printed a second shadow around it. Shadows belong to the trace layer.
 */
.scene-resident-layer img { display: block; width: auto; height: 100%; max-height: none; object-fit: contain; object-position: center bottom; }
.scene-resident-layer[data-anchor-track="placement"],
.scene-resident-layer[data-anchor-track="presence"] {
  height: auto;
  transform: none;
}
.scene-resident-layer[data-anchor-track="placement"] img,
.scene-resident-layer[data-anchor-track="presence"] img { width: 100%; height: 100%; }
.scene-presence-trace-layer,
.scene-resident-workstation-layer,
.scene-resident-trace-layer { pointer-events: none; }
.scene-resident-workstation-layer,
.scene-resident-trace-layer {
  position: absolute;
  height: auto;
  transform: none;
}
.scene-resident-workstation-layer img,
.scene-resident-trace-layer img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: none;
  object-fit: contain;
  object-position: center bottom;
}
.scene-resident-fallback {
  display: grid;
  aspect-ratio: 3 / 4;
  place-items: center;
  border: 2px dashed rgba(255, 253, 246, .88);
  border-radius: 50% 50% 42% 42%;
  background: rgba(217, 72, 111, .78);
  box-shadow: 0 7px 13px rgba(33, 29, 25, .25);
  color: #fff;
  padding: .6rem;
  font-family: var(--serif);
  font-size: 12px;
  text-align: center;
  white-space: pre-line;
}
.scene-resident-layer:nth-of-type(3n) .scene-resident-fallback { background: rgba(107, 127, 79, .82); }
.scene-presence-note {
  position: absolute;
  right: clamp(12px, 3vw, 32px);
  bottom: clamp(12px, 4vh, 34px);
  z-index: 80;
  max-width: min(28rem, calc(100% - 24px));
  border: 1.5px solid var(--line);
  border-radius: 13px;
  background: rgba(255, 253, 246, .94);
  box-shadow: 3px 3px 0 rgba(58, 42, 32, .2);
  color: var(--ink);
  padding: 9px 14px;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.scene-presence-note .eyebrow { margin: 0 0 2px; color: var(--moss); font-size: 9px; }
.scene-presence-note p:last-child { margin: 0; font-family: var(--serif); font-size: 14px; }
/* z-index comes from the guest anchor's foot line, same scale as the villagers. */
.scene-presence-token {
  position: absolute;
  display: grid;
  width: clamp(4.4rem, 10vw, 5.5rem);
  justify-items: center;
  pointer-events: none;
  transform: translate(-50%, var(--presence-token-foot-y-offset, -100%));
  transform-origin: bottom center;
}
.scene-presence-token-shadow {
  position: absolute;
  bottom: -.2rem;
  left: 50%;
  width: 70%;
  height: .52rem;
  border-radius: 50%;
  background: rgba(58, 42, 32, .28);
  filter: blur(3px);
  transform: translateX(-50%);
}
.scene-presence-token-board {
  position: relative;
  display: grid;
  width: 100%;
  min-height: 4rem;
  justify-items: center;
  border: 2px solid var(--line);
  border-radius: .7rem;
  outline: 1.5px solid var(--ink);
  background: linear-gradient(135deg, #D9A469, #B87343 48%, #965A35);
  box-shadow: inset 0 1px 0 rgba(255, 244, 210, .55), 2px 3px 0 rgba(58, 42, 32, .3);
  padding: .65rem .35rem .35rem;
  color: #FFF8EA;
  text-align: center;
  animation: scene-presence-token-breathe 3s ease-in-out infinite;
  animation-delay: calc(var(--presence-token-index, 0) * -.42s);
}
.scene-presence-token-board::before,
.scene-presence-token-board::after { position: absolute; content: ""; }
.scene-presence-token-board::before {
  top: -.62rem;
  left: 50%;
  width: 2px;
  height: .72rem;
  background: #806044;
  box-shadow: 1px 0 rgba(255, 236, 191, .45);
  transform: translateX(-50%);
}
.scene-presence-token-board::after {
  top: -.82rem;
  left: 50%;
  width: .42rem;
  height: .42rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #967252;
  box-shadow: 0 1px 0 rgba(58, 42, 32, .35);
  transform: translateX(-50%);
}
.scene-presence-token-portrait {
  width: clamp(2.8rem, 7vw, 3.5rem);
  height: clamp(2.8rem, 7vw, 3.5rem);
  border: 1.5px solid var(--line);
  border-radius: 50%;
  background: var(--honey-soft);
  box-shadow: 0 1px 0 rgba(58, 42, 32, .36);
  object-fit: cover;
}
.scene-presence-token-name {
  max-width: 100%;
  margin-top: .18rem;
  color: #FFF8EA;
  font-family: var(--serif);
  font-size: clamp(.66rem, 1.5vw, .78rem);
  line-height: 1.2;
  overflow-wrap: anywhere;
  text-shadow: 0 1px 0 rgba(58, 42, 32, .5);
}
.scene-presence-token.is-name-only .scene-presence-token-board { min-height: 2.45rem; padding-top: .72rem; }
.scene-presence-token[data-presence-kind="companion"] .scene-presence-token-board { background: linear-gradient(135deg, #D7A96A, #A96B42 48%, #7F4C32); }
@keyframes scene-presence-token-breathe {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50% { transform: translateY(-.32rem) rotate(1deg); }
}
.scene-composition-diagnostics {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 100;
  max-width: min(25rem, calc(100% - 20px));
  max-height: 42%;
  overflow: auto;
  margin: 0;
  border: 1px solid #8D3D29;
  border-radius: 9px;
  background: rgba(255, 244, 222, .95);
  color: #6F281C;
  padding: 7px 9px 7px 26px;
  font: 10px/1.45 ui-monospace, monospace;
}
.scene-composition-caption { display: flex; align-items: baseline; gap: 8px; border-top: 1px solid var(--line); background: var(--panel); padding: 8px 12px; }
.scene-composition-caption h2,
.scene-composition-caption p { margin: 0; }
.scene-composition-caption h2 { font-size: 14px; }
.scene-composition-caption p { color: var(--ink-soft); font-size: 12px; }
.composer-contract-preview { min-height: 0; overflow: auto; border: 1.5px solid var(--line); border-radius: 13px; background: var(--panel); padding: 10px 12px; }
.composer-contract-preview summary { cursor: pointer; color: var(--rose-text); font-family: var(--serif); }
.composer-contract-preview pre { overflow: auto; margin: 9px 0 0; font-size: 10px; white-space: pre-wrap; }

@media (max-width: 62rem) {
  .composer-demo-screen { display: flex; height: auto; min-height: 100%; overflow: visible; }
  body[data-scene-composer-demo="true"] #game { overflow: auto; }
  .composer-residents { margin-left: 0 !important; }
  .scene-composition { min-height: 28rem; }
}
/* The resident day keeps its scene and actions in view while this column holds
   the complete day record. min-height: 0 is what lets the grid item shrink to
   the viewport row instead of growing past it. */
.world-side { display: flex; min-height: 0; flex-direction: column; gap: 12px; overflow: auto; padding: 0 4px 4px 0; }

/* The resident record reuses the map's always-visible thin rail. On macOS,
   -webkit-appearance: none keeps this from reverting to an invisible overlay
   scrollbar while idle. */
.world-side,
.map-side { overscroll-behavior: contain; }
.world-side::-webkit-scrollbar,
.map-side::-webkit-scrollbar { width: 10px; -webkit-appearance: none; }
.world-side::-webkit-scrollbar-track,
.map-side::-webkit-scrollbar-track { background: transparent; }
.world-side::-webkit-scrollbar-thumb,
.map-side::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: 999px;
  background: var(--ink-soft);
  background-clip: content-box;
}
.world-side::-webkit-scrollbar-thumb:hover,
.map-side::-webkit-scrollbar-thumb:hover { background: var(--terra); background-clip: content-box; }
/* Chrome ignores the WebKit rules when scrollbar-color is present, so Firefox
   receives its equivalent only when those rules do not exist. */
@supports not selector(::-webkit-scrollbar) {
  .world-side,
  .map-side { scrollbar-width: thin; scrollbar-color: var(--ink-soft) transparent; }
}
.world-card h3:first-child { font-size: 15px; }
.world-row { display: flex; gap: 9px; margin-top: 6px; color: var(--ink-soft); font-size: 12.5px; line-height: 1.75; }
.world-row b { min-width: 62px; color: var(--ink); font-family: var(--serif); font-weight: 400; }
.world-event { margin-top: 8px; border: 1.5px solid var(--line); border-radius: 11px; background: rgba(252, 245, 228, .7); padding: 9px 12px; }
.world-event h3 { display: inline; font-size: 14px; }
.event-status { display: inline-flex; width: fit-content; margin: 0 0 0 7px; border: 1px solid var(--line); border-radius: 999px; background: var(--honey-soft); padding: 1px 8px; font-size: 10.5px; }
.world-event .muted { margin: 4px 0 0; font-size: 11.5px; }
.actionbar { display: flex; align-items: center; gap: 10px; border: 2px solid var(--ink); border-radius: 14px; background: var(--panel); box-shadow: 3px 3px 0 rgba(58, 42, 32, .18); padding: 11px 16px; }
.actionbar-label { margin: 0; color: var(--ink-soft); font-family: var(--serif); font-size: 14px; white-space: nowrap; }
.actionbar-buttons { display: flex; min-width: 0; flex: 1; gap: 10px; }
.actionbar-buttons > button { min-width: 0; flex: 1 1 0; padding-inline: 8px; }

/* G21 */
.quiet-screen > img { object-position: center 60%; }
.quiet-panel { position: absolute; right: 50%; bottom: 17%; z-index: 3; width: min(40rem, calc(100% - 2rem)); padding: 22px 26px; text-align: center; transform: translateX(50%); }
.quiet-panel h1 { font-size: 26px; }
.quiet-copy { color: var(--ink-soft); font-family: var(--serif); font-size: 15px; line-height: 1.9; }

/* G14V */
.visitor-screen > img { object-position: center 40%; }
.visitor-screen .scene-vignette { background: linear-gradient(180deg, rgba(58, 42, 32, .2), transparent 18%, transparent 66%, rgba(58, 42, 32, .3)); }
.visitor-banner { position: absolute; top: 74px; left: 50%; z-index: 4; border: 2px solid var(--ink); background: var(--honey-soft); box-shadow: 3px 3px 0 rgba(58, 42, 32, .25); color: var(--ink); font-family: var(--serif); font-size: 15px; transform: translateX(-50%); }
.visitor-feed { position: absolute; top: 150px; left: 26px; z-index: 3; display: flex; width: min(22.5rem, calc(100% - 52px)); flex-direction: column; gap: 10px; }
.visitor-feed-card { border: 1.5px solid var(--line); border-radius: 12px; background: rgba(255, 253, 246, .93); color: var(--ink); cursor: pointer; padding: 11px 14px; text-align: left; white-space: normal; }
.visitor-feed-card h3 { font-size: 14px; }
.visitor-feed-card p { margin: 3px 0 0; color: var(--ink-soft); font-size: 11.5px; }
.readonly-chip { display: inline-block; margin-top: 6px; border: 1px dashed var(--line); border-radius: 999px; color: var(--ink-soft); padding: 1px 8px; font-size: 10.5px; }
.visitor-invite { position: absolute; right: 26px; bottom: 96px; z-index: 3; width: min(25rem, calc(100% - 52px)); border: 2px solid var(--ink); border-radius: 16px; background: rgba(255, 253, 246, .97); box-shadow: 4px 4px 0 rgba(58, 42, 32, .25); padding: 16px 18px; }
.visitor-invite h2 { font-size: 16px; line-height: 1.7; }

/* W3 map: the picture and every marker share one strict 3:2 frame, so a
   percentage always lands on the same brush stroke at any screen width. */
.map-main { display: grid; min-height: 0; flex: 1; grid-template-columns: minmax(0, 1fr) 400px; gap: 14px; }
.map-canvas { position: relative; display: flex; min-height: 0; align-items: center; justify-content: center; overflow: hidden; border: 2px solid var(--ink); border-radius: 16px; background: var(--shell-map-desk); box-shadow: 4px 4px 0 rgba(58, 42, 32, .18); container-type: size; }
/* First line is the fallback for browsers without container queries; the second
   is the exact one — the largest 3:2 box that fits, so the picture is never
   cropped and never letterboxed inside its own frame. */
.map-frame { position: relative; width: 100%; margin: auto; aspect-ratio: 3 / 2; }
.map-frame { width: min(100cqw, calc(100cqh * 3 / 2)); height: min(100cqh, calc(100cqw * 2 / 3)); }
.map-picture { display: block; width: 100%; height: 100%; object-fit: contain; }
.map-picture-fallback { display: grid; width: 100%; height: 100%; place-items: center; padding: 18px; text-align: center; }

/* W7 daylight: the light walking across the sheet. Not the picture being
   recoloured — the picture is never touched — but a filter on the paper plus
   layers over it, painted in the order they are listed.
   `isolation` keeps those blends inside the frame; the boards and the dashed
   leader come later in the markup, so they stay above the light and are never
   dimmed by it. Every number below is also in world-shell.js, and a test
   compares the two strings character for character so they cannot drift. */
.map-frame { isolation: isolate; }
.map-daylight { position: absolute; inset: 0; pointer-events: none; }
.map-daylight-layer { position: absolute; inset: 0; }
.map-daylight-layer.is-screen { mix-blend-mode: screen; }
.map-daylight-layer.is-multiply { mix-blend-mode: multiply; }
/* No picture, no light on it: the words-only fallback keeps its plain paper. */
.map-canvas.is-wordsonly .map-daylight { display: none; }
.map-frame[data-beat="morning"] .map-picture { filter: saturate(1.02) brightness(1.02); }
.map-frame[data-beat="dusk"] .map-picture { filter: sepia(.1) saturate(1.06) brightness(.86); }
.map-frame[data-beat="night"] .map-picture { filter: saturate(.72) brightness(.62) contrast(1.04); }
.map-daylight-layer.is-morning-wash { background: radial-gradient(ellipse 85% 85% at 6% 0%, rgba(255, 238, 196, .12) 0%, rgba(255, 238, 196, 0) 100%); }
.map-daylight-layer.is-dusk-wash { background: radial-gradient(ellipse 85% 85% at 94% 100%, rgba(246, 185, 107, .26) 0%, rgba(246, 185, 107, 0) 100%); }
.map-daylight-layer.is-dusk-vignette { background: radial-gradient(ellipse 74% 74% at 50% 50%, rgba(18, 20, 31, 0) 42%, rgba(18, 20, 31, .08) 100%); }
.map-daylight-layer.is-night-tint { background: rgba(42, 46, 92, .22); }
.map-daylight-layer.is-night-pool { background: radial-gradient(ellipse 54% 54% at 50% 50%, rgba(255, 214, 150, .26) 0%, rgba(255, 214, 150, 0) 100%); }
.map-daylight-layer.is-night-vignette { background: radial-gradient(ellipse 74% 74% at 50% 50%, rgba(18, 20, 31, 0) 42%, rgba(18, 20, 31, .32) 100%); }
.map-daylight-layer.is-night-rim { background: linear-gradient(to right, rgba(18, 20, 31, .42) 0%, rgba(18, 20, 31, 0) 10%), linear-gradient(to left, rgba(18, 20, 31, .42) 0%, rgba(18, 20, 31, 0) 10%), linear-gradient(to bottom, rgba(18, 20, 31, .42) 0%, rgba(18, 20, 31, 0) 10%), linear-gradient(to top, rgba(18, 20, 31, .42) 0%, rgba(18, 20, 31, 0) 10%); }
.map-today { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 4px 0 0; }
.map-today-label { border: 1.5px solid var(--ink); border-radius: 999px; background: var(--honey-soft); padding: 2px 10px; font-family: var(--serif); font-size: 11.5px; }
.map-today-line { color: var(--ink-soft); font-size: 12px; }

.map-board { position: absolute; width: 12px; height: 12px; border: 0; background: transparent; color: var(--ink); cursor: pointer; padding: 0; transform: translate(-50%, -50%); }
/* A 44x44 hit area that leaves the drawn diamond exactly where it is. */
.map-board::before { content: ""; position: absolute; top: 50%; left: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); }
.map-board:hover, .map-board:focus-visible { z-index: 5; }
.map-board:focus-visible { outline: 3px solid var(--rose); outline-offset: 6px; }
.map-board-marker { position: absolute; inset: 0; transform: rotate(45deg); border: 2px solid #FFF8EA; border-radius: 2px; background: var(--terra); box-shadow: 0 1px 3px rgba(58, 42, 32, .5); }
.map-board.festival .map-board-marker { background: var(--moss); box-shadow: 0 0 0 4px rgba(107, 127, 79, .18); }
.map-board.quiet .map-board-marker { background: #B9AC90; }
.map-board.mine .map-board-marker { background: #8A6BB0; }
.map-board-stack { position: absolute; bottom: calc(100% + 7px); left: 50%; display: flex; flex-direction: column; align-items: center; gap: 4px; pointer-events: none; transform: translateX(-50%); }
.map-board[data-stack="below"] .map-board-stack { top: calc(100% + 7px); bottom: auto; flex-direction: column-reverse; }
/* A place with nobody and nothing on today keeps only its diamond. */
.map-board.quiet .map-board-stack { opacity: 0; }
.map-board.quiet:hover .map-board-stack,
.map-board.quiet:focus-visible .map-board-stack { opacity: 1; }
.map-board-plate { display: flex; flex-direction: column; align-items: center; gap: 1px; border: 1.5px solid var(--ink); border-radius: 10px; background: rgba(255, 253, 246, .95); box-shadow: 1px 1px 0 rgba(58, 42, 32, .25); padding: 3px 10px; }
.map-board-name { font-family: var(--serif); font-size: 12px; white-space: nowrap; }
.map-board-line { color: var(--ink-soft); font-size: 10.5px; white-space: nowrap; }
.map-board-arrival { color: var(--terra); font-size: 10px; white-space: nowrap; }
.map-board-faces { display: flex; flex-wrap: nowrap; align-items: center; gap: 3px; }
.map-board-more { border: 1.5px solid var(--ink); border-radius: 999px; background: rgba(255, 253, 246, .95); padding: 1px 6px; font-size: 10.5px; }
/* A companion is drawn at the villagers' size and line weight — never smaller,
   never fainter. The warm ring is the only difference, and it carries no word. */
/* `flex: none` on both is the rule's teeth: a crowded row may run wide, but it
   may never shrink one person's face — least of all the companion's. */
.map-face { display: inline-flex; flex: none; align-items: center; }
.map-face > img { width: 26px; height: 26px; flex: none; border: 1.5px solid var(--ink); border-radius: 50%; background: var(--paper); object-fit: cover; }
.map-face.is-nameplate { border: 1.5px solid var(--ink); border-radius: 999px; background: rgba(255, 253, 246, .95); box-shadow: 1px 1px 0 rgba(58, 42, 32, .2); padding: 3px 8px; }
.map-face.is-companion { gap: 4px; border-radius: 999px; background: rgba(255, 253, 246, .92); box-shadow: 1px 1px 0 rgba(58, 42, 32, .2); padding: 2px 8px 2px 2px; }
.map-face.is-companion > img { box-shadow: 0 0 0 3px rgba(233, 178, 98, .9), 0 0 9px rgba(233, 178, 98, .55); }
.map-face.is-companion.is-nameplate { padding: 3px 9px; box-shadow: 0 0 0 3px rgba(233, 178, 98, .9), 1px 1px 0 rgba(58, 42, 32, .2); }
.map-face-name { font-family: var(--serif); font-size: 10.5px; line-height: 1.2; white-space: nowrap; }
/* One dashed leader, drawn only for a companion, and it never moves. */
.map-route { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.map-route line { stroke: var(--terra); stroke-width: 2; stroke-dasharray: 5 5; stroke-linecap: round; vector-effect: non-scaling-stroke; }

.map-sheet { position: absolute; right: 10px; bottom: 10px; left: 10px; z-index: 6; display: grid; gap: 6px; border: 2px solid var(--ink); border-radius: 14px; background: rgba(255, 253, 246, .98); box-shadow: 3px 3px 0 rgba(58, 42, 32, .25); padding: 12px 14px; }
.map-sheet[hidden] { display: none; }
.map-sheet-name { font-family: var(--serif); font-size: 15px; }
.map-sheet-line { margin: 0; color: var(--ink-soft); font-size: 12.5px; }
.map-sheet-arrival { margin: 0; color: var(--terra); font-size: 12px; }
.map-sheet-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }

/* Without the picture there is nothing to pin to, so the boards become words. */
.map-canvas.is-wordsonly { display: block; overflow: auto; padding: 12px; container-type: normal; }
.map-canvas.is-wordsonly .map-frame { width: 100%; height: auto; aspect-ratio: auto; }
.map-canvas.is-wordsonly .map-route { display: none; }
.map-canvas.is-wordsonly .map-board { position: static; display: flex; width: auto; height: auto; align-items: center; gap: 8px; margin-bottom: 7px; text-align: left; transform: none; }
.map-canvas.is-wordsonly .map-board::before { content: none; }
.map-canvas.is-wordsonly .map-board-stack { position: static; flex-direction: row; align-items: center; gap: 8px; opacity: 1; transform: none; }
.map-canvas.is-wordsonly .map-board-marker { position: static; width: 10px; height: 10px; flex: 0 0 auto; }

.map-side { display: flex; min-height: 0; flex-direction: column; gap: 10px; overflow: auto; padding-right: 4px; }
.map-list-card { flex: 1; }
.map-list { display: grid; gap: 7px; }
.map-place-entry { display: grid; gap: 5px; }
.map-place-note { color: var(--ink-soft); font-size: 10.5px; padding-left: 7px; }
.place-button { display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; padding: 7px 11px; text-align: left; }
.place-button small { color: var(--ink-soft); }
.map-help { margin: 9px 0 0; font-size: 11px; }
.privacy-card { font-size: 12px; }

/* Only the resident day's desktop right column scrolls. The page, scene, title,
   and action row remain inside the fixed viewport shell. */
@media (min-width: 900px) {
  html:has(body[data-screen="resident"]) { height: 100%; overflow: hidden; }
  body[data-screen="resident"] { height: 100%; overflow: hidden; }
  body[data-screen="resident"] #game { position: fixed; width: 100dvw; height: 100dvh; overflow: hidden; }
  body[data-screen="resident"] .resident-screen { height: 100%; min-height: 0; overflow: hidden; }
  body[data-screen="resident"] .world-main { min-height: 0; flex: 1; align-items: stretch; }
  body[data-screen="resident"] .world-scene { min-height: 0; }
  body[data-screen="resident"] .actionbar { flex: none; }
}

/* place pages and production portraits */
.place-screen > img { object-position: center 45%; }
.place-panel { position: absolute; right: 26px; bottom: calc(32px + env(safe-area-inset-bottom)); z-index: 3; width: min(34rem, calc(100% - 52px)); max-height: calc(100% - 110px); overflow: auto; padding: 16px 18px; }
.portrait-strip { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 10px; }
.portrait-person { width: 5rem; text-align: center; }
.portrait-person .villager-portrait { width: 4rem; }
.companion-nameplate-wrap { display: grid; place-items: center; overflow: visible; border: 0; background: transparent; }
.companion-nameplate { display: inline-block; max-width: 8rem; border: 1.5px solid var(--ink); border-radius: 999px; background: var(--paper); box-shadow: 2px 2px 0 rgba(58, 42, 32, .2); padding: .45rem .7rem; font-family: var(--serif); font-size: .9rem; line-height: 1.1; overflow-wrap: anywhere; }
.portrait-person p { margin: 0; font-size: 12px; }
.shared-presence-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.shared-presence-tag { display: inline-flex; max-width: 11rem; align-items: center; gap: 5px; border: 1.5px solid var(--ink); border-radius: 999px; background: rgba(255, 253, 246, .95); box-shadow: 1px 1px 0 rgba(58, 42, 32, .2); padding: 3px 8px; color: var(--ink); font-family: var(--serif); font-size: 12px; line-height: 1.2; overflow-wrap: anywhere; }
.shared-presence-tag img { width: 22px; height: 22px; flex: 0 0 auto; border: 1px solid var(--line); border-radius: 50%; object-fit: cover; }
.shared-presence-tag[data-presence-kind="companion"] { background: var(--honey-soft); }
.shared-presence-note { margin: 5px 0 0; color: var(--ink-soft); font-size: 12px; }
.encounter-card { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 12px; border-color: var(--moss); background: var(--honey-soft); }
.encounter-card > .eyebrow { grid-column: 1 / -1; margin: 0; }
.encounter-card .villager-portrait { width: 5rem; margin: 0; }
.encounter-copy h3 { margin: 0 0 3px; }
.encounter-copy p { margin: 0; font-family: var(--serif); font-size: 13px; line-height: 1.75; }
/* 回應過之後那張卡不是句點：這一行把「今天遇見完了」和「話還能再說」分開。 */
.encounter-copy .encounter-again-note { margin: 9px 0 8px; font-size: 11.5px; }
.equal-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 10px; }
.equal-choices > button { width: 100%; min-width: 0; padding-inline: 8px; }
.garden-harvest-actions { display: grid; gap: 6px; margin-top: 14px; }
.garden-harvest-actions > button { width: fit-content; }
.garden-harvest-actions > p { margin: 0; font-size: 11.5px; }
.garden-gift-panel { border-top: 1.5px solid var(--line); margin-top: 18px; padding-top: 14px; }
.garden-gift-panel > h4,
.garden-gift-panel > p { margin: 0; }
.garden-gift-panel > p { margin-top: 5px; }
.garden-recovery { border: 1.5px dashed var(--terra); border-radius: 12px; background: var(--honey-soft); margin-top: 14px; padding: 12px; }
.garden-recovery > h4,
.garden-recovery > p { margin: 0; }
.garden-recovery > p,
.garden-recovery > button { margin-top: 8px; }
.place-verbs { border-top: 1.5px solid var(--line); padding-top: 10px; }
.place-verbs h3 { font-size: 14px; }
.feedback-card { border-style: dashed; background: rgba(107, 127, 79, .1); }

/* 02A authored dialogue */
.dialogue-screen > img { object-position: center 42%; }
.dialogue-layout { position: absolute; right: 4vw; bottom: 5vh; z-index: 3; display: grid; width: min(56rem, calc(100% - 8vw)); grid-template-columns: 14rem minmax(0, 1fr); gap: 20px; padding: 24px; }
.dialogue-person { align-self: center; text-align: center; }
.dialogue-person .villager-portrait { width: 9rem; }
.dialogue-person h2 { margin: 6px 0; }
.dialogue-person .chip { margin-inline: auto; }
.dialogue-exchange { display: flex; min-width: 0; flex-direction: column; justify-content: center; }
.dialogue-exchange h1 { font-size: 24px; }
.dialogue-line { min-height: 5rem; border-left: 3px solid var(--moss); background: rgba(252, 235, 198, .45); padding: 13px 16px; font-family: var(--serif); font-size: 16px; line-height: 1.9; }
.dialogue-leave { align-self: flex-start; margin-top: 13px; }
.dialogue-note { margin: 9px 0 0; font-size: 11px; }
.response-boundary { margin-bottom: 8px; font-size: 11px; }
/* Five response states, but silence is not a button — only four render. A fixed
   five-column track squeezed each one below the width of 換個方式, wrapping it
   and lifting the whole row to three line-heights. auto-fit follows the real
   button count, and the 5rem floor is the width that fits the longest label, so
   nowrap can never silently grow the row again. */
.five-response-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr)); gap: 6px; }
.five-response-choices .choice-button { min-width: 0; padding-inline: 7px; white-space: nowrap; }

/* E4 return summary: a single removable page the village clipped for you. It is
   the first card of today's right column, in the flow with everything else —
   floating it over the column covered 「今天可以——」 and left it hanging in
   mid-air whenever it held only a line or two. */
.return-summary { position: relative; border-radius: 16px 4px 16px 16px; }
.return-summary::before { position: absolute; top: 0; left: 18px; width: 34px; height: 8px; border-radius: 0 0 8px 8px; background: var(--rose); content: ""; }
.return-summary-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.return-summary-head h2 { margin-bottom: 10px; font-size: 20px; }
.return-summary-list { display: grid; gap: 8px; }
.return-summary-card { border-left: 3px solid var(--line); background: var(--paper); padding: 9px 11px; }
.return-summary-card.main { border-left-color: var(--rose); }
.return-summary-card.pending_invitation { border-left-color: var(--moss); }
.return-summary-card p { margin: 0; font-size: 13px; }
.return-summary-card .eyebrow { margin-bottom: 2px; font-size: 9px; }
.return-summary-folded { margin: 2px 0 0; color: var(--ink-soft); font-family: var(--serif); font-size: 12px; text-align: center; }

/* G13M hut */
.hut-main { display: grid; min-height: 0; flex: 1; grid-template-columns: minmax(0, 1fr) 400px; gap: 14px; }
.hut-scene > img { object-position: center 38%; }
.hut-side { display: flex; min-height: 0; flex-direction: column; gap: 13px; }
.hut-side .card { font-family: var(--serif); font-size: 14px; line-height: 1.8; }
.hut-hint { display: grid; flex: 1; place-items: center; background: rgba(252, 245, 228, .7); color: var(--ink-soft); text-align: center; }
.hut-leave { width: 100%; }
.hut-action-panel { flex: 1; min-height: 0; overflow: auto; }
.hut-action-panel h2 { font-size: 18px; }
.memory-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; margin: 10px 0; }
.memory-grid > button { min-width: 0; padding-inline: 7px; font-size: 12px; }
/* Letter recipients are chosen from the village's own buttons, at body size, so
   the chosen name is as readable as the letter being written. */
.recipient-choices { display: flex; flex-wrap: wrap; gap: 8px; }
.recipient-choice { min-height: 40px; padding: 7px 14px; font-size: 14px; }
.hut-list,
.chronicle-list { color: var(--ink-soft); font-size: 12px; line-height: 1.7; }
/* 編年史一天一節：日戳在節標題，拍別在每一行的短籤，句子只說自己的事。
   間距照版面鐵則由容器負責——節與節、節標題與條目都不得貼死（≥12px）。 */
.chronicle-list { display: grid; gap: 7px; margin: 0; padding-left: 0; list-style: none; }
.chronicle-day-group + .chronicle-day-group { margin-top: 16px; }
.chronicle-day-group > * + * { margin-top: 12px; }
.chronicle-day-group h3 { margin: 0; color: var(--rose-text); font-size: 13px; letter-spacing: .08em; }
/* 年份自己一行、月份是紙頁上的一道分隔線，日期標題因此每一則都長得一樣。
   手帳基調：不用現代分頁元件，翻頁與跳月都寫成村公所在翻找。 */
.chronicle-month-group + .chronicle-month-group { margin-top: 24px; }
.chronicle-month-group > * + .chronicle-day-group { margin-top: 12px; }
.chronicle-year-line { margin: 0 0 9px; color: var(--ink); font-family: var(--serif); font-size: 15px; letter-spacing: .2em; }
.chronicle-month-line { display: flex; align-items: center; gap: 9px; margin: 0 0 4px; color: var(--moss); font-family: var(--serif); font-size: 12px; letter-spacing: .16em; }
.chronicle-month-line::after { flex: 1; border-top: 1px dashed var(--line); content: ""; }
.chronicle-month-jump { margin-bottom: 14px; }
.chronicle-month-jump summary { cursor: pointer; color: var(--rose-text); font-family: var(--serif); font-size: 12px; letter-spacing: .1em; }
.chronicle-month-choices { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.chronicle-month-choice { min-height: 30px; border: 1px solid var(--line); border-radius: 999px; background: var(--paper); color: var(--ink-soft); cursor: pointer; padding: 4px 12px; font-family: var(--serif); font-size: 11px; }
.chronicle-month-choice:hover { border-color: var(--moss); color: var(--moss); }
.chronicle-month-search { border-style: dashed; color: var(--moss); }
.chronicle-entry { display: flex; align-items: baseline; gap: 8px; }
.chronicle-beat { flex: 0 0 auto; border: 1px solid var(--moss); border-radius: 999px; color: var(--moss); padding: 1px 7px; font-family: var(--serif); font-size: 10px; }
.chronicle-entry-text { min-width: 0; }
.hut-action-icon { display: grid; width: 34px; height: 34px; place-items: center; overflow: hidden; border: 1px solid var(--line); border-radius: 8px; font-size: 9px; }
.hut-action-icon img { width: 100%; height: 100%; object-fit: cover; }
.hut-action-icon .image-fallback { min-height: 0; padding: 2px; }
.hut-dock { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; border: 2px solid var(--ink); border-radius: 14px; background: var(--panel); box-shadow: 3px 3px 0 rgba(58, 42, 32, .18); padding: 11px 15px; }
.hut-return-note { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: .35rem .8rem; width: min(42rem, 100%); margin-top: .8rem; border: 1.5px solid var(--moss); border-radius: 12px; background: var(--honey-soft); padding: .75rem .9rem; }
.hut-return-note .eyebrow { margin: 0; color: var(--moss); }
.hut-return-note-text { grid-column: 1 / 2; margin: 0; white-space: pre-wrap; }
.hut-return-note > button { grid-column: 2; grid-row: 1 / 3; }
.hut-recipe-card { margin-top: .75rem; border: 1px solid var(--line); border-radius: 10px; background: #fffdf6; padding: .8rem; }
.hut-recipe-card h3 { margin: 0 0 .3rem; }
.hut-recipe-card p { margin: .35rem 0; }
.hut-cooking-gifts { display: grid; gap: .45rem; margin-top: .8rem; }
.hut-cooking-gifts > button { text-align: left; }
.dock-button { display: grid; min-height: 78px; min-width: 0; place-items: center; gap: 2px; border-color: var(--line); padding: 7px; white-space: normal; }
.dock-button.active { border-color: var(--rose); background: var(--honey-soft); }
.dock-button img { width: 34px; height: 34px; border: 1px solid var(--line); border-radius: 8px; object-fit: cover; }
.dock-button h3 { margin: 0; font-size: 14px; }
.dock-button p { margin: 0; font-family: var(--sans); font-size: 10px; }
.day-note { min-height: 1.4rem; margin: 0; color: var(--moss); font-size: 12px; text-align: center; }

/* H5 partner diary: the engine supplies the day and projection; this only lays the public facts into a book. */
.partner-diary-screen { overflow: auto; background: var(--paper); padding: 6.6rem clamp(1rem, 5vw, 5rem) 2rem; }
.partner-diary-head { width: min(70rem, 100%); margin: 0 auto 1rem; }
.partner-diary-eyebrow { margin-bottom: .2rem; color: var(--rose-text); letter-spacing: .46em; }
.partner-diary-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: .65rem; }
.partner-diary-title-row h1 { margin: 0 .25rem 0 0; font-size: clamp(1.55rem, 3vw, 2rem); }
.partner-diary-title-row .villager-portrait { width: 44px; margin: 0; flex: 0 0 44px; }
.partner-diary-portrait-action { margin: .6rem 0 0; }
.partner-diary-avatar { display: grid; width: 44px; height: 44px; place-items: center; border: 2px solid var(--ink); border-radius: 50%; background: var(--honey-soft); color: var(--ink-soft); font-family: var(--serif); font-size: 13px; }
.partner-diary-chip { margin: 0; border: 1px solid var(--ink); border-radius: 999px; background: var(--panel); padding: .18rem .7rem; font-family: var(--serif); font-size: .78rem; }
.partner-diary-chip.weather { border-color: var(--line); color: var(--ink-soft); }
.partner-diary-quote { margin: 0 0 0 auto; color: var(--ink-soft); font-family: var(--serif); font-size: .88rem; }
.partner-diary-card { width: min(70rem, 100%); margin: 0 auto; border: 2px solid var(--ink); border-radius: 16px; background: var(--panel); box-shadow: 5px 6px 0 rgba(58, 42, 32, .16); padding: clamp(.75rem, 2vw, 1.4rem); }
.partner-diary-book { position: relative; display: grid; grid-template-columns: 1fr 1fr; min-height: 32rem; overflow: hidden; border: 2px solid var(--ink); border-radius: 10px 14px 14px 10px; background: #fffdf6; box-shadow: 0 10px 16px rgba(58, 42, 32, .18); }
.partner-diary-book::before { position: absolute; top: 0; bottom: 0; left: 50%; z-index: 2; width: 28px; transform: translateX(-50%); background: linear-gradient(90deg, transparent, rgba(58,42,32,.15) 50%, transparent); content: ""; pointer-events: none; }
.partner-diary-page { position: relative; min-width: 0; padding: 1.8rem clamp(1.2rem, 3.2vw, 2.3rem) 3.9rem; }
.partner-diary-left { background: #f8f1e1; }
.partner-diary-right { border-left: 2px dashed rgba(58, 42, 32, .35); }
.partner-diary-date { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; border-bottom: 1px solid var(--line); }
.partner-diary-date p { margin: 0 0 .55rem; font-size: .78rem; }
.partner-diary-date-day { color: var(--ink); font-family: var(--serif); font-size: 1.05rem !important; }
.partner-diary-section-title { margin: .85rem 0 .3rem; color: var(--ink-soft); font-family: var(--serif); font-size: .72rem; letter-spacing: .32em; }
.partner-diary-facts { display: grid; margin: 0; padding: 0; list-style: none; }
.partner-diary-facts li { display: grid; grid-template-columns: 28px 1fr; align-items: center; gap: .55rem; border-bottom: 1px dotted var(--line); padding: .42rem 0; }
.partner-diary-facts p, .partner-diary-extra-facts p { margin: 0; font-size: .82rem; }
.partner-diary-beat { display: grid; width: 27px; height: 27px; place-items: center; border: 1px solid var(--moss); border-radius: 50%; color: var(--moss); font-family: var(--serif); font-size: .75rem; }
.partner-diary-extra-facts { margin-top: .7rem; border-top: 1px dotted var(--line); }
.partner-diary-player-facts p:not(.partner-diary-section-title) { color: var(--rose-text); }
.partner-diary-margin-note { position: absolute; right: clamp(1.2rem, 3.2vw, 2.3rem); bottom: 1.8rem; left: clamp(1.2rem, 3.2vw, 2.3rem); margin: 0; border-top: 1px solid var(--line); padding-top: .5rem; color: var(--ink-soft); font-family: var(--serif); font-size: .76rem; }
.partner-diary-written-title { color: var(--rose-text); }
.partner-diary-hand { margin: 1.1rem 0 0; color: #43406b; font-family: "ChenYuluoyan", "Kaiti TC", serif; font-size: clamp(1.28rem, 2.3vw, 1.55rem); line-height: 2; white-space: pre-line; }
.partner-diary-awaiting { display: grid; min-height: 12rem; place-items: center; margin: 1.3rem 0; border: 1.5px dashed var(--line); border-radius: 10px; color: var(--ink-soft); padding: 1rem; text-align: center; }
.partner-diary-seal { position: absolute; right: clamp(1.2rem, 3.2vw, 2.3rem); bottom: 3.2rem; display: grid; width: 44px; height: 44px; place-items: center; border: 2px solid #c0392b; border-radius: 6px; color: #c0392b; font-family: "ChenYuluoyan", "Kaiti TC", serif; font-size: 1rem; transform: rotate(-4deg); }
.partner-diary-ribbon { position: absolute; top: 0; right: 2.2rem; width: 18px; height: 76px; background: var(--terra); clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 84%, 0 100%); }
.partner-diary-page-number { position: absolute; bottom: .7rem; margin: 0; color: var(--ink-soft); font-family: var(--serif); font-size: .7rem; letter-spacing: .14em; }
.partner-diary-left .partner-diary-page-number { left: clamp(1.2rem, 3.2vw, 2.3rem); }
.partner-diary-right .partner-diary-page-number { right: clamp(1.2rem, 3.2vw, 2.3rem); }
.partner-diary-turns { display: flex; flex-wrap: wrap; align-items: center; gap: .65rem; margin-top: 1rem; }
.partner-diary-reply-hint { margin: 0; color: var(--ink-soft); font-size: .8rem; }
.partner-diary-reply-form { display: flex; gap: .65rem; margin-top: 1.35rem; border: 1px solid var(--line); border-radius: 12px; background: #fffdf6; box-shadow: 0 2px 0 rgba(58, 42, 32, .08); padding: .75rem; }
.partner-diary-reply-form input { min-width: 0; flex: 1; border: 1.5px solid var(--ink); border-radius: 10px; background: #fffdf6; padding: .65rem .8rem; }
.partner-diary-reply-receipt { color: var(--rose-text); }
.partner-diary-icon { color: var(--rose-text); font-family: var(--serif); font-size: .72rem; }

/* G5 mailbox v2: the final owner-approved F layout. */
.mailbox-screen { gap: 0; overflow: auto; background: var(--paper); padding: 6.6rem clamp(1rem, 5vw, 4.4rem) 2rem; }
.mailbox-head { width: min(70rem, 100%); margin: 0 auto 1rem; }
.mailbox-head .eyebrow { margin-bottom: .35rem; font-size: 13px; letter-spacing: .46em; }
.mailbox-title-row { display: flex; align-items: center; gap: .65rem; flex-wrap: wrap; }
.mailbox-title-row h1 { margin: 0 .25rem 0 0; font-size: clamp(1.55rem, 3vw, 2rem); }
.mailbox-title-row .chip { border-color: var(--ink); background: var(--panel); color: var(--ink); padding: .18rem .8rem; font-size: .82rem; white-space: nowrap; }
.mailbox-title-row .chip.soft { border-width: 1.5px; border-color: var(--line); color: var(--ink-soft); }
.mailbox-layout.card { display: grid; width: min(70rem, 100%); min-height: 30rem; grid-template-columns: minmax(19rem, .82fr) 1.18fr; margin: 0 auto; border-radius: 16px; box-shadow: 5px 6px 0 rgba(58, 42, 32, .16); padding: 0; }
.mailbox-column { position: relative; min-width: 0; padding: 1.9rem clamp(1.2rem, 3vw, 2.2rem) 3.4rem; }
.mailbox-list-column { overflow: auto; border-right: 1px solid var(--line); }
.mailbox-list-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; border-bottom: 1px solid var(--line); padding-bottom: .55rem; }
.mailbox-list-title { font-family: var(--serif); font-size: 1.05rem; }
.mailbox-list-summary { color: var(--ink-soft); font-family: var(--serif); font-size: .78rem; white-space: nowrap; }
.mail-rows { margin: .4rem 0 0; padding: 0; list-style: none; }
.mail-row { border-bottom: 1px dotted var(--line); }
.mail-item { display: grid; width: 100%; grid-template-columns: 30px minmax(0, 1fr); align-items: center; column-gap: .6rem; border: 0; background: transparent; color: var(--ink); cursor: pointer; padding: .6rem 0; font: inherit; text-align: left; }
.mail-item:focus-visible { outline: 3px solid var(--rose); outline-offset: 2px; }
.mail-who { display: grid; width: 29px; height: 29px; place-items: center; overflow: hidden; border: 1px solid var(--moss); border-radius: 50%; color: var(--moss); font-size: .7rem; white-space: nowrap; }
.mail-who.villager-portrait { width: 29px; margin: 0; border-width: 1px; border-color: var(--moss); background: transparent; }
.mail-player-portrait { border-color: var(--rose); color: var(--rose-text); font-family: var(--serif); }
.mail-copy { min-width: 0; }
.mail-name-row { display: flex; align-items: baseline; gap: .55rem; white-space: nowrap; }
.mail-person-name { font-family: var(--serif); font-size: .95rem; font-weight: 700; letter-spacing: .04em; white-space: nowrap; }
.mail-meta { color: var(--ink-soft); font-family: var(--serif); font-size: .74rem; white-space: nowrap; }
.mail-subject { margin: .15rem 0 0; overflow: hidden; color: var(--ink); font-family: var(--serif); font-size: .85rem; text-overflow: ellipsis; white-space: nowrap; }
.mail-row.mine .mail-item { grid-template-columns: minmax(0, 1fr) 30px; }
.mail-row.mine .mail-who { grid-column: 2; grid-row: 1; }
.mail-row.mine .mail-copy { grid-column: 1; grid-row: 1; }
.mail-row.mine .mail-name-row { justify-content: flex-end; }
.mail-row.mine .mail-person-name,
.mail-row.mine .mail-subject { color: var(--rose-text); }
.mail-row.mine .mail-subject { text-align: right; }
.mailbox-foot-note { position: absolute; right: clamp(1.2rem, 3vw, 2.2rem); bottom: 1.4rem; left: clamp(1.2rem, 3vw, 2.2rem); margin: 0; border-top: 1px solid var(--line); padding-top: .5rem; color: var(--ink-soft); font-family: var(--serif); font-size: .76rem; }
.mailbox-open-column { display: flex; align-items: stretch; background: radial-gradient(ellipse at 70% 12%, rgba(228, 211, 176, .25), transparent 55%); }
.open-letter { position: relative; display: flex; flex: 1; max-width: 44rem; flex-direction: column; margin: .4rem .3rem 1rem; transform: rotate(-.45deg); border: 1px solid var(--line); border-radius: 5px; background: var(--panel); box-shadow: 0 5px 14px rgba(58, 42, 32, .14); padding: 1.7rem 1.6rem; }
.open-letter::before { position: absolute; top: -6px; right: -1px; left: -1px; height: 7px; background: linear-gradient(135deg, var(--panel) 6px, transparent 6.5px) 0 0 / 13px 8px repeat-x; content: ""; }
.open-letter-eyebrow { margin: 0 0 1rem; color: var(--rose-text); font-family: var(--serif); font-size: .72rem; letter-spacing: .32em; }
.letter-title { margin: 0 0 1.2rem; font-size: 1.5rem; font-weight: 700; letter-spacing: .03em; }
.mailbox-hand { min-height: 9rem; margin: 0; color: #43406b; font-family: "ChenYuluoyan", "Kaiti TC", "DFKai-SB", serif; font-size: clamp(1.25rem, 2.2vw, 1.5rem); line-height: 2; white-space: pre-line; }
.letter-signature { margin: auto 0 0; padding-top: 1.4rem; color: var(--ink-soft); font-family: var(--serif); letter-spacing: .2em; text-align: right; }
.mailbox-letter-actions { margin-top: 1rem; }
.mailbox-seal-row { display: flex; justify-content: flex-end; margin-top: 1rem; }
.mailbox-seal { display: grid; width: 52px; height: 52px; place-items: center; transform: rotate(-4deg); border: 2px solid #c0392b; border-radius: 6px; background: transparent; color: #c0392b; cursor: pointer; padding: 0; font-family: "ChenYuluoyan", "Kaiti TC", "DFKai-SB", serif; font-size: .95rem; line-height: 1.2; text-align: center; white-space: pre-line; }
.open-letter-foot { margin: .75rem 0 0; color: var(--ink-soft); font-family: var(--serif); font-size: .7rem; letter-spacing: .14em; text-align: right; }
.attachment-note { width: fit-content; border: 1px dashed var(--moss); border-radius: 9px; background: rgba(107, 127, 79, .1); color: var(--moss); padding: 6px 10px; font-size: 12px; }

.handbook-panel { position: absolute; top: 50%; right: 5vw; width: min(34rem, calc(100% - 3rem)); max-height: calc(100% - 8rem); overflow: auto; transform: translateY(-50%); }
.handbook-tabs { display: flex; gap: 8px; margin: 12px 0 14px; }

/* ---------------------------------------------------------------------------
   版面鐵則・卡與卡不得貼死（PANEL STACK SPACING ANCHOR）
   來源：owner 連續回報三次同一類問題——手帳相鄰卡貼死、種房「相遇時刻」與
   「菜圃與種子」零間隙、村口回村表單的輸入框與送出鈕零間隙。逐卡補 margin
   每次都會漏掉下一張新卡，所以間距改由**容器**統一負責：面板／表單容器內
   任意兩個相鄰的區塊，一律至少留 12px。新增卡片自動繼承，不必再記得補。
   新增一種堆疊容器時，把它的選擇器加進這一組，不要回頭在單張卡上加 margin。
   結構性檢查：packages/versefolk-app/test/web-game.test.js
   「keeps adjacent panel and form blocks visually separated」。
   --------------------------------------------------------------------------- */
.handbook-panel > * + .card,
.handbook-panel > * + section,
.place-panel > * + .card,
.place-panel > * + section,
.place-panel > * + .actions,
.hut-action-panel > * + .card,
.hut-action-panel > * + section,
.hut-action-panel > * + .memory-grid,
.hut-action-panel > * + .recipient-choices,
.hut-action-panel > * + textarea,
.hut-action-panel > * + button,
.open-letter > * + .attachment-note,
.village-return-card > * + input,
.village-return-card > * + textarea,
.village-return-card > * + button { margin-top: 12px; }
/* The mature garden places the harvest action directly after the bordered
   tending choices. Keep every adjacent pair of framed garden controls on the
   same 12px panel-stack rhythm. */
.garden-panel > :is(.equal-choices, button) + :is(.equal-choices, button) { margin-top: 12px; }
/* A control row never touches the panel it reveals. */
:where(.actions, .handbook-tabs, .landing-actions, .partner-diary-turns) + :where(.card, form.card, .floating-panel) { margin-top: 14px; }
.handbook-harvest { margin-top: 0; }
.harvest-page { min-height: 12rem; border: 1.5px solid var(--line); border-radius: 7px 14px 14px 7px; background: linear-gradient(90deg, #f6eddb 0 4%, #fffdf6 4%); box-shadow: inset 12px 0 14px rgba(58, 42, 32, .05); padding: 1.15rem 1.3rem 1.2rem 1.7rem; }
.harvest-page .eyebrow { color: var(--rose-text); }
.harvest-summary { min-height: 4.5rem; color: var(--ink-soft); font-family: var(--serif); line-height: 1.9; }
.harvest-date { margin: .7rem 0 0; color: var(--moss); font-size: 12px; text-align: right; }
.harvest-pager { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px; margin-top: 10px; }
.harvest-pager p { margin: 0; font-size: 12px; text-align: center; }
.festival-badge { width: fit-content; margin: .3rem 0 0; border: 1px solid var(--terra); border-radius: 999px; background: #fff7dc; color: var(--rose-text); padding: .16rem .65rem; font-family: var(--serif); font-size: .82rem; }
.festival-atmosphere { margin: .35rem 0 0; color: var(--ink-soft); font-family: var(--serif); font-size: .88rem; }
.festival-folklore-note { border-left: 3px solid var(--terra); background: rgba(252, 235, 198, .58); color: var(--ink-soft); padding: .55rem .7rem; }
.festival-ritual { margin-top: .8rem; border-color: var(--terra); background: rgba(255, 247, 220, .9); }
.festival-scene-marker { position: absolute; right: clamp(1rem, 4vw, 3rem); bottom: 1.2rem; z-index: 4; max-width: min(30rem, calc(100% - 2rem)); border: 1px solid rgba(255, 248, 234, .9); border-radius: 999px; background: rgba(48, 35, 29, .7); color: #fff8ea; padding: .35rem .8rem; font-family: var(--serif); font-size: .82rem; text-shadow: 0 1px 2px #000; }
.festival-book-page { margin-top: .8rem; border: 1px dashed var(--line); border-radius: 10px; background: #fffdf6; padding: .8rem .9rem; }
.festival-book-page h3 { color: var(--rose-text); }
.festival-book-list { display: grid; gap: .35rem; margin: .5rem 0 0; padding: 0; list-style: none; }
.festival-book-empty { color: var(--ink-soft); font-family: var(--serif); }
.festival-book-filled { color: var(--ink); }
.festival-completion { margin: .65rem 0 0; color: var(--moss); font-family: var(--serif); }
.errand-card { border-style: dashed; border-color: var(--terra); background: rgba(252, 235, 198, .5); }
.errand-card.compact { margin-top: 8px; padding: 9px 10px; }
.errand-card.compact .eyebrow { margin-bottom: 2px; font-size: 9px; }
.errand-card.compact h3 { font-size: 13px; }
.errand-card.compact p { margin-bottom: 5px; font-size: 12px; }
.errand-action-card { border-color: var(--moss); background: rgba(252, 235, 198, .7); }
.confirmation-list { display: grid; gap: 8px; margin-top: 12px; }
.check-row { display: flex; align-items: flex-start; gap: 8px; }
.check-row input { width: auto; margin-top: 6px; }
.list-plain { margin: 0; padding: 0; list-style: none; }
.list-plain li + li { margin-top: 6px; border-top: 1px solid var(--line); padding-top: 6px; }
/* Hut action feedback must leave the world-date chips at the upper left clear. */
.gentle-warning { position: fixed; top: calc(76px + env(safe-area-inset-top)); right: clamp(1rem, 3vw, 2rem); z-index: 15; max-width: min(28rem, calc(100% - 2rem)); border: 1.5px solid var(--rose); border-radius: 999px; background: var(--panel); color: var(--rose-text); padding: 6px 14px; }

/* Safari/importmap/runtime fallback */
.fallback-screen { display: grid; place-items: center; background: linear-gradient(var(--shell-veil-soft), var(--shell-veil-strong)), url("/assets/scene-composition/empty-base/place_chronicle_hall/noon.webp") center 35% / cover; }
/* The one line the page can still say when it could not open: the hour the
   village is in. It only appears once the beat is known. */
.fallback-beat-line { margin: .6rem 0 0; color: var(--ink-soft); font-family: var(--serif); font-size: 13.5px; }
.fallback-card { width: min(36rem, calc(100% - 2rem)); border: 2px solid var(--ink); border-radius: 18px; background: rgba(255, 253, 246, .97); box-shadow: 5px 5px 0 rgba(58, 42, 32, .24); padding: clamp(1.4rem, 4vw, 2rem); }
.fallback-card h1 { font-size: clamp(1.75rem, 4vw, 2.4rem); }
/* The first thing a visitor sees while the village is still opening. It used
   to be a white page; now it is the same paper, with the hour written on it. */
.loading-screen { display: grid; place-items: center; }
.loading-card { width: min(30rem, calc(100% - 2rem)); border: 2px solid var(--ink); border-radius: 18px; background: var(--panel); box-shadow: 5px 5px 0 rgba(58, 42, 32, .2); padding: clamp(1.3rem, 4vw, 1.9rem); text-align: center; }
.loading-card h1 { margin: .2rem 0 .4rem; font-size: clamp(1.3rem, 3.4vw, 1.7rem); }
.loading-line { margin: 0; color: var(--ink-soft); font-family: var(--serif); font-size: 14px; }
.fallback-copy { color: var(--ink-soft); line-height: 1.8; }
.fallback-next-step { margin: 1rem 0 0; border: 1.5px dashed var(--line); border-radius: 11px; background: var(--paper); color: var(--rose-text); padding: 9px 12px; font-size: 12px; overflow-wrap: anywhere; }
.storage-notice { position: fixed; right: 1rem; bottom: 1rem; z-index: 35; max-width: calc(100% - 2rem); border: 1.5px solid var(--ink); border-radius: 999px; background: var(--honey-soft); box-shadow: 2px 2px 0 rgba(58, 42, 32, .2); padding: 6px 14px; color: var(--ink-soft); font-size: 12px; }

.sr-only { position: absolute !important; width: 1px !important; height: 1px !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; }
[hidden] { display: none !important; }

@keyframes page-arrive {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 899px) {
  .site-header { padding: 12px 14px; }
  .five-response-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .brandmark { width: 32px; height: 32px; font-size: 17px; }
  .brand { font-size: 18px; }
  .brand small { display: none; }
  .main-nav { max-width: 62vw; overflow-x: auto; }
  .nav-button { padding: 5px 7px; font-size: 12px; }
  .audio-toggle { padding: 5px 8px; font-size: 11px; }
  .app-version { margin-left: 4px; font-size: 9px; }
  .app-update-notice { top: calc(100% - 4px); right: 14px; max-width: calc(100vw - 28px); }
  .audio-mix-toggle { margin-left: 4px; padding: 3px 6px; font-size: 10px; }
  .audio-status { right: 10px; bottom: 10px; left: 10px; max-width: none; border-radius: 12px; text-align: center; }
  body:not([data-screen="guest"]) .audio-status { bottom: 9rem; }
  .screen { padding: 60px 14px 12px; }

  /* G14m: scene above, copy below */
  .landing-screen { overflow: hidden; background: var(--paper); }
  .landing-screen > img,
  .landing-screen > .image-fallback:first-child,
  .landing-screen > .scene-composition-background { bottom: auto; height: 42.5%; object-position: center 28%; }
  .landing-screen .scene-vignette { bottom: auto; height: 42.5%; background: linear-gradient(180deg, rgba(58, 42, 32, .18), transparent 30%, rgba(58, 42, 32, .4)); }
  .landing-hero { top: 42.5%; right: 0; bottom: 0; left: 0; width: auto; overflow: auto; background: var(--paper); padding: 18px; }
  .landing-hero h1 { margin: 0; color: var(--ink); font-size: clamp(1.65rem, 7.4vw, 1.9rem); text-shadow: none; }
  .landing-subtitle { margin: 8px 0 0; color: var(--ink-soft); font-size: 15px; line-height: 1.8; text-shadow: none; white-space: normal; }
  .landing-actions { display: grid; gap: 0; margin-top: 8px; }
  .landing-actions button { width: 100%; min-height: 48px; margin-top: 10px; font-size: 16px; }
  .landing-resume-actions { margin-top: 10px; }
  .landing-resume-button { width: 100%; min-height: 44px; }
  .landing-note { width: 100%; margin-top: 12px; background: transparent; color: var(--ink-soft); padding: 0; font-size: 12px; line-height: 1.7; text-align: center; }
  .landing-screen > .scene-footnote { display: none; }

  .routes-screen { overflow: auto; }
  .routes-content { display: block; width: 100%; height: auto; padding: 66px 14px 18px; }
  .routes-intro h1 { font-size: 22px; }
  .companion-route-card { margin-top: 1.1rem; }

  .application-screen,
  .leave-screen { overflow: auto; background: var(--paper); }
  .application-screen .scene-vignette,
  .leave-screen .scene-vignette { background: rgba(251, 244, 230, .9); }
  .application-card,
  .status-screen .floating-panel,
  .leave-screen .floating-panel { position: relative; top: auto; right: auto; width: auto; max-height: none; margin: 60px 14px 16px; overflow: visible; transform: none; border: 0; border-radius: 0; background: transparent; box-shadow: none; padding: 0; }
  .application-card h1 { font-size: 21px; }

  .floating-layout { inset: 62px 14px 14px; display: block; width: auto; }
  .hearth-question { max-height: 100%; overflow: auto; }
  .hearth-companion { display: none; }
  .action-row { grid-template-columns: 1fr; }
  .portrait-panel { inset: 60px 14px 14px; }
  .portrait-grid,
  .portrait-tools { grid-template-columns: 1fr; }
  .portrait-tools { padding-bottom: 1rem; }

  .trial-layout { inset: 62px 14px 14px; display: block; overflow: auto; }
  .certificate-card { padding: 20px; }
  .certificate-body { grid-template-columns: 7rem 1fr; gap: 14px; }
  .certificate-rights { grid-column: 1 / -1; }
  .trial-task { margin-top: 12px; }

  .resident-screen,
  .map-screen,
  .hut-screen,
  .mailbox-screen { overflow: auto; padding-bottom: 9.5rem; }
  .world-head { flex: none; gap: 5px 8px; }
  .world-head .eyebrow { display: none; }
  .world-head h1 { font-size: 21px; }
  .world-head .chip { font-size: 10.5px; padding: 3px 9px; }
  /* On narrow screens the date chips wrap, so center this below their block. */
  .gentle-warning { top: calc(10rem + env(safe-area-inset-top)); right: auto; left: 50%; max-width: calc(100% - 2rem); transform: translateX(-50%); text-align: center; }
  .world-main,
  .map-main,
  .hut-main { display: flex; min-height: auto; flex: none; flex-direction: column; }
  .world-scene,
  .hut-scene { height: 180px; min-height: 180px; flex: none; }
  /* The map earns its own height: a full 3:2 picture, nothing cropped away.
     Width decides height here — a container measured by size would collapse to
     nothing once the height stops being fixed. */
  .map-canvas { height: auto; min-height: 0; flex: none; container-type: inline-size; }
  .map-frame { width: 100%; height: auto; aspect-ratio: 3 / 2; }
  .map-frame { width: 100cqw; height: calc(100cqw * 2 / 3); }
  .world-side,
  .map-side,
  .hut-side { overflow: visible; }
  .actionbar { position: absolute; right: 14px; bottom: max(10px, env(safe-area-inset-bottom)); left: 14px; z-index: 8; flex-direction: column; align-items: stretch; gap: 6px; padding: 8px; }
  .actionbar-label { display: none; }
  .actionbar-buttons { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
  .actionbar-buttons > button { min-height: 42px; font-size: 13px; }

  .quiet-panel { bottom: 14%; padding: 18px; }
  .quiet-panel h1 { font-size: 21px; }
  .quiet-copy { font-size: 12px; }
  .quiet-panel .actionbar-buttons { grid-template-columns: 1fr; }
  .quiet-screen > .scene-footnote { display: none; }

  .visitor-screen { overflow: auto; padding: 60px 14px 16px; }
  .visitor-banner { position: relative; top: auto; left: auto; width: 100%; margin: 0; font-size: 12px; text-align: center; transform: none; }
  .visitor-feed { position: relative; top: auto; left: auto; width: 100%; margin-top: 12px; }
  .visitor-invite { position: relative; right: auto; bottom: auto; width: 100%; margin-top: auto; }
  .visitor-screen > .scene-footnote { display: none; }

  /* The map now carries information of its own, so it comes first. */
  .map-main { flex-direction: column; }
  .map-list-card { max-height: none; }
  .map-board-stack { gap: 3px; }
  .map-board-plate { padding: 2px 7px; }
  .map-board-name { font-size: 10px; }
  /* No hover here, so the short line moves into the card a tap opens. */
  .map-board-line { display: none; }
  .map-board-arrival { font-size: 9px; }
  .map-face > img { width: 20px; height: 20px; }
  .map-face-name { font-size: 9px; }
  .map-board-more { font-size: 9px; padding: 1px 5px; }
  .privacy-card { margin-bottom: 0; }

  .place-panel { right: 14px; bottom: calc(18px + env(safe-area-inset-bottom)); width: calc(100% - 28px); max-height: calc(100% - 90px); }

  .dialogue-screen { overflow: auto; background: var(--paper); }
  .dialogue-layout { position: relative; right: auto; bottom: auto; width: auto; grid-template-columns: 1fr; gap: 10px; margin: 62px 14px 14px; padding: 16px; }
  .dialogue-person { display: grid; grid-template-columns: 4rem 1fr; align-items: center; gap: 10px; text-align: left; }
  .dialogue-person .villager-portrait { grid-row: 1 / 3; width: 4rem; margin: 0; }
  .dialogue-person h2 { margin: 0; }
  .dialogue-person .chip { margin: 0; }
  .dialogue-exchange h1 { font-size: 20px; }
  .dialogue-line { min-height: 0; font-size: 14px; }
  .dialogue-choices { grid-template-columns: 1fr; }

  .hut-side .hut-hint { display: none; }
  .hut-leave { min-height: 42px; }
  .hut-dock { display: flex; flex: none; gap: 8px; overflow-x: auto; padding: 8px; }
  .dock-button { min-width: 8rem; }
  .hut-screen .day-note { position: absolute; right: 14px; bottom: 7.7rem; left: 14px; }

  .partner-diary-screen { padding: 4.6rem .75rem 1.4rem; }
  .partner-diary-book { grid-template-columns: 1fr; min-height: 0; }
  .partner-diary-book::before { display: none; }
  .partner-diary-right { min-height: 25rem; border-top: 2px dashed rgba(58, 42, 32, .35); border-left: 0; }
  .partner-diary-left { min-height: 32rem; }
  .partner-diary-title-row { gap: .4rem; }
  .partner-diary-turns > button { min-height: 40px; padding-inline: .65rem; font-size: .82rem; }
  .partner-diary-reply-form { flex-direction: column; }

  .mailbox-screen { padding-top: 4.6rem; }
  .mailbox-head h1 { font-size: 20px; }
  .mailbox-screen { padding-bottom: 20px; }

  .handbook-panel { top: 62px; right: 14px; bottom: 14px; width: auto; max-height: none; overflow: auto; transform: none; }
  .storage-notice { right: 10px; bottom: 10px; left: 10px; border-radius: 12px; text-align: center; }
}

@media (max-width: 860px) {
  .mailbox-layout.card { min-height: auto; grid-template-columns: 1fr; }
  .mailbox-list-column { overflow: visible; border-right: 0; border-bottom: 1px solid var(--line); }
  .mailbox-open-column { min-height: 26rem; }
}

@media (max-width: 430px) {
  .site-header { gap: 8px; }
  .wordmark { gap: 8px; }
  .main-nav { max-width: 55vw; }
  .companion-route-card h2 { font-size: 1.3rem; }
  .certificate-body { grid-template-columns: 1fr; }
  .certificate-portrait { width: 9rem; }
  .certificate-rights { grid-column: auto; }
  .visitor-invite .actions > button { width: 100%; }
}

@media (max-width: 1024px) {
  .trial-layout { display: flex; flex-direction: column; align-items: stretch; gap: 14px; overflow: auto; }
  .trial-layout > * { flex: none; }
  .trial-task { align-self: stretch; margin-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .screen { animation: none; }
  .scene-presence-token-board { animation: none; }
  /* Everything that could move is switched off here, not case by case, so a
     new screen cannot quietly reintroduce motion for someone who asked for
     none. Text and every piece of information stay exactly the same. */
  *, *::before, *::after {
    animation-delay: -.01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-delay: 0s !important;
    transition-duration: .01ms !important;
  }
  html { scroll-behavior: auto !important; }
}

/* ──────────────────────────────────────────────────────────────────────────
   環境層（W8）：地圖的天候與燈火層，以及全站共用的落雨 runtime 層。
   場景舞台上的天候貼圖走 .scene-environment-layer（見上），這一段只補地圖那
   一面，以及唯一會動的那一層。整段獨立，不動天光／tone／外殼任何既有規則。
   ────────────────────────────────────────────────────────────────────────── */

/* 燈火層用 screen 混合。沒有這一行，混合會一路穿到整個頁面底色，村子夜裡會
   連紙外的邊都一起亮起來。 */
.map-frame { isolation: isolate; }

.map-environment-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}
/* 圖載不出來時整張圖退成文字清單，這時沒有東西可以疊，天候一起收掉。 */
.map-canvas.is-wordsonly .map-environment-layer,
.map-canvas.is-wordsonly .env-rain-layer { display: none; }

/**
 * 落雨：兩個 div，各自一條 repeating-linear-gradient 與一個無限 translateY。
 * 直條負責雨絲的疏密，縱向 mask 負責把長線切成一段一段——**只有直條不會動**，
 * 垂直平移一條連續直線在畫面上等於沒動，這是這個做法唯一會踩的坑。
 * 位移量＝mask 的週期，所以每一圈都接得上，看不出接縫。
 * 只動 transform，不重排也不重繪；行動端照樣跑（本來就是最便宜的那一個）。
 */
.env-rain-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.env-rain-fall {
  position: absolute;
  inset: -60% -30%;
  will-change: transform;
}
.env-rain-fall-near {
  background-image: repeating-linear-gradient(90deg,
    rgba(226, 238, 252, 0) 0px, rgba(226, 238, 252, 0) 24px,
    rgba(226, 238, 252, .20) 25px, rgba(226, 238, 252, .20) 26px,
    rgba(226, 238, 252, 0) 27px, rgba(226, 238, 252, 0) 50px);
  -webkit-mask-image: repeating-linear-gradient(180deg,
    rgba(0, 0, 0, .9) 0px, rgba(0, 0, 0, .9) 30px,
    rgba(0, 0, 0, 0) 44px, rgba(0, 0, 0, 0) 96px);
  mask-image: repeating-linear-gradient(180deg,
    rgba(0, 0, 0, .9) 0px, rgba(0, 0, 0, .9) 30px,
    rgba(0, 0, 0, 0) 44px, rgba(0, 0, 0, 0) 96px);
  animation: env-rainfall-near 620ms linear infinite;
}
.env-rain-fall-far {
  background-image: repeating-linear-gradient(90deg,
    rgba(238, 246, 255, 0) 0px, rgba(238, 246, 255, 0) 46px,
    rgba(238, 246, 255, .14) 47px, rgba(238, 246, 255, .14) 49px,
    rgba(238, 246, 255, 0) 50px, rgba(238, 246, 255, 0) 92px);
  -webkit-mask-image: repeating-linear-gradient(180deg,
    rgba(0, 0, 0, .75) 0px, rgba(0, 0, 0, .75) 24px,
    rgba(0, 0, 0, 0) 38px, rgba(0, 0, 0, 0) 132px);
  mask-image: repeating-linear-gradient(180deg,
    rgba(0, 0, 0, .75) 0px, rgba(0, 0, 0, .75) 24px,
    rgba(0, 0, 0, 0) 38px, rgba(0, 0, 0, 0) 132px);
  animation: env-rainfall-far 980ms linear infinite;
}
@keyframes env-rainfall-near {
  from { transform: rotate(12deg) translateY(0); }
  to { transform: rotate(12deg) translateY(96px); }
}
@keyframes env-rainfall-far {
  from { transform: rotate(15deg) translateY(0); }
  to { transform: rotate(15deg) translateY(132px); }
}
/* 落在紙上的雨是深的。同樣的幾何、同樣的角度，只換水的顏色——淡色雨絲在暮色
   河堤上很清楚，在明亮的俯瞰紙圖上等於沒有（實測：接上去完全看不見）。 */
.env-rain-layer[data-surface="paper"] .env-rain-fall-near {
  background-image: repeating-linear-gradient(90deg,
    rgba(86, 106, 128, 0) 0px, rgba(86, 106, 128, 0) 24px,
    rgba(86, 106, 128, .30) 25px, rgba(86, 106, 128, .30) 26px,
    rgba(86, 106, 128, 0) 27px, rgba(86, 106, 128, 0) 50px);
}
.env-rain-layer[data-surface="paper"] .env-rain-fall-far {
  background-image: repeating-linear-gradient(90deg,
    rgba(96, 114, 134, 0) 0px, rgba(96, 114, 134, 0) 46px,
    rgba(96, 114, 134, .20) 47px, rgba(96, 114, 134, .20) 49px,
    rgba(96, 114, 134, 0) 50px, rgba(96, 114, 134, 0) 92px);
}

/* 弱雨與強雨只差密度與速度，不差幾何：換天候時雨不會整片跳位。
   不做閃電、不做閃爍——光敏安全紅線。 */
.env-rain-layer[data-intensity="light"] { opacity: .72; }
.env-rain-layer[data-intensity="heavy"] .env-rain-fall-near { animation-duration: 460ms; }
.env-rain-layer[data-intensity="heavy"] .env-rain-fall-far { animation-duration: 720ms; }

/* 靜態退回：平常不顯示，要求減少動態時它才是那場雨。 */
.env-rain-static {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.env-rain-static[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  .env-rain-fall { display: none; }
  .env-rain-static { display: block; }
}

/* ──────────────────────────────────────────────────────────────────────────
   場所對話・視覺小說構圖：空景、大立繪、正式對話面板。

   桌面面板只占左側場景欄：視窗寬扣掉 34rem 右欄後，兩邊各留 26px。立繪掛在
   面板上，它的 50% 也就是場景欄的中線，不會再被右欄切成兩半。背景仍是
   玩家所在的場所，但場上的村民、夥伴與在場名牌暫時退場，只留底景和環境層。
   ────────────────────────────────────────────────────────────────────────── */

.place-dialogue-box {
  position: fixed;
  right: calc(min(34rem, calc(100% - 52px)) + 52px);
  bottom: calc(32px + env(safe-area-inset-bottom));
  left: 26px;
  z-index: 20;
  display: block;
  width: auto;
  max-width: none;
  max-height: 45dvh;
  overflow: visible;
  border: 2px solid var(--ink);
  border-radius: 18px;
  outline: none;
  background: var(--panel);
  box-shadow: 4px 4px 0 rgba(58, 42, 32, .25);
  padding: 16px 18px 15px;
  animation: place-dialogue-arrive .25s ease-out both;
}
.place-dialogue-box:focus-visible { box-shadow: 4px 4px 0 rgba(58, 42, 32, .25), 0 0 0 3px var(--rose); }
.place-dialogue-box.is-narration { border-style: dashed; }

@keyframes place-dialogue-arrive {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* 大立繪以場景欄為準置中，腳底壓住面板的上緣；掛點空時整個容器消失。 */
.place-dialogue-figure {
  position: absolute;
  bottom: calc(100% - 2px);
  left: 50%;
  pointer-events: none;
  transform: translateX(-50%);
}
.place-dialogue-figure:empty { display: none; }

.place-dialogue-body {
  position: relative;
  display: flex;
  width: min(72rem, 100%);
  max-height: calc(45dvh - 33px);
  min-width: 0;
  margin: 0 auto;
  overflow: auto;
  flex-direction: column;
}

.place-dialogue-speaker {
  display: inline-block;
  width: fit-content;
  margin-bottom: 9px;
  border: 1.5px solid var(--rose);
  border-radius: 999px;
  background: rgba(217, 72, 111, .12);
  padding: 3px 13px;
  color: var(--rose-text);
  font-family: var(--serif);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .1em;
}

.place-dialogue-line {
  margin: 0;
  color: var(--ink);
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.85;
}

/* 間距鐵則：回應鈕與框線之間永遠留得下一口氣，鈕不會貼著紙的邊緣。
   欄數由 responseColumnsV1 決定，只取整除得開的數字，所以最後一列不會
   落單一顆；「先這樣，下次再聊」自己占滿一整列，那是有意的整列，不是孤兒。 */
.place-dialogue-responses {
  display: grid;
  margin-top: 14px;
  gap: 8px;
  grid-template-columns: repeat(var(--dialogue-response-columns, 2), minmax(0, 1fr));
}
.place-dialogue-responses > .choice-button { width: 100%; min-width: 0; padding-inline: 10px; }
.place-dialogue-responses > .choice-button.is-wide { grid-column: 1 / -1; }

/* 相遇時刻卡只留一個入口，那一句話由框接住。 */
.five-response-choices.is-single { grid-template-columns: minmax(0, 1fr); }

/* 站在畫面裡的人本身就是入口。點得動的時候他是一顆按鈕：沒有框、沒有底色，
   只有一圈暖光告訴你他可以被叫住。 */
.scene-resident-layer.is-actionable {
  border: 0;
  outline: none;
  background: none;
  cursor: pointer;
  padding: 0;
  line-height: 0;
  transition: filter .25s ease, scale .25s ease;
}
.scene-resident-layer.is-actionable:hover,
.scene-resident-layer.is-actionable:focus-visible {
  filter: drop-shadow(0 0 14px rgba(255, 236, 190, .95));
}
/* 舊聚光 class 仍由既有互動流程維護；非對話畫面的 fixture 也繼續使用它。 */
.scene-resident-layer.is-dimmed { filter: brightness(.6) saturate(.8); }
.scene-resident-layer.is-speaking {
  z-index: 3;
  filter: drop-shadow(0 6px 18px rgba(255, 220, 160, .55));
  scale: 1.04;
}

/* 右欄的頭像也是入口。它本來就是一個圓，圓自己就好看——所以不套方框、不墊紙
   卡：能點的記號直接長在圓上。手機上沒有 hover，「看得出來可以點」必須在靜置
   狀態就成立，於是圓的描邊從墨線換成村裡的暖棕，外面再共形一圈同色的細描邊，
   一眼認得出它跟旁邊只是被看的圓不一樣。指標移上去或鍵盤走到它，那圈描邊亮
   起來、圓微微上浮；名字待在原地不動，這一排字不會跟著跳。 */
.portrait-person.is-actionable {
  display: block;
  border: 0;
  outline: none;
  background: none;
  box-shadow: none;
  cursor: pointer;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: center;
}
.portrait-person.is-actionable .villager-portrait {
  border-color: var(--terra);
  box-shadow: 0 0 0 1.5px rgba(179, 106, 76, .34);
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.portrait-person.is-actionable:hover .villager-portrait,
.portrait-person.is-actionable:focus-visible .villager-portrait {
  transform: translateY(-2px);
  border-color: var(--terra);
  box-shadow: 0 0 0 3px rgba(179, 106, 76, .55), 0 4px 10px rgba(58, 42, 32, .2);
}
/* 鍵盤走到它的時候換成村裡那條玫瑰色的焦點圈：那是全站同一個記號，不能被
   頭像自己的暖棕吃掉。 */
.portrait-person.is-actionable:focus-visible .villager-portrait {
  box-shadow: 0 0 0 3px var(--rose), 0 4px 10px rgba(58, 42, 32, .2);
}
/* 對話中切空景：只收人物／夥伴／在場名牌，底景、天候與其他環境層都留著。 */
.place-screen.has-place-dialogue .scene-resident-layer,
.place-screen.has-place-dialogue .scene-resident-workstation-layer,
.place-screen.has-place-dialogue .scene-resident-trace-layer,
.place-screen.has-place-dialogue .scene-presence-token,
.place-screen.has-place-dialogue .scene-presence-note { display: none; }

/* 窄畫面沒有右欄切分：面板回到整個場景寬、立繪也回到視窗中線，
   回應鈕改成一列一顆。 */
@media (max-width: 1000px) {
  .place-dialogue-box {
    right: 14px;
    bottom: calc(18px + env(safe-area-inset-bottom));
    left: 14px;
    width: auto;
    padding-right: max(18px, env(safe-area-inset-right));
    padding-left: max(18px, env(safe-area-inset-left));
  }
  .place-dialogue-responses { grid-template-columns: minmax(0, 1fr); }
}

/* 要求減少動態的人，框直接在原地出現與消失；讀到的字一模一樣。 */
@media (prefers-reduced-motion: reduce) {
  .place-dialogue-box { animation: none; }
  .scene-resident-layer.is-actionable,
  .scene-resident-layer.is-speaking { transition: none; }
  /* 頭像那圈描邊照樣亮，只是不再有過場，圓也不上浮。 */
  .portrait-person.is-actionable .villager-portrait { transition: none; }
  .portrait-person.is-actionable:hover .villager-portrait,
  .portrait-person.is-actionable:focus-visible .villager-portrait { transform: none; }
}

/* ──────────────────────────────────────────────────────────────────────────
   對話大立繪：說話的人站在全寬紙帶上方中央。

   立繪是去背的，所以它不需要框、也不需要底色——套一張紙卡就變成「貼在紙上的
   一張照片」，而不是「站在紙上的人」。腳底一層極輕的落影讓他站得住；影子由
   drop-shadow 讀 alpha 畫出來，所以它跟著毛邊與鬍鬚走，不會在透明的地方留下
   一個方方正正的影子。

   掛點空的時候整個容器不存在（上面的 `.place-dialogue-figure:empty`），所以
   這一段每一條都只在「真的有一張圖畫出來了」之後才生效：沒有資產的夥伴、以及
   圖載不起來的時候，版面就是原本那個版面。
   ────────────────────────────────────────────────────────────────────────── */

.place-dialogue-portrait {
  display: block;
  width: auto;
  height: min(64dvh, 46rem);
  max-width: min(78dvw, 34rem);
  object-fit: contain;
  /* 立繪高矮不一，站的位置不該跟著變：一律以腳底對齊紙帶上緣。 */
  object-position: bottom;
  filter: drop-shadow(0 3px 4px rgba(58, 42, 32, .24));
}

/* 手機讓人物保留主角感，但不蓋滿可視高度，也不擠壓紙帶裡的文字。 */
@media (max-width: 1000px) {
  .place-dialogue-portrait { height: min(44dvh, 22rem); max-width: 72dvw; }
}
