/* ==========================================================================
   THE ORACLE -- oracle.css
   An UNOFFICIAL fan homage. Tibia is a game and a registered trademark of
   CipSoft GmbH. No CipSoft artwork, sprite, logo or font file is used,
   reproduced or linked here. Every mark on this page is original CSS or
   original inline SVG authored for this project.

   PRIVACY CONTRACT
   ----------------
   This stylesheet makes ZERO network requests. No @import, no url() to any
   host, no webfont, no external image. Every family named below is a stack
   of locally-installed system fonts; if none is present the browser falls
   back to its own generic. That is intentional and it is not negotiable:
   the page claims it contacts no other host, so it must contact no other
   host.

   CONTENT SECURITY POLICY NOTE
   ----------------------------
   The vhost serves style-src 'self' with no 'unsafe-inline', so inline
   style="" attributes in the markup are blocked by the browser. Nothing in
   the shell uses them. Anything the renderer must size at runtime is driven
   by a CSS custom property set through the CSSOM, which CSP permits:

       el.style.setProperty('--fill', '61.4%');

   Search this file for "--fill" and "--sev" for the full list of runtime
   properties.

   ASCII ONLY. No em dashes, no smart quotes, no ellipsis character, no
   emoji, no box drawing. Double hyphen "--" stands in for a dash.

   CONTENTS
     01 Tokens
     02 Base and backdrop
     03 Typography
     04 Chrome primitives (the panel recipe, ornaments, slabs)
     05 Bars and meters
     06 Buttons and the LOOK affordance
     07 Masthead / the temple
     08 Divination
     09 Reading sections and signal rows
     10 Entropy verdict
     11 What the Oracle cannot see
     12 Footer
     13 Panel states: pending / empty / failed / blocked
     14 Utilities
     15 Responsive
     16 Reduced motion, forced colors, print
   ========================================================================== */


/* ==========================================================================
   01 TOKENS
   Palette values are the verified tibia.com website palette recorded in
   research/tibia_canon.json (tibia_visual_identity.website_palette_verified)
   plus the classic C++ client bar colours. Names below are ours.
   ========================================================================== */

:root {
  /* --- The dark field ------------------------------------------------- */
  --night:          #061222;  /* page backdrop. never pure black. */
  --slate:          #16232F;  /* dark chrome band */
  --slate-hi:       #24333F;  /* raised dark chrome */
  --slate-lo:       #0C1A28;  /* recessed dark chrome */

  /* --- Parchment ------------------------------------------------------ */
  --parch-pale:     #FAF0D7;  /* palest paper. inner highlight line. */
  --parch-light:    #F1E0C6;  /* odd rows, primary surface */
  --parch:          #D4C0A1;  /* even rows, main container fill */
  --parch-dim:      #C3AE8D;  /* recessed paper */

  /* --- Ink and frame -------------------------------------------------- */
  --ink:            #5A2800;  /* body copy. dark red-brown, not black. */
  /* --ink-soft is measured, not eyeballed: it has to clear 4.5:1 against the
     DARKER stripe (#D4C0A1), not just the lighter one, because row labels
     land on both. #7A4A1C looked right and only reached 4.20 there. */
  --ink-soft:       #6E4016;  /* secondary copy on parchment. 4.92:1 on --parch */
  --muted:          #505050;  /* disabled / tertiary on parchment */
  --frame:          #5F4D41;  /* caption bars, 1px content frame */
  --ornament:       #793D03;  /* tooled leather band between sections */
  --stone:          #55636C;  /* 2px cold outer border. the metal. */
  --stone-lit:      #7C8B95;  /* lit edge of the stone */
  --hairline:       #000000;  /* hard outer terminating line */
  --bevel-shadow:   #8B7355;  /* the dark inner bevel on paper */

  /* --- Torchlight ----------------------------------------------------- */
  --gold:           #FFBB05;  /* highlight, active, the Oracle's voice */
  --gold-deep:      #CFA600;  /* secondary gold */
  --gold-ember:     #8A6402;  /* burnt gold, rules and dividers */
  --alert:          #EF0000;  /* warning, negative */

  /* --- Game client bars (classic C++ client) --------------------------- */
  --hp:             #FF2D2D;
  --mana:           #0000FF;
  --track:          #000000;

  /* --- Four stop severity ramp ----------------------------------------
     Lifted from the creature health line: green at 60 percent or more,
     yellow 30 to 60, red below 30, dark red near death. Reused here as
     "how exposed are you", so the ramp runs the other way: green is
     protected, dark red is uniquely marked.                              */
  --sev-safe:       #2FA84F;
  --sev-watch:      #E0B000;
  --sev-exposed:    #FF2D2D;
  --sev-marked:     #8C0000;

  /* --- The LOOK command prints green ----------------------------------- */
  --look-dark:      #17421C;  /* on parchment */
  --look-bright:    #59D97A;  /* on the dark field */
  --whisper:        #5FF7F7;  /* private message cyan */

  /* --- Type stacks. LOCAL FAMILIES ONLY. No webfonts, ever. ------------ */
  --face-display: "Palatino Linotype", "Book Antiqua", Palatino,
                  "URW Palladio L", "Liberation Serif", Georgia,
                  "Times New Roman", serif;
  --face-body:    Verdana, Geneva, "DejaVu Sans", Tahoma, Arial, sans-serif;
  --face-mono:    "DejaVu Sans Mono", "Liberation Mono", Consolas,
                  "Courier New", monospace;

  /* --- Metrics --------------------------------------------------------- */
  --tile:           32px;     /* the client renders 32x32 pixel tiles */
  --col-max:        1180px;   /* old-web centred column */
  --gap:            16px;
  --gap-s:          8px;
  --gap-l:          28px;

  /* --- Runtime properties (set by the renderer through the CSSOM) ------- */
  --fill:           0%;       /* on any .bar__fill */
  --torch:          1;        /* masthead ember intensity, 0 to 1 */
}


