/* ============================================================================
   decor.css — illuminated-manuscript flourishes: keepsake wax seal + frame,
   drop-cap capitals, rune-motif dividers. Depends on tokens.css, base.css.

   Deliberately self-contained: everything here is achievable with the
   markup index.html already needs for other reasons (a container div, a
   paragraph to mark as a chapter-opener) — nothing in this file requires
   the orchestrator to hand-author bespoke SVG defs. Where a "real SVG with
   a radial gradient" is called for, it's produced as a `data:image/svg+xml`
   background-image (same technique as --noise-grain in tokens.css), which
   is why decor.css never needs an <svg> element pre-placed in the DOM.

   Runic borders are ALWAYS drawn geometry (SVG path data below), never
   Unicode Runic-block characters (U+16A0–U+16FF) in a font — that was the
   previous build's tofu/invisible-glyph bug on Android. There is no font
   dependency here at all, so this can never regress.

   ---------------------------------------------------------------------------
   CONTRACT: markup this file assumes
   ---------------------------------------------------------------------------

   WAX SEAL (only place --seal-red is allowed to appear)
     js/print.js's real keepsake cover renders it EMPTY —
       <div class="keepsake-seal" aria-hidden="true"></div>
     — so the impression glyph is a pure-CSS mask (::after below), not a
     dependency on an inner <svg>. An inner icon still works if present:
     <div class="keepsake-seal"><svg class="icon"><use href="#i-seal-stamp"/></svg></div>
     Optional ribbon caption under it: <p class="keepsake-seal-label">…</p>

   THE KEEPSAKE (js/print.js's real exported document — see its own header
   comment: it owns escaping/structure, css/print.css + decor.css own look)
     <article class="keepsake">
       <header class="keepsake-cover">
         <p class="keepsake-eyebrow">Official Chronicle Keepsake</p>
         <h1 class="keepsake-title">AETHELWING</h1>
         <p class="keepsake-subtitle">…</p>
         <p class="keepsake-date">…</p>
         <div class="keepsake-seal" aria-hidden="true"></div>
       </header>
       <section class="keepsake-sheet keepsake-rider">
         <h2 class="keepsake-heading">The Rider</h2>
         <dl class="keepsake-facts"><dt>Name</dt><dd>…</dd>…</dl>
         <p class="keepsake-oath"><strong>Oath (active)</strong> — …</p>
       </section>
       <section class="keepsake-sheet keepsake-dragon">…<h3 class="keepsake-subheading">Scars</h3>
         <ul class="keepsake-scars">…</ul> or <p class="keepsake-empty">…</p></section>
       <section class="keepsake-sheet"><h2 class="keepsake-heading">The Chronicle</h2>
         <article class="keepsake-entry keepsake-dropcap"><p class="keepsake-entry-meta">…</p>
           <p class="keepsake-entry-text">…</p></article>…</section>
       <section class="keepsake-sheet"><table class="keepsake-flightlog">…</table></section>
       <section class="keepsake-sheet keepsake-ending"><p class="keepsake-epilogue">…</p></section>
     </article>
   The illuminated corner-fitting + double-fillet frame goes on the cover
   page only (a full manuscript-style frontispiece); inner .keepsake-sheet
   pages stay plain parchment for print economy and readability across many
   journal entries. .keepsake-frame/.keepsake-frame-inner (an alternate two
   -div authoring form wrapping arbitrary content) still work identically if
   ever used instead of/around a bare .keepsake.

   DROP CAPITALS — add `.cap-drop` (prose) or `.keepsake-dropcap` (the
   keepsake's own first journal entry, exactly as js/print.js emits it) ONLY
   to the first paragraph/entry of a chapter, never every paragraph:
     <p class="cap-drop">Once, beneath a sky of molten copper, …</p>

   RUNE DIVIDER — a decorative horizontal rule between sections:
     <div class="rune-divider" role="separator" aria-hidden="true"></div>
   ============================================================================ */


/* ---------------------------------------------------------------------- */
/* WAX SEAL — pure CSS medallion (radial-gradient "SVG-equivalent" wax),    */
/* the ONLY component in the entire app allowed to render --seal-red.      */
/* ---------------------------------------------------------------------- */

