/* ── LeaderPortrait ────────────────────────────────────────────────── */
.leader-portrait {
  /* Locked "lego": pol_leader_frame.png is painted by the ::before layer
     so image + caption sit INSIDE the frame (image in the upper photo
     well, caption in the lower caption band). The frame is brightness-
     lifted via a filter so it's visible on the dark stage backdrop
     without needing a separate lighter variant of the PNG. */
  position: relative;
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
  height: 100%; width: 100%;
  padding: 10px 12px 0 12px;
  border: none !important;
  background: none !important;
  box-shadow: none !important;
}
/* Frame as a real <img> — spans the whole container, brightness-lifted
   so the dark mod frame (RGB 43–73) reads against the black-gray stage.
   If this img errors or is missing, the broken-image glyph appears — a
   visible diagnostic instead of the silent failure mode of background-
   image + pseudo-elements. */
.lp-frame-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
  z-index: 0;
  /* Brightness/contrast lift is BAKED into pol_leader_frame_bright.png
     (via tools — the original mod PNG is RGB 43–73 which is invisible
     on the dark stage). Used to be `filter: brightness(1.6) contrast(1.15)`
     here, but html2canvas drops `filter` on <img> tags so the export
     PNG was missing the frame entirely. Pre-baked file solves both. */
  display: block;
}
.lp-frame {
  /* Photo well — plain black clipping box inside the frame outline.
     position: relative so it stacks above the ::before frame layer. */
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
  /* Unified interior colour — shows through only when no portrait is
     set; covered entirely once an image is uploaded. */
  background: var(--panel-interior);
  overflow: hidden;
  border: none;
}
.lp-image { width: 100%; height: 100%; object-fit: cover; display: block; }
.lp-empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim); font-size: 28px;
}
.lp-caption {
  /* Sits over the frame PNG's caption band — no own background.
     z-index:1 so it stacks above the ::before frame. */
  position: relative;
  z-index: 1;
  width: 100%;
  height: 52px;   /* matches the caption band in pol_leader_frame.png */
  padding: 6px 10px 8px;
  background: transparent;
  border: none;
  text-align: center;
  display: flex; flex-direction: column; justify-content: center;
  /* Safety net: if the auto-fit in leader-portrait.js can't land on a
     size that fits (very long name + min-font floor), clip overflow
     rather than bleed into the portrait photo above. */
  overflow: hidden;
}
.lp-name {
  font-family: var(--font-title);
  font-size: 17px; color: var(--text); line-height: 1.15;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-shadow: 0 1px 0 rgba(0,0,0,0.7);
}
.lp-position {
  font-size: 11.5px; color: var(--accent);
  text-transform: uppercase; letter-spacing: 2px;
  margin-top: 3px;
  font-weight: 600;
}

/* ── EventTitle — focus icon + metallic banner ────────────────────── */
.event-title {
  display: grid;
  grid-template-columns: 1fr 3fr;
  gap: 0;
  align-items: stretch;
  padding: 0;
  position: relative;
  width: 100%; height: 100%;
  /* Focus icons are allowed to render at full size and spill past the
     component's edges if they're bigger than the icon cell. Combined
     with the host's overflow override below. */
  overflow: visible;
  background:
    linear-gradient(180deg, #24272b 0%, #14171a 45%, #0b0d10 100%);
  border: 1px solid #5a5d61;
  box-shadow:
    inset 0 0 0 1px #16181b,
    inset 0 1px 0 rgba(255,255,255,0.06),
    inset 0 -1px 0 rgba(0,0,0,0.55),
    0 3px 8px rgba(0,0,0,0.55);
}
.et-icon-frame {
  /* Clean slate — plain dark backdrop, no tile. */
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  overflow: visible;
  background-color: #0f1114;
  border: none;
  border-right: 1px solid #2a2d31;
  padding: 0;
}
.et-icon {
  width: 100%; height: 100%;
  max-width: none; max-height: none;
  object-fit: contain;
  image-rendering: crisp-edges;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.9));
}

