/* Written by Irmak Hakman — 2026-10-15 14:25 */
/* Copyright (c) 2026 Irmak Hakman — SPDX-License-Identifier: BUSL-1.1 (see LICENSE) */

/* ============================================================================
   base.css - the primitives every redesigned page is built from.

   SCOPING: everything here is under html.lamplit. Pages opt in by putting
   class="lamplit" on the <html> element, so redesigned and not-yet-redesigned
   pages can coexist during the migration without fighting each other.

   It is on <html> and not <body> on purpose: applyTheme() assigns
   document.body.className wholesale, so a marker class on <body> would be
   wiped the moment a theme was applied.

   Load order: tokens.css, fonts.css, base.css, then the page stylesheet.
   ============================================================================ */

/* ── Reset ──────────────────────────────────────────────────────────────── */
html.lamplit *,
html.lamplit *::before,
html.lamplit *::after{box-sizing:border-box}

html.lamplit{
  background:var(--ink);
  color-scheme:dark;
  -webkit-text-size-adjust:100%;
}

:where(html.lamplit) body{
  margin:0;
  background:var(--ink);
  color:var(--bone);
  font-family:var(--ui);
  font-size:var(--t-base);
  line-height:1.5;
  font-synthesis-weight:none;
  -webkit-font-smoothing:antialiased;
}

/* Tabular figures everywhere by default. This app is mostly numbers that sit
   in columns - HP, AC, initiative, damage, prices - and proportional digits
   make them jitter as they change. */
:where(html.lamplit) body{font-variant-numeric:tabular-nums}

/* ── Type ───────────────────────────────────────────────────────────────── */
:where(html.lamplit) h1,
:where(html.lamplit) h2,
:where(html.lamplit) h3{
  font-family:var(--display);
  font-weight:600;
  font-variation-settings:'WONK' 1;
  line-height:1.15;
  letter-spacing:-.01em;
  margin:0;
  color:var(--bone);
}
:where(html.lamplit) h1{font-size:var(--t-2xl); font-variation-settings:'opsz' 96,'WONK' 1}
:where(html.lamplit) h2{font-size:var(--t-xl);  font-variation-settings:'opsz' 48,'WONK' 1}
:where(html.lamplit) h3{font-size:var(--t-lg);  font-variation-settings:'opsz' 24,'WONK' 1}

:where(html.lamplit) p{margin:0 0 var(--s3); max-width:68ch}

/* Section labels. Sentence case, not tracked-out caps. The rule does the
   separating; the word only names the thing. */
html.lamplit .lt-label{
  font-size:var(--t-sm);
  color:var(--ash);
  font-weight:600;
  margin:0 0 var(--s2);
}

:where(html.lamplit) a{color:var(--arc); text-underline-offset:2px}
:where(html.lamplit) a:hover{color:var(--arc-hi)}

/* ── Surfaces. Depth is a lamp above-left: a lit top edge and a soft
      falloff, not a grey drop shadow under a rounded box. ──────────────── */
html.lamplit .lt-panel{
  background:linear-gradient(color-mix(in srgb, var(--slate) 88%, var(--bone) 3%), color-mix(in srgb, var(--slate) 84%, var(--ink)));
  border:1px solid var(--rule);
  border-top-color:var(--rule-hi);
  border-radius:var(--r-md);
  box-shadow:inset 0 1px 0 var(--lift), var(--cast);
}
html.lamplit .lt-well{
  background:var(--sunken);
  border:1px solid var(--rule);
  border-radius:var(--r-md);
}

/* Hairlines, not boxes: prefer a rule between things over a border around
   each of them. */
html.lamplit .lt-rule{border:0; border-top:1px solid var(--rule); margin:var(--s4) 0}

/* ── Controls ───────────────────────────────────────────────────────────── */
:where(html.lamplit) button,
html.lamplit .lt-btn{
  font:inherit;
  font-weight:600;
  color:var(--bone);
  background:var(--slate);
  border:1px solid var(--rule-hi);
  border-radius:var(--r-sm);
  padding:var(--s2) var(--s3);
  min-height:calc(36px*var(--fs, 1));
  cursor:pointer;
  display:inline-flex;
  align-items:center;
  gap:var(--s2);
  transition:background .12s ease, border-color .12s ease;
}
:where(html.lamplit) button:hover,
html.lamplit .lt-btn:hover{background:var(--slate-hi)}

/* Primary = the thing that acts. Solid --arc always carries --ink text;
   bone on arc is about 2:1 and unreadable. */
html.lamplit .lt-btn-primary{
  background:var(--arc);
  border-color:var(--arc);
  color:var(--ink);
}
html.lamplit .lt-btn-primary:hover{background:var(--arc-hi); border-color:var(--arc-hi)}

