/* Base styles — reset, body, layout, buttons, flash, nav */

body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: var(--theme-bg-image);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0.12;
  pointer-events: none;
  z-index: 0;
}

body::after {
  content: '';
  position: fixed;
  inset: 0;
  background: radial-gradient(ellipse at center, transparent 30%, rgba(0, 0, 0, 0.5) 100%);
  pointer-events: none;
  z-index: 9998;
}
/* The vintage edges belong to the sign-in, legal and demo pages and to the
   game itself. A signed-in page under the nav (profile and sign out) is a
   working page and is drawn flat: the dashboard, profile, setup, mode select
   and the game's own screens opened on their own. The game screen carries the
   nav too, hidden, and keeps its edges (game/layout.css). */
body:has(.app-nav):not(:has(.game-screen))::after { display: none; }

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

/* hidden means hidden, whatever display a class gives the element. */
[hidden] { display: none !important; }

/* The parchment pages' entrance: a short fade and rise. One copy for all of
   them (the dashboard, profile, mode select and setup each had their own). */
@keyframes riseIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
html { font-size: 125%; }
@media (max-width: 768px) { html { font-size: 100%; } }
body { font-family: var(--theme-font); background: var(--theme-bg); color: var(--theme-text); min-height: 100vh; padding-top: env(safe-area-inset-top); }
a { color: var(--theme-accent); }

/* The Android app is consumption-only on Google Play, so nothing in it may
   point to buying Premium. Markup broadcast from jobs has no request to ask,
   so it carries both variants and this picks (html.native, see the layout). */
html:not(.native) .native-only,
html.native .web-only { display: none !important; }

/* Read by screen readers, not shown. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* An app does not flash a grey box on every tap, or let a long press select
   the words on its buttons. */
html.native { -webkit-tap-highlight-color: transparent; }
html.native :is(button, .btn, summary, .app-nav, .game-topbar, .panel-action-btn, .demo-card, .shelf-card-face, .shelf-new,
                .story-card, .story-strip-link) {
  -webkit-user-select: none;
  user-select: none;
}

/* Nor does it fade each screen in. The pages' entrances (a 0.8s fade and
   rise) played on every screen, and in the app a screen changes with no
   slide, the page before staying until the new one draws: the new one then
   arrived blank and faded in after the tap. */
html.native :is(.dashboard, .profile-box, .mode-select, .setup-card, .signin-box, .legal-content,
                .signin-logo, .signin-subtitle, .signin-divider, .signin-scroll-cue, .signin-edition,
                .google-btn, .signin-demo-btn) {
  animation: none;
}

.container { position: relative; z-index: 1; max-width: 900px; margin: 0 auto; padding: 1rem; }
@media (min-width: 1400px) { .container { max-width: 1200px; } }
@media (max-width: 768px) {
  .container { padding: 0.5rem 0.6rem; }
  .app-nav-tokens-count { display: block; }
}

.btn { display: inline-block; padding: 0.5rem 1.2rem; border: 1px solid var(--theme-accent); background: transparent; color: var(--theme-accent); cursor: pointer; font-family: inherit; font-size: 0.9rem; text-decoration: none; }
@media (hover: hover) {
  .btn:hover { background: var(--theme-accent); color: var(--theme-bg); }
}
/* In a game's palette (the confirm over the saves, say); the parchment pages
   draw their own (pages/parchment.css). */
.btn--quiet { border-color: var(--border-color); color: var(--text-mid); }
@media (hover: hover) {
  .btn--quiet:hover { background: transparent; border-color: var(--theme-accent); color: var(--theme-accent); }
}
.btn--danger { border-color: color-mix(in srgb, var(--color-failure-text) 45%, transparent); color: var(--color-failure-text); }
@media (hover: hover) {
  .btn--danger:hover { background: color-mix(in srgb, var(--color-failure-text) 12%, transparent); border-color: var(--color-failure-text); color: var(--color-failure-text); }
}