/* ==========================================================================
   02 BASE AND BACKDROP
   ========================================================================== */

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

html {
  /* The whole design is committed to night. There is no light variant:
     the Academy stair is not lit. color-scheme keeps form controls and
     scrollbars from being rendered pale by the browser. */
  color-scheme: dark;
  background: var(--night);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  font-family: var(--face-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--parch-light);
  background-color: var(--night);

  /* Layer order is top-first.
     1. vignette   -- the client's ambient light falloff in a cave
     2. torchlight -- a warm bloom from above the stair
     3. tile grid  -- a faint 32px lattice: this reads as "map" instantly
     4. base night colour                                                */
  background-image:
    radial-gradient(ellipse 150% 120% at 50% 38%,
                    rgba(6, 18, 34, 0) 0%,
                    rgba(6, 18, 34, 0.55) 62%,
                    rgba(3, 9, 18, 0.92) 100%),
    radial-gradient(ellipse 90% 55% at 50% -8%,
                    rgba(255, 187, 5, 0.075) 0%,
                    rgba(255, 187, 5, 0) 70%),
    repeating-linear-gradient(0deg,
                    rgba(85, 99, 108, 0.075) 0 1px,
                    rgba(85, 99, 108, 0) 1px var(--tile)),
    repeating-linear-gradient(90deg,
                    rgba(85, 99, 108, 0.075) 0 1px,
                    rgba(85, 99, 108, 0) 1px var(--tile));
  background-attachment: fixed;
  background-repeat: no-repeat, no-repeat, repeat, repeat;

  /* The page must never scroll sideways. Wide content scrolls inside its
     own .scroll-x container instead. clip is used rather than hidden so
     that position: sticky keeps working. */
  overflow-x: clip;
}

/* Everything sits in one centred old-web column. */
.wrap {
  width: 100%;
  max-width: var(--col-max);
  margin: 0 auto;
  padding: 0 var(--gap);
}

.band {
  padding: var(--gap-l) 0;
}

.band + .band { padding-top: var(--gap); }

/* Skip link. Visible the moment it takes focus, never before. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 99;
  padding: 10px 16px;
  background: var(--gold);
  color: #1A1000;
  font: 700 13px/1 var(--face-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  border: 2px solid var(--hairline);
}
.skip:focus {
  left: var(--gap);
  top: var(--gap);
}

/* Focus ring. Gold, square, unmistakable, and it never disappears under a
   panel border because it is offset outward. */
:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
/* Keyboard users get the ring; pointer users do not get a stuck one. */
:focus:not(:focus-visible) { outline: none; }

::selection {
  background: var(--gold);
  color: #1A1000;
}


/* ==========================================================================
   03 TYPOGRAPHY
   Square, dense, 2002. Verdana at small sizes for copy; a heavy local serif
   in small caps for anything that speaks.
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--face-display);
  font-weight: 700;
  margin: 0;
  line-height: 1.15;
  text-wrap: balance;
}

/* The wordmark. NOT the CipSoft logo -- an original setting of a heavy
   local serif in small caps, gold on night, with the client's hard 1px
   black outline and a burnt-gold rule beneath. */
.wordmark {
  font-family: var(--face-display);
  font-size: clamp(2.4rem, 9vw, 4.6rem);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow:
     1px  1px 0 var(--hairline),
    -1px -1px 0 var(--hairline),
     1px -1px 0 var(--hairline),
    -1px  1px 0 var(--hairline),
     0 0 24px rgba(255, 187, 5, 0.28);
  margin: 0;
}

.kicker {
  font-family: var(--face-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone-lit);
  margin: 0 0 6px;
}

/* A band heading: the section titles of the reading. */
.band__title {
  font-size: clamp(1.35rem, 4.4vw, 2.05rem);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--gold-deep);
  text-shadow: 1px 1px 0 var(--hairline);
  margin: 0;
}

.band__lead {
  max-width: 68ch;
  margin: 10px 0 0;
  color: #C7B9A2;
  font-size: 14px;
}

/* THE ORACLE'S VOICE.
   It speaks in full capitals. Always. This is the single most recognisable
   thing about it, so the type shouts by default. */
.oracle-speaks {
  font-family: var(--face-display);
  font-size: clamp(1.05rem, 3.4vw, 1.6rem);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow: 1px 1px 0 var(--hairline);
  margin: 0;
}

/* The same voice, spoken over parchment instead of over the dark. */
.oracle-speaks--ink {
  color: var(--ink);
  text-shadow: none;
}

.oracle-speaks--quiet {
  font-size: clamp(0.95rem, 2.6vw, 1.15rem);
  color: var(--gold-deep);
  letter-spacing: 0.12em;
}