/* Destructive is a wash with red text, never a solid red block. */
html.lamplit .lt-btn-danger{
  background:var(--blood-fill);
  border-color:var(--blood);
  color:var(--blood);
}
html.lamplit .lt-btn-danger:hover{background:color-mix(in srgb, var(--blood) 18%, transparent)}

html.lamplit .lt-btn-quiet{background:transparent; border-color:transparent; color:var(--ash)}
html.lamplit .lt-btn-quiet:hover{background:var(--slate); color:var(--bone)}

:where(html.lamplit) button:disabled,
html.lamplit .lt-btn:disabled{opacity:.5; cursor:default}

:where(html.lamplit) input:not([type=checkbox]):not([type=radio]),
:where(html.lamplit) select,
:where(html.lamplit) textarea{
  font:inherit;
  color:var(--bone);
  background:var(--sunken);
  border:1px solid var(--rule-hi);
  border-radius:var(--r-sm);
  padding:var(--s2) var(--s3);
  min-height:calc(36px*var(--fs, 1));
}
/* Checkboxes and radios are sized by the pages that use them; the 36px
   min-height above would otherwise stretch them into ovals. */
:where(html.lamplit) input[type=checkbox],
:where(html.lamplit) input[type=radio]{accent-color:var(--arc);cursor:pointer}

:where(html.lamplit) input::placeholder,
:where(html.lamplit) textarea::placeholder{color:var(--ash-dim)}

/* One visible focus treatment, everywhere, keyboard-first. */
html.lamplit :focus-visible{
  outline:2px solid var(--arc);
  outline-offset:2px;
  border-radius:var(--r-sm);
}

/* ── Icons. These replace 647 emoji: real strokes that inherit currentColor,
      so an icon in a disabled button actually looks disabled. ──────────── */
html.lamplit .lt-icon{
  width:1.15em; height:1.15em;
  flex:none;
  stroke:currentColor;
  fill:none;
  stroke-width:1.75;
  stroke-linecap:round;
  stroke-linejoin:round;
}

/* ============================================================================
   THE STATE RING - the one bold thing.

   Anything that can act wears a ring: a character, a monster token, an
   initiative row. The ring encodes live state so "who is up and how hurt are
   they" is readable across a room, and everything else on the page can stay
   quiet.

     --hp     0-100, drives the arc
     [data-state="active"]  it is this thing's turn
     [data-state="down"]    at 0 hp

   Usage:
     <span class="lt-ring" style="--hp:70"><img src="..." alt=""></span>
   ============================================================================ */
html.lamplit .lt-ring{
  /* thickness scales with the ring so a 32px initiative ring and a 56px
     portrait ring are equally readable */
  --ring-w:max(2.5px, calc(var(--ring-size, 44px) * .075));
  position:relative;
  display:inline-grid;
  place-items:center;
  width:var(--ring-size, calc(44px*var(--fs, 1)));
  height:var(--ring-size, calc(44px*var(--fs, 1)));
  border-radius:var(--r-full);
  flex:none;
}