.flash-notice { background: #1a3a2a; border: 1px solid var(--theme-accent); padding: 0.75rem 1rem; margin-bottom: 1rem; }
.flash-alert { background: #3a1a1a; border: 1px solid #a08080; color: #c8a0a0; padding: 0.75rem 1rem; margin-bottom: 1rem; }

h1, h2, h3 { color: #e8e8d4; font-weight: normal; letter-spacing: 0.05em; }

.app-nav { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 0.5rem 0.75rem; padding: 0.4rem 0 0.75rem; border-bottom: 1px solid #1e1810; margin-bottom: 0.75rem; font-size: 0.7rem; }
.app-nav-home { text-decoration: none; margin-right: auto; display: flex; align-items: center; }
@media (hover: hover) {
  .app-nav-home:hover { opacity: 0.8; }
}
.app-nav-icon { height: 1.6rem; width: auto; }
.app-nav-user { display: inline-flex; align-items: center; gap: 0.3rem; font-family: 'Lora', Georgia, serif; font-style: italic; color: #4a4030; max-width: 8rem; text-decoration: none; }
.app-nav-user-icon { width: 0.95em; height: 0.95em; flex-shrink: 0; opacity: 0.8; }
.app-nav-user-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (hover: hover) {
  .app-nav-user:hover { color: var(--theme-accent); }
}
.app-nav-tokens { color: #4a4030; font-size: 0.65rem; letter-spacing: 0.05em; max-width: 6rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-nav-signout { background: transparent; border: 1px solid #2a2318; color: #4a4030; padding: 0.2rem 0.4rem; cursor: pointer; font-family: 'Cinzel', serif; font-size: 0.6rem; letter-spacing: 0.1em; line-height: 1.2; }
@media (hover: hover) {
  .app-nav-signout:hover { color: var(--theme-accent); border-color: #3a3020; }
}
.app-nav-locale { background: transparent; border: 1px solid #2a2318; color: #4a4030; padding: 0.2rem 0.4rem; cursor: pointer; font-family: 'Cinzel', serif; font-size: 0.6rem; letter-spacing: 0.1em; line-height: 1.2; appearance: none; -webkit-appearance: none; }
@media (hover: hover) {
  .app-nav-locale:hover { color: var(--theme-accent); border-color: #3a3020; }
}


/* ── Loading overlay ── */
.loading-overlay[hidden] { display: none !important; }
.loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    repeating-conic-gradient(rgba(120, 90, 50, 0.03) 0% 25%, transparent 0% 50%) 0 0 / 4px 4px,
    radial-gradient(ellipse at 0% 0%, rgba(90, 60, 30, 0.15) 0%, transparent 50%),
    radial-gradient(ellipse at 100% 100%, rgba(90, 55, 25, 0.18) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 40%, #efe3cd 0%, #e2d3b8 40%, #d4c4a4 80%);
  animation: overlayFadeIn 0.3s ease-out both;
}
@keyframes overlayFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.loading-overlay-content { text-align: center; }
.loading-overlay-title {
  font-family: 'Cinzel', 'Palatino Linotype', serif;
  font-size: 2.2rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: #3a2a14;
  text-transform: uppercase;
  text-shadow: 0 1px 0 rgba(255, 245, 220, 0.5);
  margin-bottom: 1.5rem;
}
.loading-overlay-dots {
  display: flex;
  gap: 0.45rem;
  justify-content: center;
}
.loading-overlay-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #8a7354;
  animation: loadPulse 1.4s ease-in-out infinite;
}
.loading-overlay-dots span:nth-child(2) { animation-delay: 0.2s; }
.loading-overlay-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes loadPulse {
  0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

/* ── Site footer — legal links ── */
.site-footer {
  padding: 2rem 1rem 1.2rem;
  font-family: 'Lora', Georgia, serif;
  font-style: italic;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  position: relative;
  z-index: 1;
}

/* A wrapping row, so each link wraps whole: the old centred text with a dot
   between links could end a line on a lone dot. */
.site-footer,
.profile-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  column-gap: 1.6em;
}

.site-footer a {
  color: #4a4030;
  text-decoration: none;
  opacity: 0.7;
  transition: opacity 0.3s ease;
  /* "Refund / Policy" broke across two lines on a phone. */
  white-space: nowrap;
}
@media (hover: hover) {
  .site-footer a:hover { opacity: 1; }
}

/* Modal dialog — generic, driven by controllers/dialog_controller.js. Native
   <dialog> supplies Esc, focus trapping and the backdrop; this is only paint. */
/* margin: auto is what centres a modal dialog, and the global `* { margin: 0 }`
   reset above strips the UA default — without this it pins to the top-left. */
.app-dialog { border: 1px solid var(--border-color); background: var(--panel-bg, #14100c); color: var(--text-mid); padding: 0; max-width: min(30rem, calc(100vw - 2rem)); width: 100%; margin: auto; }
.app-dialog::backdrop { background: rgba(0, 0, 0, 0.65); }
.app-dialog-body { padding: 1rem 1.15rem 1.15rem; }
/* On a phone a dialog is a sheet from the bottom edge, where the thumb is,
   rather than a card floating mid-screen. The lightbox stays centred on its
   picture. dialog. outranks the per-dialog widths (.app-dialog:has(...)). */
@media (max-width: 640px) {
  dialog.app-dialog:not(.lightbox) {
    margin: auto 0 0;
    width: 100%;
    max-width: 100%;
    max-height: 90dvh;
    overflow-y: auto;
    border-width: 1px 0 0;
    border-radius: 12px 12px 0 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
}
/* Re-acceptance popup (shared/_terms_reacceptance). It opens over every page,
   dark game screens and the parchment dashboard alike, and sits outside each
   page's own markup, so the page styles never reach it. It carries its own
   parchment look, the dashboard's, rather than inheriting the default theme,
   whose font is Courier. */
.terms-reaccept { margin: auto; padding: 0; width: 100%; max-width: min(32rem, calc(100vw - 2rem)); border: 1px solid rgba(138, 115, 84, 0.6); color: #3a2a14; background: radial-gradient(ellipse at 50% 30%, #efe3cd 0%, #e2d3b8 60%, #d4c4a4 100%); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); font-family: 'Lora', Georgia, serif; }
.terms-reaccept::backdrop { background: rgba(20, 14, 8, 0.72); }
.terms-reaccept-body { padding: 1.4rem 1.5rem 1.2rem; }
.terms-reaccept-title { font-family: 'Cinzel', 'Palatino Linotype', serif; font-size: 0.8rem; font-weight: normal; letter-spacing: 0.22em; text-transform: uppercase; text-align: center; color: #5a4a30; margin-bottom: 1rem; }
.terms-reaccept-text { font-size: 0.8rem; line-height: 1.6; margin-bottom: 1rem; }
.terms-reaccept a { color: #5a4a30; text-decoration: underline; text-underline-offset: 2px; }
@media (hover: hover) {
  .terms-reaccept a:hover { color: #3a2a14; }
}
/* Parchment over any page, a game included: its own ring colour (access.css). */
.terms-reaccept { --focus-ring: #5a4a30; }
.terms-reaccept-check { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.8rem; line-height: 1.5; cursor: pointer; }
.terms-reaccept-check input { margin-top: 0.2rem; accent-color: #5a4a30; flex-shrink: 0; }
.terms-reaccept-actions { display: flex; justify-content: center; margin: 1.1rem 0 1rem; }
.terms-reaccept-btn { display: inline-block; font-family: 'Cinzel', serif; font-size: 0.7rem; letter-spacing: 0.1em; padding: 0.45rem 1rem; border: 1px solid #b5a382; background: transparent; color: #5a4a30; cursor: pointer; transition: background 0.2s ease, border-color 0.2s ease; }
.terms-reaccept a.terms-reaccept-btn { text-decoration: none; }
@media (hover: hover) {
  .terms-reaccept-btn:hover { background: rgba(138, 115, 84, 0.12); border-color: #8a7354; color: #3a2a14; }
}
.terms-reaccept-btn-primary { border-color: #8a7354; background: rgba(90, 74, 48, 0.12); color: #3a2a14; }
.terms-reaccept-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.terms-reaccept-leave { font-size: 0.72rem; font-style: italic; line-height: 1.5; color: #7a6548; border-top: 1px solid rgba(138, 115, 84, 0.3); padding-top: 0.9rem; margin-bottom: 0.8rem; }
.terms-reaccept-exits { display: flex; justify-content: center; gap: 0.6rem; flex-wrap: wrap; }
.terms-reaccept-exits form { display: inline; }
/* High contrast replaces the parchment only where high_contrast.css defines its
   palette, the game screen. Everywhere else the variables are unset, and the card
   would lose its background, so it keeps the parchment. */
body.hc-dark:has(.game-screen) .terms-reaccept, body.hc-light:has(.game-screen) .terms-reaccept { background: var(--panel-bg); color: var(--theme-text); border-color: var(--theme-accent); --focus-ring: var(--theme-accent); }
body.hc-dark:has(.game-screen) :is(.terms-reaccept-title, .terms-reaccept-leave, .terms-reaccept a, .terms-reaccept-btn), body.hc-light:has(.game-screen) :is(.terms-reaccept-title, .terms-reaccept-leave, .terms-reaccept a, .terms-reaccept-btn) { color: var(--theme-text); border-color: var(--theme-accent); }
/* A question in the page (shared/_confirm_dialog, lib/confirm.js). */
.app-confirm { max-width: min(26rem, calc(100vw - 2rem)); }
.app-confirm-message { font-family: 'Lora', Georgia, serif; font-size: 0.85rem; line-height: 1.6; color: var(--text-bright); margin-bottom: 1.1rem; overflow-wrap: anywhere; }
.app-confirm-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.6rem; }
@media (max-width: 480px) { .app-confirm-actions > .btn { flex: 1 1 auto; text-align: center; } }
.app-dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.85rem; }
.app-dialog-title { font-family: 'Cinzel', serif; font-size: 0.78rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-muted); }
.app-dialog-close { background: transparent; border: 0; color: var(--text-muted); font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 0 0.25rem; }
@media (hover: hover) {
  .app-dialog-close:hover { color: var(--theme-accent); }
}

/* Full-size image viewer — shared/_lightbox, driven by lightbox_controller.js.
   The same .app-dialog as every other modal, sized to its picture rather than to
   a column of text: no panel, no padding, the image on the backdrop with the
   close button laid over its corner where a thumb can reach it. */
.lightbox-trigger { display: block; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; background: none; color: inherit; line-height: 0; cursor: zoom-in; }
/* fit-content, not auto. A modal <dialog> is position: fixed with inset: 0, so an
   auto width stretches it across the whole viewport and the image sits at its
   left edge, with the close button stranded at the far right. Shrink-wrapping
   the dialog to its picture is what lets margin: auto centre it. */
.app-dialog.lightbox { width: fit-content; height: fit-content; max-width: calc(100vw - 1rem); max-height: calc(100vh - 1rem); max-height: calc(100dvh - 1rem); background: transparent; border: 0; overflow: visible; }
.lightbox-body { position: relative; width: fit-content; }
.lightbox-image { display: block; width: auto; height: auto; max-width: calc(100vw - 1rem); max-height: calc(100vh - 1rem); max-height: calc(100dvh - 1rem); object-fit: contain; border: 1px solid var(--border-color); cursor: zoom-out; }
/* The viewer's one optional button — today the NPC redraw. Bottom centre, over
   the picture, so it is where the eye already is without covering the face. */
.lightbox-action { position: absolute; bottom: 0.6rem; left: 50%; transform: translateX(-50%); z-index: 1; text-decoration: none; }
.lightbox-action[hidden] { display: none; }
.lightbox-close { position: absolute; top: 0.4rem; right: 0.4rem; z-index: 1; width: 2.25rem; height: 2.25rem; border-radius: 50%; background: rgba(0, 0, 0, 0.55); color: #f0ece4; }