/* The name the Oracle addresses you by. It uses your name in the very
   first breath, before it says anything else. */
.oracle-name {
  color: var(--parch-pale);
  border-bottom: 2px solid var(--gold-ember);
  padding-bottom: 1px;
}

p { margin: 0 0 0.9em; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--gold-deep);
  text-underline-offset: 2px;
}
a:hover { color: var(--gold); }

code, .mono, kbd, samp {
  font-family: var(--face-mono);
  font-size: 0.92em;
  font-variant-ligatures: none;
}

small { font-size: 12px; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ==========================================================================
   04 CHROME PRIMITIVES

   THE PANEL RECIPE, from canon:
     outer 1px solid #000 hairline
     then 2px solid #55636C stone border
     then 1px solid #FAF0D7 pale inner highlight
     then the #D4C0A1 parchment fill
     with a full width caption bar in #5F4D41 above the fill.

   All four layers are produced by one border plus two box-shadow rings, so
   no extra wrapper elements are needed and nothing shifts layout. The
   shadows have zero blur on purpose: in this idiom the third dimension
   comes from stacked hard 1px edges, never from a soft shadow.

   Corners are square everywhere. One rounded corner breaks the illusion.
   ========================================================================== */

.panel {
  position: relative;
  border: 2px solid var(--stone);
  border-radius: 0;
  background: var(--parch);
  color: var(--ink);
  box-shadow:
    0 0 0 1px var(--hairline),                 /* hard outer terminating line */
    inset 0 0 0 1px var(--parch-pale);         /* pale carved inner highlight */
  /* Grid children must be allowed to shrink or long values force the page
     sideways. This is the fix for that, and it must not be removed. */
  min-width: 0;
}

/* A panel drawn out of stone instead of paper: used for the dark chrome
   bands (masthead, divination, verdict) where the Oracle itself speaks. */
.panel--stone {
  background-color: var(--slate);
  background-image:
    repeating-linear-gradient(45deg,
      rgba(255, 255, 255, 0.022) 0 2px,
      rgba(0, 0, 0, 0.075) 2px 4px);
  color: var(--parch-light);
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 0 0 0 1px rgba(124, 139, 149, 0.55);
}

/* The caption bar that sits above every panel's fill. */
.panel__caption {
  display: flex;
  align-items: baseline;
  gap: var(--gap-s);
  flex-wrap: wrap;
  margin: 0;
  padding: 6px 10px;
  background: var(--frame);
  color: var(--parch-pale);
  border-bottom: 1px solid var(--hairline);
  font-family: var(--face-body);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.65);
}

.panel--stone > .panel__caption {
  background: var(--slate-hi);
  border-bottom-color: var(--hairline);
  box-shadow: inset 0 -1px 0 rgba(124, 139, 149, 0.35);
}

/* The caption's own title. Allowed to shrink and wrap so a long caption
   never pushes the bits pip off the panel. */
.panel__caption-text {
  min-width: 0;
  overflow-wrap: anywhere;
}

.panel__caption-note {
  margin-left: auto;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.08em;
  color: #D8CCB6;   /* 5.04:1 on --frame. #CDBFA6 only reached 4.42. */
  text-transform: none;
}

/* The magic-level pip on a caption: entropy contributed by this panel. */
.panel__bits {
  font-family: var(--face-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--gold);
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid rgba(0, 0, 0, 0.8);
  box-shadow: inset 0 0 0 1px rgba(255, 187, 5, 0.22);
  padding: 1px 6px;
  white-space: nowrap;
}

.panel__body { padding: 0; }
.panel__body--pad { padding: 12px; }

/* The ornament band: a tooled leather edge between content bands. */
.ornament {
  height: 6px;
  background-color: var(--ornament);
  background-image:
    repeating-linear-gradient(45deg,
      rgba(0, 0, 0, 0.42) 0 3px,
      rgba(255, 187, 5, 0.16) 3px 6px);
  box-shadow: 0 1px 0 var(--hairline), 0 -1px 0 var(--hairline);
  margin: var(--gap-l) 0;
}
.ornament--tight { margin: var(--gap) 0; }

/* A hard hairline separator. This idiom uses 1px rules where a modern
   design would use whitespace. */
.rule {
  height: 1px;
  background: var(--gold-ember);
  opacity: 0.5;
  margin: var(--gap) 0;
  border: 0;
}

/* THE GRAVESTONE.
   A parchment slab with small caps centred text and a thin frame. Modelled
   on the twelve gravestones east of the Rookgaard temple, whose real
   epitaphs are matter of fact and grim about a small pointless death.
   Used for short verdict cards. */
.slab {
  background: var(--parch);
  border: 1px solid var(--frame);
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 1px 1px 0 var(--parch-pale),
    inset -1px -1px 0 var(--bevel-shadow);
  color: var(--ink);
  padding: 14px 12px;
  text-align: center;
  min-width: 0;
}