/* the arc: a conic sweep masked into an annulus */
html.lamplit .lt-ring::before{
  content:'';
  position:absolute;
  inset:0;
  border-radius:var(--r-full);
  background:conic-gradient(
    var(--ring-color, var(--ash)) calc(var(--hp, 100) * 1%),
    var(--ring-track) 0);
  -webkit-mask:radial-gradient(farthest-side, #0000 calc(100% - var(--ring-w)), #000 calc(100% - var(--ring-w)));
          mask:radial-gradient(farthest-side, #0000 calc(100% - var(--ring-w)), #000 calc(100% - var(--ring-w)));
}

html.lamplit .lt-ring > img,
html.lamplit .lt-ring > .lt-ring-face{
  width:calc(100% - (var(--ring-w) * 2) - calc(3px*var(--fs, 1)));
  height:calc(100% - (var(--ring-w) * 2) - calc(3px*var(--fs, 1)));
  border-radius:var(--r-full);
  object-fit:cover;
  background:var(--slate);
  display:grid;
  place-items:center;
  font-size:var(--t-sm);
  color:var(--ash);
}

/* Colour is earned. A character at full health is in the DEFAULT state, not a
   notable one, so a healthy ring is neutral - it does not glow green. Red is
   spent only when something is actually wrong, which is what makes it carry
   across a room. The track stays visible at all times so the arc reads as a
   proportion rather than as a coloured circle. */
html.lamplit .lt-ring{
  --ring-color:var(--ash);
  --ring-track:#E8E1D426;
}
html.lamplit .lt-ring[data-hurt]{--ring-color:var(--blood-deep)}
/* Down is the most urgent state on the screen, so it differs in FORM and not
   only in how much red is showing: the face itself goes to blood, which
   nothing else on the page ever does. Side by side with a merely-hurt ring it
   is unmistakable at a glance. */
html.lamplit .lt-ring[data-state="down"]{
  --ring-color:var(--blood);
  --ring-track:var(--blood);
  --hp:100;
}
html.lamplit .lt-ring[data-state="down"] > img{filter:grayscale(1) brightness(.5)}
html.lamplit .lt-ring[data-state="down"] > .lt-ring-face,
html.lamplit .lt-ring[data-state="down"] > img{
  background:var(--blood-fill);
  color:var(--blood);
  box-shadow:inset 0 0 0 1px var(--blood);
}

/* Active: it is your turn. This is the ONE place --arc is allowed to glow. */
html.lamplit .lt-ring[data-state="active"]{
  box-shadow:0 0 0 2px var(--ink), 0 0 0 4px var(--arc), 0 0 16px -2px var(--arc-line);
}

/* Conditions ride the edge as notches rather than a row of pills, so the
   token stays the same size however many it has. */
html.lamplit .lt-ring-notches{
  position:absolute; inset:calc(var(--ring-w) * -2);
  border-radius:var(--r-full);
  pointer-events:none;
}

/* ── Modal chrome ────────────────────────────────────────────────────────────
   ONE definition of what a dialog looks like, for every page.

   `.ct` (the modal title bar) had drifted into five different looks: the
   display-font header below, a near-white --bone bar with dark centred 11px
   text on loot/merchant/monsters/treasury, and a --slate-hi bar that still
   carried --ink text on the table screen - dark navy on dark navy, which was
   barely legible. The container border had drifted the same way: a 1px
   --bone hairline (near-white, #E6EDF7) ringing a dark panel on six pages,
   against --rule-hi everywhere else. --rule-hi is the token that means "the
   edge of something raised", so that is what a modal gets.

   The ad-hoc header classes are listed alongside .ct rather than restyled
   one by one, so a dialog written on any page starts out matching.

   These live in base.css because every page links it, and they beat a plain
   page-level `.ct` on specificity (0,2,1 vs 0,1,0). Page stylesheets should
   only set a modal's SIZE from here on, never its colour or type. */
html.lamplit .modal-box,
html.lamplit .lt-modal-box{
  background:var(--slate);
  border:1px solid var(--rule-hi);
  border-radius:var(--r-md);
}

/* The type treatment: what a modal title reads like, wherever it sits. */
html.lamplit .ct,
html.lamplit .modal-hdr,
html.lamplit .dlg-hdr,
html.lamplit .ho-mo-hdr,
html.lamplit .cal-modal-title,
html.lamplit .lt-modal-title,
html.lamplit .lt-modal-hdr{
  background:none;
  color:var(--bone);
  font-family:var(--display);
  font-variation-settings:'opsz' 24,'WONK' 1;
  font-weight:600;
  font-size:var(--t-md);
  line-height:1.2;
  text-align:left;
}

/* The bar treatment, kept separate because not every title is a bar:
   .cal-modal-title is a heading INSIDE an already-padded box, so it takes the
   type above but must not grow its own padding and rule. */
html.lamplit .ct,
html.lamplit .modal-hdr,
html.lamplit .dlg-hdr,
html.lamplit .ho-mo-hdr,
html.lamplit .lt-modal-hdr{
  padding:var(--s3) var(--s3) var(--s2);
  border-bottom:1px solid var(--rule);
}
html.lamplit .cal-modal-title,
html.lamplit .lt-modal-title{margin:0 0 var(--s4)}

/* A title bar that also carries controls - a close button, a "Manage" link.
   Add alongside .ct; on its own .ct stays a plain title, which is what the
   character sheet's and DM screen's modals want. */
html.lamplit .ct.ct-row{
  display:flex;
  align-items:center;
  gap:var(--s2);
  justify-content:space-between;
}

/* Headers that carry a close button (or any trailing control) lay their
   contents out in a row; the ones that are just a title are unaffected. */
html.lamplit .modal-hdr,
html.lamplit .dlg-hdr,
html.lamplit .ho-mo-hdr{
  display:flex;
  align-items:center;
  gap:var(--s2);
}
html.lamplit .modal-hdr,
html.lamplit .ho-mo-hdr{justify-content:space-between}
/* The heading inside such a header is the header - it must not re-declare
   its own size, or it fights the rule above. */
html.lamplit .modal-hdr h3,
html.lamplit .ho-mo-hdr .ho-mo-title,
html.lamplit .ct .lt-modal-title{
  font:inherit;
  color:inherit;
  letter-spacing:inherit;
  margin:0;
}

/* ── Motion: one orchestrated moment, and only when it answers an action. ── */
@media (prefers-reduced-motion: reduce){
  html.lamplit *,
  html.lamplit *::before,
  html.lamplit *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
}