.keepsake-seal {
  position: relative;
  width: clamp(72px, 14vw, 108px);
  aspect-ratio: 1;
  margin-inline: auto;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--parchment);
  background:
    var(--noise-grain),
    radial-gradient(circle at 34% 28%, var(--seal-red-hi) 0%, var(--seal-red) 55%, var(--seal-red-shadow) 100%);
  background-blend-mode: overlay, normal;
  box-shadow:
    0 8px 18px -4px rgba(0,0,0,0.65),
    inset 0 2px 3px rgba(255,255,255,0.25),
    inset 0 -6px 12px rgba(0,0,0,0.45);
}
/* melted-wax irregular edge — a soft blurred halo breaking the perfect circle */
.keepsake-seal::before {
  content: "";
  position: absolute;
  inset: -6%;
  border-radius: 46% 54% 52% 48% / 52% 48% 54% 46%;
  background: inherit;
  z-index: -1;
  filter: blur(0.5px);
  opacity: 0.9;
}
.keepsake-seal .icon {
  width: 55%;
  height: 55%;
  color: var(--parchment);
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5));
}
/* CSS-only impression for when .keepsake-seal is emitted empty (the real
   js/print.js case) — a small wing/drop sigil masked out of a parchment
   fill, so the seal never reads as a blank wax blob. Hidden automatically
   the moment a real inner .icon exists (::after would sit under it either
   way, but we skip drawing it at all via :empty for a crisper result). */
.keepsake-seal:empty::after {
  content: "";
  position: absolute;
  width: 52%;
  height: 52%;
  background: var(--parchment);
  opacity: 0.92;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 20c2-7 5-12 8-17 0 5 1 9 3 10 1-3 2-6 3-9 2 4 3 8 6 10-3 2-6 1-8-1-1 4-4 7-8 8-1 .3-2.3.2-4-1z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 20c2-7 5-12 8-17 0 5 1 9 3 10 1-3 2-6 3-9 2 4 3 8 6 10-3 2-6 1-8-1-1 4-4 7-8 8-1 .3-2.3.2-4-1z'/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5));
}
.keepsake-seal-label {
  margin-top: var(--space-2);
  text-align: center;
  font-family: var(--font-cinzel);
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--text-decorative);
}


/* ---------------------------------------------------------------------- */
/* THE KEEPSAKE — js/print.js's real exported document                     */
/* ---------------------------------------------------------------------- */

/* Outer gold-foil "binding" — a slim hammered-metal margin around the whole
   article, print-color-adjust in print.css keeps it gold on paper too. */
.keepsake {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: 10px;
  border-radius: var(--radius-xl);
  background: var(--gold-foil);
  box-shadow: var(--shadow-lg);
}

/* every page — cover + each .keepsake-sheet section — is its own parchment
   leaf inside that binding */
.keepsake-cover, .keepsake-sheet {
  position: relative;
  background:
    var(--noise-grain-coarse),
    linear-gradient(165deg, var(--parchment) 0%, var(--parchment-shade) 100%);
  background-blend-mode: overlay, normal;
  color: var(--ink);
  border-radius: calc(var(--radius-xl) - 6px);
  padding: var(--space-8) var(--space-6);
}

/* the cover alone gets the full illuminated-frontispiece treatment: the
   "filete doble" (a second inset gold line, independent of the outer
   binding) + four hammered-gold corner fittings — inner pages stay plain
   parchment so a long Chronicle doesn't repeat costly ornament per section */
.keepsake-cover::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: var(--border-hairline) solid color-mix(in oklab, var(--gold-dim) 70%, black);
  border-radius: calc(var(--radius-xl) - 14px);
  pointer-events: none;
}
.keepsake-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 0% 0%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 100% 0%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 0% 100%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 100% 100%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%);
  background-repeat: no-repeat;
  background-size: 46px 46px;
  background-position: top left, top right, bottom left, bottom right;
  opacity: 0.9;
}
.keepsake-cover {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding-block: var(--space-10);
}
.keepsake-eyebrow {
  font-family: var(--font-cinzel);
  text-transform: uppercase;
  letter-spacing: var(--ls-wider);
  font-size: var(--fs-xs);
  color: var(--gold-dim);
}
.keepsake-title {
  font-family: var(--font-display);
  /* AETHELWING is one unbroken word — at a fixed --fs-3xl (44px) it overflowed
     the frame on any modal narrower than ~380px (confirmed in-browser: the
     leading A and trailing G were clipped past the gold border). clamp()
     scales it down before that happens; break-word is the remaining safety
     net if a future longer title is ever swapped in. */
  font-size: clamp(1.75rem, 11vw, var(--fs-3xl));
  letter-spacing: var(--ls-wide);
  color: var(--iron-gall);
  margin: var(--space-2) 0;
  max-width: 100%;
  overflow-wrap: break-word;
  word-break: break-word;
}
.keepsake-subtitle { font-family: var(--font-scroll); font-style: italic; color: var(--iron-gall); }
.keepsake-date { font-size: var(--fs-xs); color: var(--gold-dim); margin-top: var(--space-1); }
.keepsake-seal { margin-top: var(--space-4); }