.slab__title {
  font-family: var(--face-display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0 0 6px;
}

.slab__body {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0;
}

/* The inventory slot: a 34px square with an inset bevel and a dim
   silhouette when empty. Used as the rune slots in the divination. */
.slot {
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  background: var(--slate-lo);
  border: 1px solid var(--hairline);
  box-shadow:
    inset 1px 1px 0 rgba(0, 0, 0, 0.85),
    inset -1px -1px 0 rgba(124, 139, 149, 0.4);
  display: grid;
  place-items: center;
  image-rendering: pixelated;
}


/* ==========================================================================
   05 BARS AND METERS

   The classic client's bar: a flat rectangular track with a hard black
   background, a hard 1px dark border and a SOLID UNMODULATED FILL. No
   gradient, no rounded ends, no glow. The numbers sit as plain text beside
   the bar. Do not add a gradient to these.

   The fill width is driven by the --fill custom property so the renderer
   can size it through the CSSOM under a strict style-src CSP:
       bar.style.setProperty('--fill', '61.4%');
   ========================================================================== */

.bar {
  position: relative;
  height: 14px;
  background: var(--track);
  border: 1px solid var(--hairline);
  box-shadow: inset 0 0 0 1px rgba(124, 139, 149, 0.32);
  overflow: hidden;
}

.bar__fill {
  display: block;
  height: 100%;
  width: var(--fill, 0%);
  background: var(--gold);
  transition: width 260ms linear;
}

.bar--tall { height: 20px; }
.bar--thin { height: 8px; }

/* The status bar pair: red over blue, flat, numbers to the right. */
.bar--hp   .bar__fill { background: var(--hp); }
.bar--mana .bar__fill { background: var(--mana); }

/* The spellcasting / experience bar used during divination. The shimmer is
   the only motion on the page that is not opt-in, and it is removed under
   prefers-reduced-motion in section 16. */
.bar--exp .bar__fill {
  background: var(--gold-deep);
  background-image: repeating-linear-gradient(
    90deg,
    rgba(255, 187, 5, 0.95) 0 6px,
    rgba(207, 166, 0, 0.95) 6px 12px);
  background-size: 24px 100%;
  animation: exp-crawl 900ms linear infinite;
}

@keyframes exp-crawl {
  from { background-position: 0 0; }
  to   { background-position: 24px 0; }
}

/* Four stop severity ramp. Set data-sev on the .bar. */
.bar[data-sev="safe"]    .bar__fill { background: var(--sev-safe); }
.bar[data-sev="watch"]   .bar__fill { background: var(--sev-watch); }
.bar[data-sev="exposed"] .bar__fill { background: var(--sev-exposed); }
.bar[data-sev="marked"]  .bar__fill { background: var(--sev-marked); }

.meter {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;
}

.meter__label {
  grid-column: 1 / -1;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--stone-lit);
}

.meter__value {
  font-family: var(--face-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--gold);
  white-space: nowrap;
  text-shadow: 1px 1px 0 var(--hairline);
}


/* ==========================================================================
   06 BUTTONS AND THE LOOK AFFORDANCE

   LOOK is the in-game command that examines a thing and prints a green
   description of what it actually is. That is exactly the right verb for
   "show me how you know that", so every signal row carries one.
   ========================================================================== */

.btn {
  font-family: var(--face-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--parch-light);
  border: 1px solid var(--frame);
  border-radius: 0;
  padding: 4px 9px;
  cursor: pointer;
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 1px 1px 0 var(--parch-pale),
    inset -1px -1px 0 var(--bevel-shadow);
}

.btn:hover { background: var(--parch-pale); }

/* Pressed: the bevel inverts. This is the whole trick and it costs nothing. */
.btn:active,
.btn[aria-expanded="true"] {
  background: var(--parch-dim);
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 1px 1px 0 var(--bevel-shadow),
    inset -1px -1px 0 var(--parch-pale);
}

.btn--dark {
  color: var(--gold);
  background: var(--slate-hi);
  border-color: var(--stone);
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 1px 1px 0 rgba(124, 139, 149, 0.55),
    inset -1px -1px 0 rgba(0, 0, 0, 0.75);
}
.btn--dark:hover { background: #2C3D4A; }
.btn--dark:active,
.btn--dark[aria-expanded="true"] {
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 1px 1px 0 rgba(0, 0, 0, 0.75),
    inset -1px -1px 0 rgba(124, 139, 149, 0.55);
}

.btn--look {
  padding: 2px 7px;
  letter-spacing: 0.1em;
}

/* The green LOOK description. Hidden until its button is expanded. */
.look-note {
  display: none;
  grid-column: 1 / -1;
  margin: 6px 0 2px;
  padding: 8px 10px;
  background: var(--parch-pale);
  border: 1px solid var(--frame);
  box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.14);
  color: var(--look-dark);
  font-size: 13px;
  line-height: 1.5;
}

.look-note[data-open="true"] { display: block; }

.look-note__bits {
  display: block;
  margin-top: 6px;
  font-family: var(--face-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--muted);
}


/* ==========================================================================
   07 MASTHEAD / THE TEMPLE
   The Academy stair, the statue, and the greeting. The Oracle is not a
   person: it is an animate object, a statue, with a dead woman's spirit
   bound inside it. The art below is original angular SVG, not a sprite.
   ========================================================================== */

.temple {
  position: relative;
  padding: var(--gap-l) 0 var(--gap);
  border-bottom: 1px solid var(--gold-ember);
}

/* The torchlight bloom above the stair. --torch lets the renderer dim it.
   The inset stays at 0 horizontally: any negative left/right here is a
   horizontal overflow source, and the ellipse fades out well before the
   edges anyway, so the bleed bought nothing. */