/* Title host is the one exception to the global host-clipping rule:
   focus icons can be taller than the title strip and the user wants
   them to spill out and sit on top of the spirits row below. */
#se-title-host { overflow: visible !important; }
.et-icon-empty {
  color: var(--text-dim); font-size: 26px; font-style: italic;
}
.et-text {
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center;
  padding: 10px 18px;
  min-width: 0;
}
.et-tag {
  font-size: 10px; color: var(--text-dim);
  letter-spacing: 2.5px;
  margin-bottom: 4px;
  text-transform: uppercase;
  font-weight: 600;
}
.et-primary {
  /* Bombardier is TNO's in-game headline font — perfect for the event title. */
  font-family: var(--font-title);
  font-size: 26px; color: var(--text); font-weight: 700;
  letter-spacing: 3px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.8), 0 0 14px rgba(212,210,202,0.15);
  line-height: 1.05;
}
.et-secondary {
  font-family: var(--font-title);
  font-size: 15px; color: var(--accent); font-style: italic;
  letter-spacing: 1.5px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.7);
  margin-top: 3px;
}

/* ── NationalSpirits ───────────────────────────────────────────────── */
.national-spirits {
  display: flex; flex-direction: column; gap: 0;
  /* Unified dark blue-grey interior — matches the rest of the dashboard
     chassis (relations rows, alliance cards, flag wells). */
  background: var(--panel-interior);
  /* Frame comes from the universal --frame-* system in
     superevent-layout.css — we used to zero it out with `border: none`
     back when this panel wanted a frameless black strip; now it joins
     the rest of the dashboard with the thick metal frame. */
  padding: 0;
  position: relative;
  height: 100%;
  overflow: hidden;
}
.ns-label {
  /* Metal-plate title bar with a subtle top-highlight bevel for depth.
     The gradient + inset highlight simulates light catching an actual
     machined strip rather than reading as a flat label. */
  background: linear-gradient(180deg, #2e3136 0%, #202327 100%);
  color: var(--text);
  font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 2px;
  font-weight: 700;
  padding: 7px 12px;
  border-bottom: 1px solid #3c3f43;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -1px 0 rgba(0, 0, 0, 0.4);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}
.ns-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 6px;
  padding: 8px;
  flex: 1;
}
.ns-slot {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 5px 4px;
  /* No slot background or border — spirits sit flush on the panel's
     pure-black interior. Matches the in-game look where icons float
     directly on the black backplate rather than on individual tiles. */
  background: transparent;
  border: none;
  box-shadow: none;
}
.ns-icon {
  width: 44px; height: 44px; object-fit: contain;
  image-rendering: crisp-edges;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.8));
}
.ns-icon.ns-empty {
  background: radial-gradient(circle at 30% 25%, #1e2024 0%, #08070a 80%);
  border: 1px dashed #2f3236;
}
.ns-caption {
  font-size: 10px; color: var(--text);
  text-align: center; line-height: 1.1;
  text-shadow: 0 1px 0 rgba(0,0,0,0.6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}

/* ── EconomicSystem ────────────────────────────────────────────────── */
/* Flex row: left side fills the available height with title pinned to
   the TOP-LEFT and the system label pinned to the BOTTOM-LEFT (flush
   against the panel's inner border). Icon sits on the right, centered. */
.economic-system {
  /* Stacked title + label on the left, icon on the right (DOM order
     preserved). Vertically centred — breathes better than the old
     space-between layout that stranded title and label at opposite
     ends of the panel. */
  display: flex;
  align-items: center;
  gap: 14px;
}
.es-icon-frame {
  flex: 0 0 auto;
  width: 52px; height: 52px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 30% 25%, #1e2024 0%, var(--panel-interior-lo) 80%);
  border: 1px solid var(--panel-border-strong);
  box-shadow:
    inset 0 0 8px rgba(0,0,0,0.8),
    inset 0 1px 0 rgba(255,255,255,0.04);
}
.es-icon { max-width: 42px; max-height: 42px; object-fit: contain; image-rendering: crisp-edges; }
.es-icon-empty { color: var(--text-dim); font-size: 18px; }
.es-left {
  flex: 1;
  min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
}
.es-title {
  font-size: 10.5px; color: var(--accent);
  text-transform: uppercase; letter-spacing: 2.2px; font-weight: 700;
  opacity: 0.85;
}
.es-label {
  font-family: var(--font-title);
  font-size: 18px; font-weight: 700;
  color: var(--text); line-height: 1.15;
  letter-spacing: 0.4px;
  text-shadow: 0 1px 0 rgba(0,0,0,0.7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── CountryInfoCard ───────────────────────────────────────────────── */
/* Monumental museum-plaque layout:
     row 1 — flag (framed) + "A.D. 2025" year stamp
     row 2 — engraved hairline divider
     row 3 — COUNTRY NAME, large tracked caps, flanked by hairlines
     row 4 — romanised native name (italic subtitle) if set
     row 5 — description, justified, with a small-caps first letter
             and a subtle warm-accent bar marking the paragraph */
.country-info-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 4px 2px;
}

/* ── Row 1: flag + year stamp ─────────────────────────────────────── */
.cic-head {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 14px;
  align-items: center;
  padding-bottom: 8px;
  /* Engraved divider below the head — thin highlight over a thin shadow
     reads as an etched line on machined metal. */
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}
.cic-flag-frame {
  width: 80px; height: 56px;
  padding: 0;
  background: var(--panel-interior);
  border-style: solid;
  border-width: 8px;
  border-color: transparent;
  border-image: var(--ui-tiled) 22 fill / 8px / 0 stretch;
  box-shadow:
    0 2px 6px rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.cic-flag { width: 100%; height: 100%; object-fit: cover; display: block; }

.cic-year {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 0;
  text-align: right;
}
.cic-year-label {
  font-size: 9.5px;
  color: var(--text-dim);
  letter-spacing: 3.5px;
  text-transform: uppercase;
  font-weight: 600;
  line-height: 1;
  margin-bottom: 2px;
}
.cic-year-value {
  font-family: var(--font-title);
  font-size: 30px;
  font-weight: 700;
  /* Warm brass-gold tint — matches the ruling-party italic caption
     accent token and reads as an engraved monumental stamp rather
     than plain white text. */
  color: var(--accent-warm, #b79a55);
  letter-spacing: 4px;
  line-height: 1;
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.75),
    0 0 18px rgba(183, 154, 85, 0.25);
  font-variant-numeric: tabular-nums;
}

/* ── Row 2–3: country name with flanking hairlines ────────────────── */
.cic-name-native {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  font-family: var(--font-title);
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 4px;
  text-transform: uppercase;
  padding: 2px 0 3px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}
/* Flanking hairlines either side of the name — scale with whatever
   width is left over after the text, so short ("USA") and long
   ("United Arab Republic") names both look balanced. */
.cic-name-native::before,
.cic-name-native::after {
  content: '';
  flex: 1 1 20px;
  height: 1px;
  max-width: 80px;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(212, 210, 202, 0.32) 50%,
    transparent 100%
  );
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
}
.cic-name-native:empty { display: none; }

.cic-name-roman {
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--accent-dim, #8a8a82);
  font-style: italic;
  letter-spacing: 1px;
  text-align: center;
  margin-top: -2px;
  margin-bottom: 2px;
}
.cic-name-roman:empty { display: none; }

/* ── Row 5: description with small-caps first letter ──────────────── */
.cic-description {
  position: relative;
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--text);
  line-height: 1.5;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
  padding: 8px 2px 2px 10px;
  margin-top: 2px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.45);
  /* Left accent bar — marks the block as a formal "citation" / plaque
     description. Matches the warm brass of the year stamp. */
  border-left: 2px solid rgba(183, 154, 85, 0.4);
}
.cic-description::first-letter {
  font-family: var(--font-title);
  font-size: 1.6em;
  font-weight: 700;
  color: var(--accent-warm, #b79a55);
  padding-right: 2px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}
.cic-description:empty { display: none; }

/* ── MusicPlayer ──────────────────────────────────────────────────── */
.music-player {
  /* Cover fills the component's height as a square; text + controls
     stack vertically in the remaining space. Looks right whether the
     host is 80px tall (small) or 140px+ (like the TNO in-game reference). */
  display: flex;
  gap: 14px;
  align-items: stretch;
}
.mp-cover {
  aspect-ratio: 1 / 1;
  height: 100%;
  min-width: 68px;
  max-width: 140px;
  background: radial-gradient(circle at 30% 25%, #24272b 0%, var(--panel-interior-lo) 85%);
  border: 1px solid var(--panel-border-strong);
  display: flex; align-items: center; justify-content: center;
  position: relative;
  box-shadow: inset 0 0 10px rgba(0,0,0,0.8);
  flex-shrink: 0;
}
.mp-cover-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mp-cover-note {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 34px; color: var(--accent); pointer-events: none;
  text-shadow: 0 1px 2px rgba(0,0,0,0.7);
}
.mp-text {
  flex: 1;
  display: flex; flex-direction: column;
  gap: 4px; min-width: 0;
  justify-content: center;
  padding: 2px 0;
}
.mp-row { display: flex; gap: 10px; align-items: baseline; min-width: 0; }
.mp-key {
  font-size: 11.5px;
  color: var(--accent);
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  flex-shrink: 0;
  min-width: 48px;
  opacity: 0.85;
}
.mp-val {
  font-size: 15px;
  color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font-title);
  font-weight: 600;
  letter-spacing: 0.3px;
}
.mp-controls {
  display: flex;
  gap: 3px;
  margin-top: auto;
  padding-top: 4px;
}
.mp-controls button {
  min-width: 36px; height: 28px;
  padding: 0 4px;
  /* Beveled metal button: top-highlight + bottom-shadow + outer drop */
  background: linear-gradient(180deg, #3a3d41 0%, #1b1d20 50%, #0f1114 100%);
  border: 1px solid var(--panel-border-strong);
  color: var(--accent);
  font-size: 13px;
  border-radius: 2px;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset 0 -1px 0 rgba(0,0,0,0.5),
    0 1px 2px rgba(0,0,0,0.4);
  transition: filter 0.1s, background 0.1s;
}
.mp-controls button:hover {
  filter: brightness(1.15);
  color: #fff;
}
.mp-controls button:active {
  background: linear-gradient(180deg, #0f1114 0%, #050608 100%);
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.8);
}

/* ── Newspaper — shared tokens ─────────────────────────────────────── */
/* Colour + type variables used by both the composite panel and the
   decomposed pieces. Tweak in one place to reshade the whole widget. */
:root {
  --np-paper:       #c6c3b8;  /* base newsprint — cool grey-tan, not parchment */
  --np-ink:         #1a1a17;  /* body text */
  --np-ink-dim:     #53504a;  /* captions, date lines, sub-masthead */
  --np-rule:        #3a3834;  /* horizontal + column rules */
  --np-rule-hair:   rgba(58, 56, 52, 0.55);  /* secondary hairline */
}

/* ── NewspaperPanel (legacy composite — kept for back-compat) ─────── */
.newspaper-panel {
  background-color: var(--np-paper) !important;
  background-image: var(--ui-news-bg) !important;
  background-size: 100% 100% !important;
  background-repeat: no-repeat !important;
  border: none !important;
  color: var(--np-ink) !important;
  padding: 34px 32px 36px !important;
  font-family: var(--font-body);
  box-shadow: 0 6px 18px rgba(0,0,0,0.6), 0 0 0 1px rgba(0,0,0,0.15) inset !important;
}

/* ── NewspaperPiece — decomposed news sub-components ──────────────── */
/* Each piece is its own top-level stage component (own host div). They
   sit on top of the paper piece but aren't nested inside it — user can
   drag them anywhere. `group: 'news'` in the registry tags them. */

.np-piece-paper {
  /* ── Aged-newsprint texture — pseudo-free, export-faithful ──────────
     Previously used three inline-SVG turbulence layers + two pseudo
     elements (::before fold crease, ::after corner wear) with
     background-blend-mode + mix-blend-mode. Both renderers in the PNG
     export path (html-to-image, html2canvas) had gaps with that stack
     — SVG filters and blend modes rendered inconsistently.

     Current approach:
       1. --np-paper-noise: a tileable PNG of the three noise layers,
          rasterised ONCE at module load from an inline SVG (see
          newspaper-piece.js → initPaperTexture). Just a PNG — every
          renderer handles it identically.
       2. Vignette, fold crease, and corner-wear are plain CSS radial /
          linear gradients stacked above the noise in the same
          background-image list. Standard alpha compositing (no blend
          modes) — darkens the paper proportionally to each gradient's
          opacity. html2canvas and html-to-image both render these
          correctly.
       3. Base --np-paper colour shows through the transparent bits.
     No pseudo-elements, no filters, no blend modes. Exports 1:1. */
  background-color: var(--np-paper);
  background-image:
    /* Corner wear — small darker stamps at three corners. */
    radial-gradient(circle at 100% 100%, rgba(30,30,28,0.14) 0%, rgba(30,30,28,0) 18%),
    radial-gradient(circle at 0%   100%, rgba(30,30,28,0.12) 0%, rgba(30,30,28,0) 16%),
    radial-gradient(circle at 100% 0%,   rgba(30,30,28,0.08) 0%, rgba(30,30,28,0) 12%),
    /* Fold crease — one soft diagonal band across the sheet. */
    linear-gradient(98deg,
      rgba(0,0,0,0)      0%,
      rgba(0,0,0,0)      48%,
      rgba(30,30,28,0.06) 50%,
      rgba(0,0,0,0)      52%,
      rgba(0,0,0,0)      100%),
    /* Vignette — lighter upper-centre, darker edges. */
    radial-gradient(ellipse 130% 100% at 50% 20%,
      rgba(0,0,0,0) 45%,
      rgba(30,30,28,0.10) 80%,
      rgba(30,30,28,0.22) 100%),
    /* Noise PNG — set by newspaper-piece.js once rasterised.  The
       fallback (`none`) just disables the layer if the rasterise fails
       so the paper still renders as a solid tan. */
    var(--np-paper-noise, none);
  background-size:
    100% 100%, 100% 100%, 100% 100%,   /* corner stamps (all stretched) */
    100% 100%,                          /* fold crease */
    100% 100%,                          /* vignette */
    480px 480px;                        /* tiled noise */
  background-repeat:
    no-repeat, no-repeat, no-repeat,
    no-repeat,
    no-repeat,
    repeat;
  box-shadow:
    0 6px 18px rgba(0,0,0,0.55),
    0 1px 3px rgba(0,0,0,0.35),
    inset 0 0 0 1px rgba(30, 30, 28, 0.18),
    inset 0 0 60px rgba(40, 40, 36, 0.10);
}

/* All text pieces inherit the newspaper serif + paper-dark text.
   The inner .np-body / .np-headline fills the ENTIRE host so an empty
   text field is still clickable for inline editing (otherwise the padding
   would belong to the wrapper and the click would miss the editable). */
.np-piece-headline,
.np-piece-body {
  font-family: var(--font-body);
  color: var(--np-ink);
  background: transparent;
  padding: 0;
  overflow: hidden;
}
.np-piece-headline .np-headline,
.np-piece-body .np-body {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 4px 8px;
  margin: 0;
}
.np-piece-body .np-body {
  overflow-y: auto;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
  line-height: 1.45;
}
/* Drop cap in the SAME serif as the body — no display-font switch. The
   lead-in reads as a natural enlargement of the first letter, not a
   bolted-on widget. */
.np-piece-body .np-body::first-letter {
  float: left;
  font-family: inherit;
  font-weight: 700;
  font-size: 2.6em;
  line-height: 0.95;
  color: var(--np-ink);
  padding: 3px 6px 0 0;
}
.np-piece-headline .np-headline {
  /* Classic banner headline: serif body font, centred, single hairline
     beneath. Used to have a display font + double-rule trick — both
     looked bolted on against the rest of the paper. */
  text-align: center;
  font-family: var(--font-body);
  font-weight: 700;
  line-height: 1.14;
  color: var(--np-ink);
  padding-bottom: 4px;
  border-bottom: 1px solid var(--np-rule-hair);
}

/* Logo + image pieces: no bg, just a transparent container with the
   <img> inside filling it. */
.np-piece-logo,
.np-piece-image {
  background: transparent;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.np-piece-logo .np-logo {
  max-width: 100%; max-height: 100%;
  width: 100%;
  object-fit: contain;
  /* Mimic hand-inked masthead bleed: slight darken + tiny soft drop. */
  filter: contrast(1.08) drop-shadow(0 1px 0 rgba(0,0,0,0.25));
}
/* Image piece: thin dark frame + gentle newsprint photo grading. The
   previous version multiplied a paper-texture overlay on top via a
   ::before pseudo with mix-blend-mode — dropped to keep this pseudo-
   free and to render identically across every PNG export path (neither
   html2canvas nor html-to-image handle mix-blend-mode reliably). */
.np-piece-image {
  box-shadow:
    inset 0 0 0 1px var(--np-rule),
    0 2px 6px rgba(0,0,0,0.25);
}
.np-piece-image .np-image {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Gentle newsprint grading: partial desaturation + a nudge of contrast,
     no sepia (sepia on a modern photo reads as fake Instagram filter). */
  filter: grayscale(0.25) contrast(1.04);
}

/* Masthead stacks vertically: logo (or text fallback) → optional sub
   (date/issue). The article headline sits BELOW the masthead block
   and acts as the news title. Flanking rules give it the classic
   newspaper nameplate look (thick–thin sandwich). */
.np-masthead {
  display: flex; flex-direction: column; align-items: center;
  padding-top: 4px;
  padding-bottom: 10px;
  margin-bottom: 14px;
  gap: 4px;
  border-top: 4px double var(--np-rule);
  border-bottom: 3px solid var(--np-rule);
  position: relative;
}
.np-masthead::after {
  /* Hairline 2px below the thick bottom rule — newspaper "double rule". */
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -4px;
  border-bottom: 1px solid var(--np-rule);
}
.np-masthead-main {
  font-size: 38px; font-weight: 900;
  letter-spacing: 1.5px;
  font-family: var(--font-blackletter);
  color: #1a1408;
  text-shadow: 0 1px 0 rgba(255,255,255,0.15);
  text-align: center;
  padding: 4px 0 2px;
}
.np-logo {
  /* Prominent title image — fills the masthead's width minus some padding.
     Tune the max-height here if the panel height changes a lot. */
  width: 100%;
  max-width: 100%;
  max-height: 110px;
  object-fit: contain;
  display: none;
  filter: contrast(1.08) drop-shadow(0 1px 0 rgba(0,0,0,0.2));
}
.np-masthead-sub {
  font-size: 11px;
  color: var(--np-ink-dim);
  font-style: italic;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.np-headline {
  font-family: var(--font-body);
  font-size: 26px; font-weight: 700; line-height: 1.14;
  color: var(--np-ink); margin: 2px 0 10px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--np-rule-hair);
}
.np-image-wrap {
  margin: 0 0 8px;
  background: var(--np-ink);
  overflow: hidden;
  box-shadow:
    inset 0 0 0 1px var(--np-rule),
    0 2px 6px rgba(0,0,0,0.25);
}
.np-image {
  width: 100%; height: auto; display: block;
  filter: grayscale(0.25) contrast(1.04);
  transform-origin: center;  /* zoom + pan pivots around the image center */
  will-change: transform;
}
.np-caption {
  font-size: 10.5px;
  color: var(--np-ink-dim);
  font-style: italic;
  margin-bottom: 8px;
  padding: 2px 4px;
  border-left: 2px solid var(--np-rule-hair);
}
.np-body {
  font-size: 13px;
  line-height: 1.5;
  color: var(--np-ink);
  column-count: 1;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.np-body::first-letter {
  float: left;
  font-family: inherit;
  font-size: 2.6em;
  line-height: 0.95;
  font-weight: 700;
  padding: 3px 6px 0 0;
}

/* ── RelationsPanel ───────────────────────────────────────────────── */
.relations-panel { display: flex; flex-direction: column; gap: 6px; }
.rp-title {
  /* Crisp tracked overline — matches the heading rhythm of the rest of
     the dashboard. The thin accent rule underneath sells the
     "section heading" read at a glance. */
  font-size: 10.5px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 2px; font-weight: 700;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
}
.rp-rows { display: flex; flex-direction: column; gap: 3px; }
.rp-row {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 8px;
  align-items: center;
  /* Reverted to the original compact padding — the previous bump
     (4px 8px) made rows taller and pushed the last entry past the
     panel's fixed height. */
  padding: 3px 6px;
  /* Uses the unified --panel-interior colour so every card, slot and
     well across the dashboard reads as the same chassis material. */
  background: linear-gradient(180deg, var(--panel-interior) 0%, var(--panel-interior-lo) 100%);
  border: 1px solid var(--panel-border);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
.rp-icon { width: 20px; height: 20px; object-fit: contain; image-rendering: crisp-edges; }
.rp-icon-empty { background: var(--panel-interior); border: 1px dashed #2f3236; }
.rp-caption { font-size: 11.5px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-value {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: 0.5px;
}
.rp-pos  { color: #8bc97a; }
.rp-neg  { color: #e26b5a; }
.rp-zero { color: var(--text-dim); }

/* ── AlliancePanel ────────────────────────────────────────────────── */
.ap-row { display: flex; gap: 8px; flex-wrap: wrap; }
.ap-card {
  display: grid; grid-template-columns: 36px 1fr; gap: 8px;
  align-items: center; flex: 1 1 0; min-width: 0;
  padding: 7px 10px;
  background: linear-gradient(180deg, var(--panel-interior) 0%, var(--panel-interior-lo) 100%);
  border: 1px solid var(--panel-border);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
.ap-icon { width: 32px; height: 32px; object-fit: contain; image-rendering: crisp-edges; }
.ap-icon-empty { background: var(--panel-interior); border: 1px dashed #2f3236; }
.ap-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ap-role {
  font-size: 9.5px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 1.5px; font-weight: 700;
}
.ap-name {
  font-family: var(--font-title);
  font-size: 13px; font-weight: 700; color: var(--accent); letter-spacing: 0.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ap-sub { font-size: 10px; color: var(--text-dim); }

.cb-button {
  padding: 9px 22px;
  font-family: var(--font-title);
  font-size: 14px;
  letter-spacing: 1.5px;
  background: linear-gradient(180deg, #24272b 0%, #14171a 100%);
  color: var(--text);
  border: 1px solid var(--panel-border-strong);
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 2px 4px rgba(0,0,0,0.4);
}
.cb-button:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: linear-gradient(180deg, #2f3236 0%, #1e2024 100%);
}