/* inner pages */
.keepsake-heading {
  font-family: var(--font-display);
  color: var(--iron-gall);
  border-bottom: var(--border-thin) solid var(--gold-leaf);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-4);
}
.keepsake-subheading {
  font-family: var(--font-cinzel);
  color: var(--iron-gall);
  margin-top: var(--space-4);
  margin-bottom: var(--space-2);
}
.keepsake-facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  margin: 0 0 var(--space-3);
}
.keepsake-facts dt {
  font-family: var(--font-cinzel);
  color: var(--gold-dim);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}
.keepsake-facts dd { margin: 0; color: var(--ink); }
.keepsake-oath {
  font-family: var(--font-scroll);
  font-style: italic;
  padding: var(--space-3) var(--space-4);
  border-left: var(--border-thick) solid var(--gold-leaf);
  background: rgba(36, 23, 8, 0.04);
}
.keepsake-oath strong { color: var(--iron-gall); font-style: normal; }
.keepsake-scars { padding-left: 1.2em; margin: 0; }
.keepsake-scars li { margin-bottom: var(--space-1); }
.keepsake-empty { font-style: italic; color: color-mix(in oklab, var(--ink) 55%, transparent); }
.keepsake-dragon-name { font-family: var(--font-display); font-size: var(--fs-xl); color: var(--iron-gall); margin-bottom: var(--space-2); }
.keepsake-truename { font-family: var(--font-scroll); font-style: italic; color: var(--gold-dim); font-size: var(--fs-md); }

/* base.css:148 sets a global `p { color: var(--text-body) }` (light
   parchment text, correct for the dark app background). Every other
   text-holding class on this parchment page sets its OWN color explicitly
   (.keepsake-facts dd, .keepsake-flightlog td, etc.) and so never touches
   that rule, but .keepsake-entry-text and .keepsake-epilogue are bare <p>
   tags with no color of their own — direct styling on an element always
   wins over an inherited value, so that global rule silently beat the
   inherited --ink from .keepsake-sheet/.keepsake-cover. Confirmed by
   rendering a real PDF: every journal entry and the ending epilogue printed
   as light cream text on light parchment, barely legible. Same bug class as
   the Chronicle/Journal fix in views.css, just in the one light surface
   that audit never covered because it only lives inside the print flow. */
.keepsake-cover p, .keepsake-sheet p { color: var(--ink); }

.keepsake-entry {
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px dashed color-mix(in oklab, var(--gold-dim) 45%, transparent);
}
.keepsake-entry:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.keepsake-entry-meta {
  font-family: var(--font-cinzel);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
  color: var(--gold-dim);
  margin-bottom: var(--space-1);
}
.keepsake-entry-text { font-family: var(--font-scroll); line-height: var(--lh-loose); margin: 0; }
/* the illuminated capital on the keepsake's first entry only, exactly the
   same treatment as .cap-drop (kept as a distinct rule since it targets a
   nested .keepsake-entry-text rather than being applied directly) */
.keepsake-dropcap .keepsake-entry-text { position: relative; }
.keepsake-dropcap .keepsake-entry-text::before {
  content: "";
  position: absolute;
  top: -0.15em;
  left: -0.1em;
  width: 1.9em;
  height: 1.9em;
  border-radius: var(--radius-sm);
  background: radial-gradient(circle at 30% 25%, color-mix(in oklab, var(--gold-hi) 45%, transparent) 0%, transparent 70%);
  pointer-events: none;
}
.keepsake-dropcap .keepsake-entry-text::first-letter {
  position: relative;
  font-family: var(--font-display);
  font-size: 3.1em;
  line-height: 0.78;
  float: left;
  padding: 0.03em 0.1em 0 0;
  color: var(--gold-leaf);
  text-shadow: 0 1px 0 rgba(255,255,255,0.35), 0 2px 6px rgba(0,0,0,0.35);
}