.temple::before {
  content: "";
  position: absolute;
  inset: -20% 0 auto 0;
  height: 340px;
  pointer-events: none;
  background: radial-gradient(ellipse 60% 100% at 50% 0%,
              rgba(255, 187, 5, calc(0.13 * var(--torch))) 0%,
              rgba(255, 187, 5, 0) 72%);
  animation: torch-breathe 5.5s ease-in-out infinite alternate;
}

@keyframes torch-breathe {
  from { opacity: 0.78; }
  to   { opacity: 1; }
}

.temple__inner {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--gap-l);
  align-items: center;
}

.temple__statue {
  width: clamp(96px, 18vw, 168px);
  height: auto;
  display: block;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 18px rgba(255, 187, 5, 0.16));
}

/* The statue's eye. Gold, and it is looking at you. */
.statue-eye {
  fill: var(--gold);
  animation: eye-ember 3.4s ease-in-out infinite alternate;
}

@keyframes eye-ember {
  from { opacity: 0.55; }
  to   { opacity: 1; }
}

.statue-stone   { fill: #46545E; }
.statue-shadow  { fill: #2A353D; }
.statue-lit     { fill: #6E7D87; }
.statue-plinth  { fill: #38434B; }
.statue-halo    { fill: none; stroke: var(--gold-ember); stroke-width: 2; }

/* The fracture. The living Oracle was killed by Hellgorak; what reads you
   is her spirit bound inside a broken statue. The crack is the whole
   character of the figure, so it is drawn, not implied. */
.statue-crack {
  fill: none;
  stroke: #202A31;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.temple__words { min-width: 0; }

.temple__place {
  font-family: var(--face-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--stone-lit);
  margin: 0 0 4px;
}

.temple__greeting {
  margin: 14px 0 0;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.34);
  border-left: 4px solid var(--gold-ember);
  box-shadow: 0 0 0 1px var(--hairline);
}

.temple__sub {
  margin: 12px 0 0;
  max-width: 64ch;
  font-size: 14px;
  color: #C7B9A2;
}

/* The privacy promise, stated early because the page's whole premise is
   honesty about the mechanism. */
/* Self-contained on purpose. This used to also carry .inline-list, which is
   declared later in the file at equal specificity and reset margin to 0,
   silently eating the top margin. A modifier must never be a second
   single-class rule that lands later in the cascade. */
.creed {
  list-style: none;
  padding: 0;
  margin: var(--gap) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-s);
}

.creed__item {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--look-bright);
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid var(--stone);
  box-shadow: 0 0 0 1px var(--hairline);
  padding: 4px 9px;
}


/* ==========================================================================
   08 DIVINATION
   The progress state while the probes run, in the idiom of a spell being
   cast and an experience bar filling.
   ========================================================================== */

.divination__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--gap-s);
  margin-bottom: 10px;
}

.divination__status {
  font-family: var(--face-display);
  font-size: clamp(0.95rem, 2.8vw, 1.25rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow: 1px 1px 0 var(--hairline);
  margin: 0;
  min-height: 1.4em;   /* reserve the line so aria-live updates do not jump */
}

.divination__count {
  margin-left: auto;
  font-family: var(--face-mono);
  font-size: 12px;
  color: var(--stone-lit);
  white-space: nowrap;
}

/* The rite list: one row per probe group, each with a rune slot. */
.rites {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--gap-s);
}

.rite {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(85, 99, 108, 0.55);
  min-width: 0;
}

.rite__name {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #B9AB95;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The rune inside the slot. A blank rune is an empty stone: a signal not
   yet collected. It fills in as the rite completes. */
.rune {
  width: 18px;
  height: 18px;
  background: #2B3944;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.9);
  clip-path: polygon(30% 0, 70% 0, 100% 30%, 100% 70%,
                     70% 100%, 30% 100%, 0 70%, 0 30%);
}

.rite[data-state="casting"] .rune {
  background: var(--gold-deep);
  animation: rune-pulse 700ms ease-in-out infinite alternate;
}
.rite[data-state="done"]    .rune { background: var(--look-bright); }
.rite[data-state="failed"]  .rune { background: var(--sev-marked); }
.rite[data-state="blocked"] .rune { background: var(--whisper); }

.rite[data-state="done"]    .rite__name { color: var(--parch-light); }
.rite[data-state="failed"]  .rite__name { color: #C98A8A; }
.rite[data-state="blocked"] .rite__name { color: var(--whisper); }

@keyframes rune-pulse {
  from { opacity: 0.35; }
  to   { opacity: 1; }
}

/* Once the reading is complete the whole divination block steps aside. */
.divination[data-state="done"] .divination__body { display: none; }
.divination[data-state="done"] .divination__status { color: var(--look-bright); }


/* ==========================================================================
   09 READING SECTIONS AND SIGNAL ROWS
   ========================================================================== */

.band__head {
  margin-bottom: var(--gap);
}

.band__head .band__title::after {
  content: "";
  display: block;
  height: 3px;
  margin-top: 8px;
  max-width: 220px;
  background: var(--ornament);
  box-shadow: 0 1px 0 var(--hairline);
}

/* The panel grid. auto-fit with a min() floor so a single long value can
   never push the column wider than the viewport on a phone. */
.reading {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
  gap: var(--gap);
  align-items: start;
}

.reading--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 460px), 1fr));
}

/* --- Rows -----------------------------------------------------------------
   A list of {label, value, LOOK}. Striped light over mid, which is the
   single most recognisable tibia.com table pattern. Built from divs rather
   than a real table so that the row can reflow to two lines on a phone
   without losing its accessible name, and so the LOOK note can expand
   inside the row.
   -------------------------------------------------------------------------- */

.rows {
  list-style: none;
  margin: 0;
  padding: 0;
}

.row {
  display: grid;
  grid-template-columns: minmax(9ch, 15ch) 1fr auto;
  gap: 4px 10px;
  align-items: baseline;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(95, 77, 65, 0.34);
  min-width: 0;
}

.row:last-child { border-bottom: 0; }

.rows > .row:nth-child(odd)  { background: var(--parch-light); }
.rows > .row:nth-child(even) { background: var(--parch); }

.row__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  text-transform: uppercase;
  min-width: 0;
  overflow-wrap: anywhere;
}

.row__value {
  font-family: var(--face-mono);
  font-size: 13px;
  color: var(--ink);
  min-width: 0;
  /* Long hashes, UA strings and GPU renderer strings must wrap rather than
     widen the page. anywhere is deliberate: break mid token if needed. */
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Value flavours the renderer can set with a class. */
.row__value--unknown  { color: var(--muted); font-style: italic; }
.row__value--blocked  { color: var(--look-dark); font-weight: 700; }
.row__value--warn     { color: #8C2A00; font-weight: 700; }
.row__value--rare     { color: #6B2E8C; font-weight: 700; }

/* A rarity pip beside a value: how identifying THIS answer is. */
.row__bits {
  display: inline-block;
  margin-left: 6px;
  padding: 0 5px;
  font-family: var(--face-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--parch-pale);
  background: var(--frame);
  border: 1px solid var(--hairline);
  vertical-align: 1px;
  white-space: nowrap;
}
.row__bits[data-sev="safe"]    { background: #1F6B33; }
.row__bits[data-sev="watch"]   { background: #8A6A00; }
.row__bits[data-sev="exposed"] { background: #A31D1D; }
.row__bits[data-sev="marked"]  { background: var(--sev-marked); }

.row__look { justify-self: end; }

/* A row that is itself a whole block of text (a caveat, a verdict line).
   Written as .row.row--note so the responsive .row rules further down the
   file cannot re-impose a second column on it. */
.row.row--note {
  grid-template-columns: 1fr;
  font-size: 13px;
  color: var(--ink-soft);
}

/* --- Wide content --------------------------------------------------------
   Nothing wide is ever allowed to widen the page. It scrolls inside its
   own box, and the box announces itself as scrollable to a screen reader
   via tabindex="0" and a label in the markup.
   -------------------------------------------------------------------------- */

.scroll-x {
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--frame);
  box-shadow: inset 0 0 0 1px var(--parch-pale);
  background: var(--parch-light);
}

.scroll-x:focus-visible { outline-offset: -1px; }

/* The raw header block: an ordered, numbered list with the exact names as
   received. Honesty here is more impressive than a fake hash. */
.headers {
  margin: 0;
  padding: 10px 10px 10px 3.4em;
  font-family: var(--face-mono);
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink);
  min-width: max-content;
}

.headers li { padding-left: 4px; }
.headers li::marker { color: var(--muted); }

.headers .hdr-name  { font-weight: 700; color: var(--ink); }
.headers .hdr-sep   { color: var(--muted); }
.headers .hdr-value { color: var(--ink-soft); }

/* nginx generated headers are marked separately from what the client sent,
   because the difference is the entire point. */
.headers li[data-origin="server"] { opacity: 0.62; }
.headers li[data-origin="server"] .hdr-name::after {
  content: " (added by our server)";
  font-weight: 400;
  font-size: 11px;
  color: var(--muted);
}

/* A short inline tag used for verdicts like GREASE PRESENT. */
.tag {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--face-body);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid var(--hairline);
  background: var(--frame);
  color: var(--parch-pale);
  white-space: nowrap;
}
.tag--good { background: #1F6B33; }
.tag--warn { background: #8A6A00; }
.tag--bad  { background: #A31D1D; }
.tag--cold { background: #2F4A57; }

/* The sigil: the fingerprint hash itself, the one mark that identifies its
   bearer wherever it goes. Presented as a rune stone, not as a receipt. */
.sigil {
  display: grid;
  gap: 8px;
  padding: 14px;
  background: var(--slate-lo);
  border: 2px solid var(--stone);
  box-shadow:
    0 0 0 1px var(--hairline),
    inset 0 0 0 1px rgba(124, 139, 149, 0.4);
}

.sigil__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--stone-lit);
}

.sigil__value {
  font-family: var(--face-mono);
  font-size: clamp(0.95rem, 3.6vw, 1.5rem);
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--gold);
  overflow-wrap: anywhere;
  text-shadow: 1px 1px 0 var(--hairline);
}

.sigil__note {
  font-size: 12px;
  color: #A99C88;
  margin: 0;
}


/* ==========================================================================
   10 ENTROPY VERDICT
   Magic level is arcane advancement raised only by spending mana: it
   measures how much you have burned, not how much you hold. That is the
   right metaphor for bits of identifying entropy, so the verdict is dressed
   as a level readout.
   ========================================================================== */

.verdict {
  display: grid;
  grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
  gap: var(--gap-l);
  align-items: center;
  padding: var(--gap-l) var(--gap);
}

.verdict__figure {
  text-align: center;
  min-width: 0;
}

.verdict__bits {
  font-family: var(--face-display);
  font-size: clamp(3.4rem, 15vw, 6rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: 0.02em;
  color: var(--gold);
  text-shadow:
     1px  1px 0 var(--hairline),
    -1px -1px 0 var(--hairline),
     0 0 30px rgba(255, 187, 5, 0.3);
  display: block;
}

.verdict__unit {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--stone-lit);
}

.verdict__band {
  display: inline-block;
  margin-top: 12px;
  padding: 4px 12px;
  font-family: var(--face-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border: 1px solid var(--hairline);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
  background: var(--frame);
  color: var(--parch-pale);
}
.verdict__band[data-sev="safe"]    { background: #1F6B33; }
.verdict__band[data-sev="watch"]   { background: #8A6A00; color: #FFF3CF; }
.verdict__band[data-sev="exposed"] { background: #A31D1D; }
.verdict__band[data-sev="marked"]  { background: var(--sev-marked); }

.verdict__words { min-width: 0; }

.verdict__plain {
  font-family: var(--face-display);
  font-size: clamp(1.05rem, 3vw, 1.35rem);
  line-height: 1.4;
  color: var(--parch-pale);
  margin: 0 0 12px;
}

.verdict__crowd {
  font-family: var(--face-mono);
  font-size: 14px;
  color: var(--gold-deep);
  margin: 0 0 14px;
}

.verdict__meter { margin: 14px 0; }

/* The caveat is not small print. The entropy figures are NOT additive and
   the page says so where the number is, not in a footnote. */
.caveat {
  margin-top: var(--gap);
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.34);
  border-left: 4px solid var(--stone);
  box-shadow: 0 0 0 1px var(--hairline);
  font-size: 13px;
  line-height: 1.6;
  color: #BDB09B;
}

.caveat strong { color: var(--parch-pale); }

.caveat--good { border-left-color: var(--look-bright); }


/* ==========================================================================
   11 WHAT THE ORACLE CANNOT SEE
   The honest limits, set as gravestones. The real Rookgaard epitaphs are
   short and flat about a small pointless death; that register is exactly
   right for correcting an overstated claim.
   ========================================================================== */

.graveyard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--gap);
}

.grave .slab__title { color: #6B3A1A; }

.grave__claim {
  display: block;
  font-family: var(--face-display);
  font-size: 13px;
  font-style: italic;
  color: var(--muted);
  text-decoration: line-through;
  margin-bottom: 8px;
}


/* ==========================================================================
   12 FOOTER
   ========================================================================== */

.footer {
  margin-top: var(--gap-l);
  border-top: 1px solid var(--gold-ember);
  background: rgba(0, 0, 0, 0.3);
  padding: var(--gap-l) 0 calc(var(--gap-l) * 1.4);
  font-size: 13px;
  color: #A99C88;
}

.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: var(--gap-l);
}

.footer__title {
  font-family: var(--face-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--stone-lit);
  margin: 0 0 8px;
}

.footer p { margin: 0 0 0.7em; }

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

/* The nothing-was-stored statement gets its own weight. It is the single
   most important sentence on the page. */
.footer__promise {
  margin-top: var(--gap-l);
  padding: 14px;
  border: 1px solid var(--stone);
  box-shadow: 0 0 0 1px var(--hairline);
  background: rgba(0, 0, 0, 0.4);
  color: var(--look-bright);
  font-size: 13px;
  line-height: 1.6;
}

.footer__promise strong {
  display: block;
  font-family: var(--face-display);
  font-size: 15px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--look-bright);
  margin-bottom: 6px;
}

.disclaimer {
  margin-top: var(--gap);
  font-size: 12px;
  color: #877B6B;
  line-height: 1.6;
}


/* ==========================================================================
   13 PANEL STATES

   Every panel has one .panel__state element. Set data-state on the .panel:

     pending  the probes for this panel have not settled yet
     ready    normal, rows are shown
     empty    nothing to report, and that is a real answer
     failed   the probe threw, and the Oracle says so plainly
     blocked  a defence stopped it. THE DEFENCE WORKED. Never phrase this as
              a failure of the visitor's browser.

   The default wording for each state lives in CSS so it exists exactly once
   and cannot drift between twelve panels. The :empty guard means the
   renderer can override any of it with a specific reason simply by writing
   textContent into the element.
   ========================================================================== */

.panel__state {
  display: none;
  padding: 14px 12px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  background: var(--parch-light);
}

/* On a stone panel the state message must not appear as a slab of paper. */
.panel--stone .panel__state {
  background: rgba(0, 0, 0, 0.34);
  color: #A99C88;
}

.panel[data-state="pending"] .panel__body,
.panel[data-state="empty"]   .panel__body,
.panel[data-state="failed"]  .panel__body,
.panel[data-state="blocked"] .panel__body { display: none; }

.panel[data-state="pending"] .panel__state,
.panel[data-state="empty"]   .panel__state,
.panel[data-state="failed"]  .panel__state,
.panel[data-state="blocked"] .panel__state { display: block; }

.panel[data-state="pending"] .panel__state:empty::before {
  content: "The Oracle is still looking.";
  font-style: italic;
}
.panel[data-state="empty"] .panel__state:empty::before {
  content: "There was nothing here to read. That is an answer too.";
  font-style: italic;
}
.panel[data-state="failed"] .panel__state:empty::before {
  content: "The Oracle could not see this. The probe threw an error and was abandoned.";
  color: #8C2A00;
}
.panel[data-state="blocked"] .panel__state:empty::before {
  content: "Something you carry turned this reading aside. The ward held.";
  color: var(--look-dark);
  font-weight: 700;
}

.panel[data-state="blocked"] { border-color: #2F6B3C; }
.panel[data-state="failed"]  { border-color: #6B2F2F; }

/* A pending panel gets a faint crawl so it does not read as broken. */
.panel[data-state="pending"] .panel__state {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(95, 77, 65, 0.07) 0 8px,
    rgba(95, 77, 65, 0) 8px 16px);
}

/* Whole-band states, for the two big readings. */
.band[data-state="failed"] .band__lead::after {
  content: " The reading for this band did not complete.";
  color: #E08A8A;
}

.noscript {
  margin: var(--gap) 0;
  padding: 14px;
  background: var(--parch-light);
  color: var(--ink);
  border: 2px solid var(--stone);
  box-shadow: 0 0 0 1px var(--hairline), inset 0 0 0 1px var(--parch-pale);
  font-size: 13px;
  line-height: 1.6;
}


/* ==========================================================================
   14 UTILITIES
   ========================================================================== */

.pad     { padding: 12px; }
.stack   { display: grid; gap: var(--gap); }
.stack-s { display: grid; gap: var(--gap-s); }
.nowrap  { white-space: nowrap; }
.center  { text-align: center; }
.hidden  { display: none !important; }
.dim     { color: var(--muted); }
.pixel   { image-rendering: pixelated; }

.inline-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}


/* ==========================================================================
   15 RESPONSIVE
   The owner reads his own systems from a phone constantly, so the phone
   layout is the one that has to be right. Panels stack, rows go to two
   lines, and nothing ever scrolls the page sideways.
   ========================================================================== */

@media (max-width: 900px) {
  :root { --gap-l: 22px; }

  .verdict {
    grid-template-columns: 1fr;
    gap: var(--gap);
    text-align: center;
  }
  .verdict__words { text-align: left; }
}

@media (max-width: 620px) {
  body { font-size: 14px; }

  :root { --gap: 12px; --gap-l: 18px; --tile: 24px; }

  .temple__inner {
    grid-template-columns: 1fr;
    gap: var(--gap);
    justify-items: start;
  }
  .temple__statue { width: 108px; }

  /* Label above value, LOOK button pushed to its own line end. This keeps
     a 40-character GPU renderer string readable at 360px. */
  .row {
    grid-template-columns: 1fr auto;
    row-gap: 2px;
  }
  .row__label { grid-column: 1 / -1; }
  .row__value { grid-column: 1; }
  .row__look  { grid-column: 2; grid-row: 2; align-self: center; }

  .rites { grid-template-columns: 1fr; }

  .panel__caption {
    font-size: 11px;
    letter-spacing: 0.1em;
  }
  .panel__caption-note {
    margin-left: 0;
    flex-basis: 100%;
  }

  .headers { padding-left: 3em; font-size: 11px; }
}

/* Very narrow phones: give the LOOK button the full row rather than
   squeezing the value into four characters. */
@media (max-width: 380px) {
  .row { grid-template-columns: 1fr; }
  .row__look { grid-column: 1; grid-row: auto; justify-self: start; }
}


/* ==========================================================================
   16 REDUCED MOTION, FORCED COLORS, HIGH CONTRAST, PRINT
   ========================================================================== */

/* Every animation on this page is decorative. All of it goes. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .bar--exp .bar__fill {
    animation: none;
    background-image: none;
    background: var(--gold-deep);
  }

  .temple::before { animation: none; opacity: 0.9; }
  .statue-eye     { animation: none; opacity: 1; }
  .rite[data-state="casting"] .rune { animation: none; opacity: 1; }
}

/* Windows High Contrast and similar: stop painting, start outlining. */
@media (forced-colors: active) {
  .panel,
  .slab,
  .btn,
  .bar,
  .sigil,
  .scroll-x {
    border: 1px solid CanvasText;
    box-shadow: none;
  }
  .bar__fill { forced-color-adjust: none; background: Highlight; }
  .rune      { forced-color-adjust: none; }
  .skip:focus { border: 2px solid CanvasText; }
}

@media (prefers-contrast: more) {
  :root {
    --ink-soft: #5A2800;
    --muted:    #3B3B3B;
    --stone:    #8595A0;
  }
  .row { border-bottom-color: var(--frame); }
  .band__lead, .footer, .caveat { color: #DCD2C2; }
}

@media print {
  body {
    background: #FFFFFF;
    color: #000000;
    background-image: none;
  }
  .temple::before,
  .divination,
  .row__look,
  .skip { display: none !important; }

  .panel {
    background: #FFFFFF;
    box-shadow: none;
    border: 1px solid #000000;
    break-inside: avoid;
  }
  .rows > .row:nth-child(odd),
  .rows > .row:nth-child(even) { background: #FFFFFF; }
  .look-note { display: block !important; }
  .wordmark, .band__title, .verdict__bits { color: #000000; text-shadow: none; }
}