.keepsake-flightlog {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.keepsake-flightlog th, .keepsake-flightlog td {
  border-bottom: 1px solid color-mix(in oklab, var(--gold-dim) 35%, transparent);
  padding: var(--space-1) var(--space-2);
  text-align: left;
  color: var(--ink);
}
.keepsake-flightlog th {
  font-family: var(--font-cinzel);
  color: var(--gold-dim);
  text-transform: uppercase;
  font-size: var(--fs-2xs);
}

.keepsake-ending .keepsake-heading { text-align: center; border-bottom: none; font-size: var(--fs-2xl); }
.keepsake-epilogue {
  font-family: var(--font-scroll);
  font-style: italic;
  line-height: var(--lh-loose);
  font-size: var(--fs-md);
  text-align: center;
  max-width: 60ch;
  margin-inline: auto;
}

/* ---------------------------------------------------------------------- */
/* .keepsake-frame / .keepsake-frame-inner — alternate two-div authoring   */
/* form for the same illuminated-frame treatment, wrapping arbitrary        */
/* content instead of the real .keepsake structure above. Both work.       */
/* ---------------------------------------------------------------------- */

.keepsake-frame {
  position: relative;
  padding: var(--space-2);
  border-radius: var(--radius-xl);
  background: var(--gold-foil);
  box-shadow: var(--shadow-lg);
}

.keepsake-frame-inner {
  position: relative;
  border-radius: calc(var(--radius-xl) - 6px);
  background:
    var(--noise-grain-coarse),
    linear-gradient(165deg, var(--parchment) 0%, var(--parchment-shade) 100%);
  background-blend-mode: overlay, normal;
  color: var(--ink);
  padding: var(--space-8) var(--space-6);
}
.keepsake-frame-inner::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: var(--border-hairline) solid color-mix(in oklab, var(--gold-dim) 70%, black);
  border-radius: calc(var(--radius-xl) - 14px);
  pointer-events: none;
}
.keepsake-frame-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 0% 0%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 100% 0%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 0% 100%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%),
    radial-gradient(circle at 100% 100%, var(--gold-hi) 0%, var(--gold-leaf) 35%, transparent 55%);
  background-repeat: no-repeat;
  background-size: 46px 46px;
  background-position: top left, top right, bottom left, bottom right;
  opacity: 0.9;
}


/* ---------------------------------------------------------------------- */
/* DROP CAPITALS — illuminated first letter, first entry of a chapter only  */
/* ---------------------------------------------------------------------- */

.cap-drop {
  position: relative;
}
.cap-drop::before {
  content: "";
  position: absolute;
  top: -0.15em;
  left: -0.1em;
  width: 1.9em;
  height: 1.9em;
  border-radius: var(--radius-sm);
  background: radial-gradient(circle at 30% 25%, color-mix(in oklab, var(--gold-hi) 45%, transparent) 0%, transparent 70%);
  z-index: 0;
  pointer-events: none;
}
.cap-drop::first-letter {
  position: relative;
  font-family: var(--font-display);
  font-size: 3.1em;
  line-height: 0.78;
  float: left;
  padding: 0.03em 0.1em 0 0;
  color: var(--gold-leaf);
  text-shadow: 0 1px 0 rgba(255,255,255,0.35), 0 2px 6px rgba(0,0,0,0.35);
}


/* ---------------------------------------------------------------------- */
/* RUNE DIVIDER — geometry drawn as an SVG data: URI, never Unicode text    */
/* ---------------------------------------------------------------------- */

.rune-divider {
  height: 22px;
  margin: var(--space-6) 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='22'%3E%3Cg fill='none' stroke='%238A6A2F' stroke-width='1.6' stroke-linecap='round'%3E%3Cpath d='M4 11h24'/%3E%3Cpath d='M40 3v16M40 3l7 5M40 19l7-5'/%3E%3Cpath d='M60 3l6 8-6 8'/%3E%3Cpath d='M78 3v16M78 3l-7 5M78 19l-7 5'/%3E%3Cpath d='M92 11h24'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: center;
  background-size: 120px 22px;
  opacity: 0.75;
}

/* thin variant for tighter spaces (nav separators, card footers) */
.rune-divider--sm {
  height: 14px;
  background-size: 80px 14px;
  opacity: 0.6;
}

@media (prefers-contrast: more) {
  .rune-divider { opacity: 1; }
}
