/* css/cards-mode.css — Cards mode (full-page) + card chrome + print rules.
 *
 * Layout
 *   #cards-mode owns the whole viewport when active.
 *   `.cards-shell` is a 2-column flex split: a fixed-width settings rail
 *   on the left + a flexible preview pane on the right.
 *
 * Card sizing
 *   Card widths/heights/font sizes are all in millimetres so the on-
 *   screen preview matches the printed output 1:1. The preview wraps
 *   each `.dcc-page` in a `.dcc-page-frame` whose own width and height
 *   are scaled (fit-to-viewport) and which clips the transformed child.
 *
 * Print
 *   Both "Print" and "Save as PDF" use the browser's native print
 *   dialog. The JS adds `body.cards-printing` and injects a `@page` rule
 *   with the chosen size; the `@media print` block at the bottom of
 *   this file hides everything except the cards and unwraps the
 *   preview transforms so each page prints at full physical size.
 */

/* ── Mode container ─────────────────────────────────────────────────────── */
#cards-mode { padding: 0; }
#cards-mode.mode-page { background: #0c0d10; }
.cards-mode-host {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.cards-shell {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  height: calc(100vh - 64px);  /* topbar height; gracefully degrades if smaller */
  background: #0c0d10;
  color: #e7e9ee;
}

/* ── Settings rail ──────────────────────────────────────────────────────── */
.cards-side {
  width: 340px;
  flex-shrink: 0;
  background: #14171c;
  border-right: 1px solid #23272e;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.cards-side-head {
  padding: 14px 18px 8px;
  border-bottom: 1px solid #23272e;
}
.cards-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.cards-summary {
  margin: 4px 0 0;
  font-size: 12px;
  color: #9aa1ad;
}
.cards-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  border-radius: 4px;
  font-size: 13px;
  cursor: pointer;
  user-select: none;
  color: #d8dde6;
}
.cards-row:hover { background: #1c1f25; }
.cards-row input[type="checkbox"] { accent-color: var(--accent, #c8c8c8); }

.cards-row-all { font-size: 13px; color: #cdd1d8; }
.cards-field { display: flex; flex-direction: column; gap: 4px; padding: 0 18px; }
.cards-field-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #8c92a0;
}
.cards-row-section { padding: 10px 18px; }
.cards-row { padding: 6px 18px; }

.cards-select {
  background: #0f1115;
  color: #e7e9ee;
  border: 1px solid #2e323a;
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 13px;
  width: 100%;
  cursor: pointer;
}

/* Top-level sub-tabs (Pick cards / Display) */
.cards-subtabs {
  display: flex;
  gap: 4px;
  padding: 12px 14px 8px;
  border-bottom: 1px solid #23272e;
  margin-top: 12px;
}
.cards-subtab {
  flex: 1 1 0;
  background: transparent;
  border: 1px solid #2e323a;
  color: #b9bec8;
  padding: 7px 8px;
  font-size: 13px;
  border-radius: 6px;
  cursor: pointer;
}
.cards-subtab:hover { background: #1f232a; color: #fff; }
.cards-subtab.is-active {
  background: var(--accent, #c8c8c8);
  color: var(--accent-on, #111);
  border-color: transparent;
  font-weight: 600;
}

.cards-side-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 6px 4px 12px;
}

/* Inner category tabs (Units / Rules / Stratagems) inside Pick cards */
.cards-cat-tabs {
  display: flex;
  gap: 2px;
  padding: 4px 14px 8px;
  border-bottom: 1px solid #1f232a;
  margin-bottom: 4px;
}
.cards-cat-tab {
  flex: 1 1 0;
  background: transparent;
  border: 0;
  color: #9aa1ad;
  padding: 6px 4px;
  font-size: 12px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  display: flex; flex-direction: column;
  align-items: center; gap: 2px;
}
.cards-cat-tab:hover { color: #fff; }
.cards-cat-tab.is-active {
  color: #fff;
  border-bottom-color: var(--accent, #c8c8c8);
}
.cards-cat-count {
  font-size: 10px;
  color: #6f7682;
  font-weight: 500;
}
.cards-cat-tab.is-active .cards-cat-count { color: var(--accent, #c8c8c8); }

.cards-list-head {
  padding: 4px 8px;
  border-bottom: 1px solid #1f232a;
  margin-bottom: 6px;
}
.cards-list { list-style: none; padding: 0; margin: 0; }
.cards-list li { margin: 0; }

/* Display sub-panel groups */
.cards-disp-group { margin-bottom: 10px; padding: 0 6px; }
.cards-disp-heading {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
  color: #8c92a0;
  padding: 4px 12px;
  margin-top: 6px;
  border-bottom: 1px solid #1f232a;
}
.cards-layout-section {
  padding: 8px 6px 14px;
  border-bottom: 1px solid #1f232a;
}
.cards-layout-section:last-child { border-bottom: 0; }
.cards-layout-section .cards-field { padding: 4px 12px 0; margin-top: 6px; }
.cards-help {
  font-size: 11px;
  line-height: 1.4;
  color: #8c92a0;
  margin: 4px 12px 6px;
}

/* Texture picker (inside the Layout sub-tab) */
.cards-textures {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 8px 12px 0;
}
.cards-texture {
  aspect-ratio: 1 / 1;
  border-radius: 4px;
  border: 1px solid #2e323a;
  cursor: pointer;
  position: relative;
  padding: 0;
  overflow: hidden;
  /* Inset gold ring helps the swatch read as a card sample. */
  box-shadow: inset 0 0 0 1px rgba(184, 144, 82, 0.3);
}
.cards-texture:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(184, 144, 82, 0.55);
}
.cards-texture.is-active {
  border-color: var(--accent, #b89052);
  box-shadow: 0 0 0 2px var(--accent, #b89052);
}
.cards-texture-label {
  position: absolute;
  inset: auto 0 0 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.78) 100%);
  color: #fff;
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 12px 4px 3px;
  text-align: center;
  line-height: 1.1;
  pointer-events: none;
}

/* Template picker (inside the Layout sub-tab) — taller "card-shaped"
 * swatches that preview each template's header band + body palette. */
.cards-templates {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  padding: 8px 12px 0;
}
.cards-template {
  aspect-ratio: 3 / 4;
  border-radius: 4px;
  border: 1px solid #2e323a;
  cursor: pointer;
  position: relative;
  padding: 0;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(184, 144, 82, 0.3);
}
.cards-template:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(184, 144, 82, 0.55);
}
.cards-template.is-active {
  border-color: var(--accent, #b89052);
  box-shadow: 0 0 0 2px var(--accent, #b89052);
}
.cards-template-label {
  position: absolute;
  inset: auto 0 0 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.82) 100%);
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 14px 4px 4px;
  text-align: center;
  line-height: 1.1;
  pointer-events: none;
}

/* Border-colour controls (inside the Layout sub-tab) */
.cards-color {
  width: 100%;
  height: 32px;
  padding: 2px;
  background: #0f1115;
  border: 1px solid #2e323a;
  border-radius: 6px;
  cursor: pointer;
}
.cards-swatches {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 8px 12px 0;
}
.cards-swatch {
  height: 32px;
  border-radius: 4px;
  border: 1px solid #2e323a;
  cursor: pointer;
  position: relative;
  padding: 0;
  /* Subtle inset gold ring so cream/white swatches stay visible against
   * the dark sidebar. */
  box-shadow: inset 0 0 0 1px rgba(184, 144, 82, 0.25);
}
.cards-swatch:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(184, 144, 82, 0.4);
}
.cards-swatch.is-active {
  border-color: var(--accent, #b89052);
  box-shadow: 0 0 0 2px var(--accent, #b89052);
}
.cards-swatch.is-active::after {
  content: '✓';
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0,0,0,0.7);
}

/* Card-back form controls */
.cards-file {
  width: 100%;
  font-size: 12px;
  color: #b9bec8;
  background: #0f1115;
  border: 1px solid #2e323a;
  border-radius: 6px;
  padding: 6px;
  cursor: pointer;
}
.cards-range {
  width: 100%;
  accent-color: var(--accent, #b89052);
  cursor: pointer;
}
.cards-slider-val {
  margin-left: 6px;
  color: #cdd1d8;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.04em;
}

/* Saved-image library (under Card backs) */
.cards-img-section {
  margin-top: 8px;
  border-top: 1px solid #1f232a;
  padding-top: 6px;
}
.cards-img-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 4px 12px 0;
}
.cards-img-thumb {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 4px;
  border: 1px solid #2e323a;
  overflow: hidden;
  cursor: pointer;
  background: #0f1115;
  /* Subtle gold ring like the swatches. */
  box-shadow: inset 0 0 0 1px rgba(184, 144, 82, 0.2);
}
.cards-img-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.cards-img-thumb:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(184, 144, 82, 0.45);
}
.cards-img-thumb.is-active {
  border-color: var(--accent, #b89052);
  box-shadow: 0 0 0 2px var(--accent, #b89052);
}
.cards-img-thumb.is-active::after {
  content: '✓';
  position: absolute;
  top: 2px; left: 4px;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,0.85);
}
.cards-img-del {
  position: absolute;
  top: 2px; right: 2px;
  width: 18px; height: 18px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(0,0,0,0.7);
  color: #fff;
  font-size: 14px;
  line-height: 16px;
  font-weight: 700;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s;
}
.cards-img-thumb:hover .cards-img-del { opacity: 1; }
.cards-img-del:hover { background: #b32020; }
.cards-link-btn {
  background: transparent;
  border: 0;
  color: var(--accent, #c8c8c8);
  font-size: 12px;
  padding: 4px 12px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.cards-link-btn:hover { color: #fff; }

/* Footer: print button */
.cards-side-foot {
  padding: 12px 18px 16px;
  border-top: 1px solid #23272e;
  background: #14171c;
}
.cards-btn {
  width: 100%;
  background: #20232a;
  color: #e7e9ee;
  border: 1px solid #2e323a;
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.cards-btn:hover { background: #2a2e36; }
.cards-btn-primary {
  background: var(--accent, #c8c8c8);
  color: var(--accent-on, #111);
  border-color: transparent;
}
.cards-btn-primary:hover { background: var(--accent-hover, #e0e0e0); }

/* ── Preview pane ───────────────────────────────────────────────────────── */
.cards-preview-wrap {
  flex: 1 1 auto;
  overflow: auto;
  background: #0c0d10;
  padding: 24px;
  display: flex;
  justify-content: center;
}
.cards-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.cards-empty {
  padding: 24px;
  text-align: center;
  color: #888c95;
  font-size: 13px;
}
.cards-empty-large {
  padding: 64px 24px;
  font-size: 15px;
  color: #aab0bc;
}

/* ── Page (one printable sheet, always 1:1) ─────────────────────────────── */
.dcc-page {
  /* Width/height are set INLINE by JS in mm. CSS only handles cosmetics
   * and grid behaviour. */
  box-sizing: border-box;
  background: #ffffff;
  color: #111;
  display: grid;
  /* grid-template-columns/rows + padding + gap also set inline by JS */
}
/* Pretty drop shadow only in preview */
.cards-preview .dcc-page { box-shadow: 0 6px 24px rgba(0,0,0,0.45); }

/* The preview wraps each .dcc-page in a frame that scales it to fit.
 * Width and height are scaled, transform: scale on the inner page. The
 * frame clips the overflow created by transform-origin. */
.dcc-page-frame {
  --dcc-preview-scale: 0.55;
  width:  calc(var(--dcc-page-w, 100mm) * var(--dcc-preview-scale));
  height: calc(var(--dcc-page-h, 100mm) * var(--dcc-preview-scale));
  overflow: hidden;
  position: relative;
  /* The preview pane is a flex column inside an `overflow:auto` parent.
   * Without flex-shrink:0 the column squashes every frame proportionally
   * when total content exceeds the viewport (2 cards => half-height each,
   * 3 => third, etc). Pin the frames at their physical size and let the
   * parent scroll. */
  flex: 0 0 auto;
}
.dcc-page-frame > .dcc-page {
  transform: scale(var(--dcc-preview-scale));
  transform-origin: top left;
}
/* Per-preset preview scale — keyed off the page width var on the frame. */
.dcc-page-frame[style*="--dcc-page-w: 215.9mm"],
.dcc-page-frame[style*="--dcc-page-w: 210mm"]   { --dcc-preview-scale: 0.6; }
.dcc-page-frame[style*="--dcc-page-w: 152.4mm"] { --dcc-preview-scale: 0.85; }
.dcc-page-frame[style*="--dcc-page-w: 101.6mm"] { --dcc-preview-scale: 1.0; }

/* ── Card chrome ─────────────────────────────────────────────────────────
 * Sized in mm so the on-screen preview matches print 1:1. Visual style
 * cribbed from 10e GW datasheets — but with a grimdark texture pass:
 * - aged-parchment background with subtle dark grain (inline SVG noise)
 * - radial vignette for warmth at the corners
 * - metallic gradient on the title bar with a thin gold accent rule
 * - ornamental triangular flourish below the title
 * - faint embossed border to suggest a metal frame
 *
 * Everything is inline (no external assets) so it survives the print
 * pipeline. SVG noise: feTurbulence in dark sepia, low alpha, locked
 * via stitchTiles so adjacent cards tile cleanly.
 */

.dcc-card {
  /* Background, border-radius, and typography multipliers (--dcc-*-mul)
   * are owned by the JS-injected <style id="cards-texture-style">. The
   * fallbacks below only apply if cards-mode.js never gets to inject
   * the rule (graceful degradation). Radius default 4mm matches a
   * physical R4 corner-cutter. */
  background: #ecdfb9;
  border-radius: 4mm;
  color: #1c1308;
  --dcc-stat-mul: 1;
  --dcc-w-mul: 1;
  --dcc-body-mul: 1;
  --dcc-fine-mul: 1;
  border: 0.4mm solid #1a140a;
  /* Dual-layer border: outer dark + inner thin gold to read as a
   * gilded frame. The inset ring is a box-shadow so it doesn't take
   * extra layout space. */
  box-shadow:
    inset 0 0 0 0.2mm #b89052,
    inset 0 0 0 0.45mm rgba(0,0,0,0.18);
  box-sizing: border-box;
  /* Content padding = base inset + the borderless "safe margin" (--dcc-safe,
   * injected by cards-mode.js, default 0). Pushes text/data inward while the
   * card background still fills to the edge — for borderless overprint. */
  padding: calc(1.6mm + var(--dcc-safe, 0mm)) calc(2mm + var(--dcc-safe, 0mm));
  display: flex;
  flex-direction: column;
  gap: 1.2mm;
  overflow: hidden;
  position: relative;
  font-family: 'Cinzel', 'Times New Roman', serif;
}
.dcc-card-empty {
  background: transparent !important;
  border: 0.3mm dashed #c8b890;
  box-shadow: none;
}

/* Card backs (duplex-print) */
.dcc-card-back {
  /* Reuse the gilded frame from .dcc-card; just strip the parchment
   * texture and let the user-uploaded image fill the cell. */
  padding: 0;
  background: #ecdfb9;
  display: block;
  position: relative;
  overflow: hidden;
}

/* ── Continuation cards (overflow spillover) ────────────────────────────
 * When a unit's text doesn't fit, splitOverflowingUnitCards() emits a
 * second card with class `dcc-card-cont`. The parchment overlay is sized
 * to its content (height: auto via flex flow) and pinned to the top of
 * the card; the rest of the cell shows either the user-set card-back
 * image (if `dcc-card-cont-art` is also set) or the page border colour
 * showing through. The friend's "art continues" idea, basically.
 */
.dcc-card-cont {
  /* Strip the card padding — the .dcc-cont-overlay handles its own. The
   * gilded frame box-shadow inherited from .dcc-card stays. The
   * !important on background beats the JS-injected
   * `.dcc-card { background: <texture> }` rule that's appended at
   * runtime — the article itself must be transparent so the back image
   * shows through. The parchment lives on .dcc-cont-overlay. */
  padding: 0;
  background: transparent !important;
  background-blend-mode: normal !important;
  position: relative;
  overflow: hidden;
}
.dcc-card-cont .dcc-cont-bg {
  /* Same pin/scale rig as the duplex back image, but full-cell behind
   * the overlay (z-index 0) so the parchment overlay (z-index 1) covers
   * just the top portion. */
  position: absolute;
  top: 50%;
  left: 50%;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  transform-origin: center;
  transform:
    translate(calc(-50% + var(--dcc-back-x, 0%)),
              calc(-50% + var(--dcc-back-y, 0%)))
    scale(var(--dcc-back-scale, 1));
  z-index: 0;
  pointer-events: none;
}
.dcc-card-cont .dcc-cont-overlay {
  /* Parchment overlay — same look as a regular .dcc-card body. The
   * JS-injected dynamic stylesheet targets this selector too so the
   * active texture preset, intensity, and corner radius all apply. */
  position: relative;
  z-index: 1;
  padding: calc(1.6mm + var(--dcc-safe, 0mm)) calc(2mm + var(--dcc-safe, 0mm));
  display: flex;
  flex-direction: column;
  gap: 1.2mm;
  /* height: auto — only as tall as needed. */
  /* Soften the bottom edge so the boundary feels designed, not clipped. */
  border-bottom-left-radius: inherit;
  border-bottom-right-radius: inherit;
  box-shadow: 0 2mm 3mm rgba(0,0,0,0.18);
}
/* When there's no user back image, the continuation card's bottom area
 * just shows the page background. Add a faint horizontal rule at the
 * overlay's bottom edge so the boundary still reads. */
.dcc-card-cont:not(.dcc-card-cont-art) .dcc-cont-overlay {
  border-bottom: 0.4mm solid #1a140a;
}
/* "Continued" header tag — small italicised marker the renderer adds to
 * the cloned header on the continuation card. */
.dcc-head-cont::after {
  content: ' (cont.)';
  font-style: italic;
  font-weight: 400;
  opacity: 0.7;
  font-size: 0.75em;
}
.dcc-back-img {
  /* Pinned to the centre of the cell, then translated by (offsetX,
   * offsetY) % and scaled. Container clips overflow so high scales
   * crop cleanly. */
  position: absolute;
  top: 50%;
  left: 50%;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  transform-origin: center;
  transform:
    translate(calc(-50% + var(--dcc-back-x, 0%)),
              calc(-50% + var(--dcc-back-y, 0%)))
    scale(var(--dcc-back-scale, 1));
  user-select: none;
  pointer-events: none;
}

/* Metallic title bar with a subtle horizontal sheen + gold accent rule. */
.dcc-head {
  background:
    linear-gradient(180deg,
      #0b0b0b 0%,
      #1c1c1c 30%,
      #292929 50%,
      #1c1c1c 70%,
      #0b0b0b 100%);
  color: #f4ead2;
  padding: 1.2mm 1.6mm;
  /* Default falls back to a noticeable rounding so the bar reads as
   * "tab-shaped" if cards-mode.js never gets to inject its dynamic
   * --dcc-head-radius. The Layout sub-tab's "Header corners" slider
   * controls the live value. */
  border-radius: var(--dcc-head-radius, 3mm);
  margin: -0.6mm -0.6mm 0;
  position: relative;
  box-shadow: 0 0.2mm 0 #5a4a22 inset, 0 -0.2mm 0 rgba(255,255,255,0.06) inset;
}
/* Gold accent stripe immediately under the header. */
.dcc-head::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -0.6mm;
  height: 0.5mm;
  background: linear-gradient(90deg,
    rgba(184,144,82,0)   0%,
    #b89052              15%,
    #e7c87a              50%,
    #b89052              85%,
    rgba(184,144,82,0)   100%);
}
/* Tiny triangular flourish hanging below the gold stripe — reads as a
 * stamped seal / banner pendant. */
.dcc-head::before {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -1.5mm;
  width: 2.4mm;
  height: 1mm;
  margin-left: -1.2mm;
  background: linear-gradient(135deg, #b89052 25%, transparent 25%) -0.6mm 0,
              linear-gradient(225deg, #b89052 25%, transparent 25%)  0.6mm 0;
  background-size: 1.2mm 1mm;
  background-repeat: no-repeat;
  pointer-events: none;
}
.dcc-name-line { display: flex; align-items: baseline; gap: 1.6mm; }
.dcc-name {
  font-family: 'Cinzel', 'Times New Roman', serif;
  font-weight: 700;
  font-size: calc(4.56mm * var(--dcc-name-mul, 1));
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin: 0;
  flex: 1 1 auto;
  line-height: 1.05;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Sits on the dark header bar in every template — same printer hairline
   * dropout as the section labels, and Cinzel caps at a 600 weight so 700 is
   * already faux-bold. Thicken the strokes so the unit/stratagem name prints
   * solid. See `.dcc-section-label`. */
  -webkit-text-stroke: 0.12mm currentColor;
  text-stroke: 0.12mm currentColor;
  paint-order: stroke fill;
}
.dcc-pts {
  background: var(--accent-dark, #b3b3b3);
  color: #fff;
  font-weight: 600;
  font-size: 2.6mm;
  padding: 0.4mm 1.4mm;
  border-radius: 0.6mm;
  white-space: nowrap;
}
.dcc-sub-line {
  display: flex; align-items: center; gap: 1.6mm;
  font-size: calc(2.86mm * var(--dcc-sub-mul, 1));
  margin-top: 0.6mm;
  color: #d8d8d2;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.dcc-role { opacity: 0.85; }
.dcc-inv {
  background: #b32020;
  color: #fff;
  padding: 0.2mm 1mm;
  border-radius: 0.6mm;
  font-weight: 600;
  font-size: 2.2mm;
  margin-left: auto;
}
.dcc-strat-phase { margin-left: auto; opacity: 0.85; }
/* Stratagem subtitle (CORE / FACTION / DETACHMENT STRATAGEM + PHASE: …)
 * is the only header label that has to fight a busy bronze CP pill for
 * attention, so it gets weight 700 unconditionally. Rule + unit
 * subtitles stay at the .dcc-sub-line default weight. */
.dcc-head-strat .dcc-sub-line { font-weight: 700; }

/* Stratagem CP pill.
 * Pinned to the header's top-right corner via absolute positioning. It used
 * to sit inline in .dcc-name-line (margin-left:auto), but that line is
 * baseline-aligned and the pill is a two-row column flex (num over "CP") —
 * its first row floated well above the name's baseline, inflating the line
 * height and shoving the subtitle down. Anchoring it removes the pill from
 * flow entirely so the name + subtitle keep their natural spacing; the
 * name-line gets right padding below so long names ellipsize clear of it. */
.dcc-head-strat .dcc-cp {
  position: absolute;
  top: 1.2mm;
  right: 1.6mm;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  background: #b32020;
  border-radius: 0.6mm;
  padding: 1.04mm 2.07mm;
  line-height: 1;
  color: #fff;
}
.dcc-head-strat .dcc-name-line { padding-right: 15mm; }
/* In the stencil template the header bleeds to the card edge — its content
 * padding folds in the borderless safe margin (--dcc-safe). The CP pill is
 * positioned against the header's padding box (the card edge), so it must
 * inset by that same base+safe amount, otherwise it prints into the trim on a
 * borderless sheet. (The default template's header only bleeds a fixed 0.6mm,
 * so the base 1.2mm/1.6mm offsets already clear the safe area there.) */
.dcc-tpl-stencil .dcc-head-strat .dcc-cp {
  top:   calc(1.6mm + var(--dcc-safe, 0mm));
  right: calc(2mm + var(--dcc-safe, 0mm));
}
.dcc-cp-num { font-size: 6.91mm; font-weight: 700; }
.dcc-cp-lbl { font-size: 2.76mm; opacity: 0.85; letter-spacing: 0.06em; }

/* Stat strip */
.dcc-stats {
  display: grid;
  grid-template-columns: repeat(var(--dcc-stat-cols, 6), 1fr);
  gap: 0.6mm;
  margin-top: 0.6mm;
}
/* Per-statline label for multi-profile units (Beast Snagga Boy vs Nob,
   etc.). Sits just above its stat row; only emitted when a card has
   more than one statline. Scales with the stat-block typography slider
   via --dcc-stat-mul so it tracks the row it labels. */
.dcc-stat-rowlabel {
  font-size: calc(2.0mm * var(--dcc-stat-mul, 1));
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #5a3f1a;
  margin: 0.9mm 0 0.2mm;
}
.dcc-stat-rowlabel:first-child { margin-top: 0.3mm; }
.dcc-stat-cell {
  background: linear-gradient(180deg, #1a1308 0%, #2a1f0e 100%);
  color: #f4ead2;
  /* Driven by the "Stat blocks" slider in Layout > Corner rounding. */
  border-radius: var(--dcc-stat-radius, 1mm);
  padding: 0.6mm 0.4mm;
  text-align: center;
  display: flex; flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: inset 0 0 0 0.1mm #6a4f1f;
}
.dcc-stat-key {
  font-size: calc(2.85mm * var(--dcc-stat-mul, 1));
  font-weight: 600;
  letter-spacing: 0.06em;
  /* Was 0.85 — printed text reads better full-opacity. */
  opacity: 0.95;
}
.dcc-stat-val {
  font-size: calc(5.4mm * var(--dcc-stat-mul, 1));
}
/* Combined SV/invuln cell — the value reads "2+ / 4++", which is wider
 * than a standalone "2+", so we shrink the value font and tighten letter
 * spacing to keep it inside the cell. */
.dcc-stat-val-combo {
  font-size: calc(3.6mm * var(--dcc-stat-mul, 1)) !important;
  letter-spacing: -0.02em;
  white-space: nowrap;
  font-weight: 700;
  margin-top: 0.4mm;
}

/* Section blocks (weapons, abilities, wargear, footers) */
.dcc-section { display: flex; flex-direction: column; }
.dcc-section-head {
  /* Bronze-bar look: dark base with a thin gold edge top + bottom. */
  background: linear-gradient(180deg, #2a1f0e 0%, #1a1308 100%);
  color: #f0e4c4;
  /* RANGED WEAPONS / MELEE WEAPONS / ABILITIES / WARGEAR / etc.
   * scale with their own "Section heads" typography slider —
   * separate from "Fine print" so users can pump the labels without
   * also bumping the footer-keywords line. */
  font-size: calc(2.47mm * var(--dcc-heading-mul, 1));
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.6mm 1.4mm;
  border-radius: var(--dcc-head-section-radius, 0.4mm) var(--dcc-head-section-radius, 0.4mm) 0 0;
  display: flex;
  align-items: center;
  gap: 1.2mm;
  box-shadow:
    inset 0 0.15mm 0 #6a4f1f,
    inset 0 -0.15mm 0 #6a4f1f;
}
.dcc-section-cols {
  margin-left: auto;
  /* Cancel the section-head's 1.4mm right padding so the column block's
     right edge meets the weapons table's right edge below it; without this
     every letter sits ~1.4mm left of the values it labels. */
  margin-right: -1.4mm;
  display: grid;
  /* Must match .dcc-w-table's fixed columns exactly (Range widest, Damage
     next, the other four narrow) so each header letter sits centred over
     its column of values. Total = 36mm = the table's stat region. */
  grid-template-columns: 8mm 5.5mm 5.5mm 5.5mm 5.5mm 6mm;
  gap: 0;
  width: 36mm;
  text-align: center;
  /* Same base size as `.dcc-section-head` (2.47mm) and same multiplier
   * (--dcc-heading-mul) so the title and column-abbreviation halves
   * of the bar render identically and stay baseline-aligned at any
   * scale. The earlier 1.75mm base + --dcc-fine-mul split made one
   * side jitter behind the other when the user moved either slider. */
  font-size: calc(2.47mm * var(--dcc-heading-mul, 1));
  opacity: 0.95;
}
.dcc-section-label {
  flex: 0 0 auto;
  /* The section labels (RANGED WEAPONS / MELEE WEAPONS / …) print light-on-dark
   * in every template — a bronze bar in the default look, a solid ink block in
   * the stencil look. Cinzel only ships up to a 600 weight, so font-weight:700
   * is already as heavy as the face goes; printers still drop the skinniest
   * serif strokes against the dark background. A small same-colour text-stroke
   * thickens every stroke uniformly so the thin parts survive the print, and
   * `paint-order: stroke fill` keeps the fill on top so letter counters stay
   * open rather than filling in. */
  -webkit-text-stroke: 0.12mm currentColor;
  text-stroke: 0.12mm currentColor;
  paint-order: stroke fill;
}

/* Weapons table */
.dcc-w-table {
  width: 100%;
  border-collapse: collapse;
  /* Fixed layout so the stat columns are exactly the widths declared on
     .dcc-num* below (not content-driven) — that's what lets the header
     letters in .dcc-section-cols line up over their values. The name
     column takes the remaining width. */
  table-layout: fixed;
  font-size: calc(2.86mm * var(--dcc-w-mul, 1));
}
.dcc-w-table tr { border-bottom: 0.15mm solid rgba(60, 40, 16, 0.32); }
.dcc-w-table tr:last-child { border-bottom: none; }
/* A weapon's stat row and its full-width keyword row are one entry: drop the
   divider between them so the rule only falls below the keywords. */
.dcc-w-table tr.dcc-w-row.has-kw { border-bottom: none; }
.dcc-w-table td { padding: 0.7mm 0.4mm; vertical-align: top; }
/* Full-width keyword row — spans name + all stat columns, indented to line up
   under the weapon name, with no top padding so it tucks under the stat row. */
.dcc-w-kwcell { padding-top: 0 !important; padding-left: 1.4mm !important; }
.dcc-w-name { font-weight: 600; padding-left: 1.4mm !important; }
.dcc-w-kw {
  font-style: italic;
  font-size: calc(2.405mm * var(--dcc-w-mul, 1));
  color: #5a3f1a;
  margin-top: 0.2mm;
  font-weight: 400;
}
.dcc-num {
  text-align: center;
  width: 5.5mm;
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
/* Range (e.g. `Melee`, `48"`) and Damage (`D6+2`) carry the widest values;
   widths here sum with the four 5.5mm stat columns to the 36mm region that
   .dcc-section-cols mirrors. */
.dcc-num-range { width: 8mm; }
.dcc-num-dmg   { width: 6mm; }

/* Primarch section — gold-rich gradient + thicker rims so the
 * choose-from-N abilities read as a distinct "pick two" block at a
 * glance, separate from the always-on ABILITIES list above. */
.dcc-section-head-primarch {
  background: linear-gradient(180deg, #b89052 0%, #8a6a2a 50%, #5a3f1a 100%) !important;
  color: #fff8e0 !important;
  letter-spacing: 0.12em !important;
  box-shadow:
    inset 0 0.25mm 0 #f0d68a,
    inset 0 -0.25mm 0 #3a2710 !important;
  text-shadow: 0 0.1mm 0.15mm rgba(0,0,0,0.6);
}
.dcc-abilities-primarch {
  /* A faint gold rule along the top edge of the body to extend the
   * header's accent into the content. */
  position: relative;
}
.dcc-abilities-primarch .dcc-abilities-body {
  border-top: 0.2mm solid rgba(184, 144, 82, 0.6);
}

/* Abilities */
.dcc-abilities-body {
  padding: 0.8mm 1.4mm;
  font-size: calc(2.52mm * var(--dcc-body-mul, 1));
  line-height: 1.3;
  color: #1a1a1a;
}
.dcc-ability-row {
  margin-bottom: 1.0mm;
  /* Preserves \n line breaks inserted by formatStructuredText() so
   * primarch / hero abilities with multi-option text read as a list,
   * not a wall. */
  white-space: pre-line;
}
.dcc-ability-row:last-child { margin-bottom: 0; }
.dcc-ability-row strong { color: #000; }
.dcc-core-row { color: #3a3a3a; font-size: calc(2.4mm * var(--dcc-body-mul, 1)); white-space: normal; }

/* Wargear options */
.dcc-wargear-body {
  padding: 0.8mm 1.4mm;
  font-size: calc(2.46mm * var(--dcc-body-mul, 1));
  line-height: 1.3;
  color: #1a1a1a;
}
.dcc-wargear-line { margin-bottom: 0.4mm; }
.dcc-wargear-line:last-child { margin-bottom: 0; }
.dcc-wargear-default { font-weight: 600; }
.dcc-wargear-line strong { color: #000; }
.dcc-wargear-sub { margin: 0.2mm 0 0.3mm 2.4mm; list-style: none; padding: 0; }
.dcc-wargear-sub li {
  position: relative;
  padding-left: 1.6mm;
  font-size: calc(2.34mm * var(--dcc-body-mul, 1));
}
.dcc-wargear-sub li::before {
  content: '◦';
  position: absolute;
  left: 0;
  color: #555;
}

/* Rule + stratagem body text */
.dcc-rule-body, .dcc-strat-body { padding: 1mm 1.4mm; flex: 1 1 auto; }
.dcc-rule-text {
  font-size: calc(2.88mm * var(--dcc-body-mul, 1));
  line-height: 1.32;
  color: #1a1a1a;
  white-space: pre-wrap;
}

/* Footer keywords */
.dcc-foot {
  margin-top: auto;
  padding-top: 0.8mm;
  border-top: 0.25mm solid rgba(60, 40, 16, 0.45);
  position: relative;
}
.dcc-foot::before {
  /* Thin gold line above the dark divider — echoes the title bar. */
  content: '';
  position: absolute;
  top: -0.15mm; left: 0; right: 0;
  height: 0.15mm;
  background: linear-gradient(90deg,
    rgba(184,144,82,0) 0%, #b89052 30%, #b89052 70%, rgba(184,144,82,0) 100%);
}
.dcc-keywords {
  font-size: calc(2.34mm * var(--dcc-fine-mul, 1));
  letter-spacing: 0.02em;
  color: #2a1f0e;
  line-height: 1.25;
}
.dcc-keywords strong { color: #0a0703; letter-spacing: 0.06em; }
.dcc-faction-kw { margin-bottom: 0.4mm; }

/* Tighten card padding for many-up grids */
.dcc-page[style*="grid-template-columns: repeat(3"] .dcc-card,
.dcc-page[style*="grid-template-rows: repeat(3"]    .dcc-card {
  padding: 1.2mm;
  gap: 0.9mm;
}
.dcc-page[style*="grid-template-columns: repeat(3"] .dcc-name,
.dcc-page[style*="grid-template-rows: repeat(3"]    .dcc-name {
  font-size: 3mm;
}
.dcc-page[style*="grid-template-columns: repeat(3"] .dcc-stat-val,
.dcc-page[style*="grid-template-rows: repeat(3"]    .dcc-stat-val {
  font-size: 3.0mm;
}

/* ── Template skins ───────────────────────────────────────────────────────
 * A "template" is a full visual skin for the printable datacards, applied
 * as a `.dcc-tpl-<id>` class on every `.dcc-card` cell (fronts, backs,
 * continuations, empty padders, and the off-screen measure stage) by
 * cards-mode.js.
 *
 * The DEFAULT look — gilded parchment, GW 10e style — is the un-suffixed
 * chrome above. It is exposed in the UI as the `classic` template
 * ("Gilded Parchment") and needs NO overrides here: `.dcc-tpl-classic`
 * simply inherits the base `.dcc-*` rules unchanged.
 *
 * To add a template:
 *   1. add an entry to the TEMPLATES array in js/ui/cards-mode.js
 *      (id + label + a preview `swatch` gradient), and
 *   2. add a `.dcc-card.dcc-tpl-<id>` skin block below.
 * Nothing else changes — the renderer already tags every card cell with
 * the active template class and the measure stage matches it.
 *
 * Specificity note: the texture system injects `.dcc-card { background }`
 * (0,1,0) and `.dcc-card-cont .dcc-cont-overlay { background }` (0,2,0)
 * at runtime via <style id="cards-texture-style">. A template that
 * recolours the card SURFACE must out-specify those, hence the
 * `.dcc-card.dcc-tpl-<id>` (0,2,0) and
 * `.dcc-card.dcc-tpl-<id> .dcc-cont-overlay` (0,3,0) selectors. Plain
 * ink/border overrides (e.g. `.dcc-tpl-<id> .dcc-rule-text`) already beat
 * the static base rules on specificity, so source order doesn't matter.
 * ========================================================================= */

/* ===== Grimdark Iron =====================================================
 * A full gothic-industrial REBUILD — not just a recolour. The skin
 * restructures the card's SHAPES, not only its palette:
 *   - the card is a cut-corner (octagonal-bevel) ARMOUR PLATE with a drawn
 *     oxidised-bronze frame and corner rivets;
 *   - the header is a bevelled BANNER with a double gilt edge + a gilt boss;
 *   - stat cells are chamfered STAT PILLARS with a bronze top bevel;
 *   - section bars are arrow-tailed riveted BANNERS;
 *   - the footer carries an ornamental gilt STAR boss on its divider.
 * Palette is the research "Imperial Gothic": blackened iron (near-black, NOT
 * #000 — avoids halation + worst home-printer ink pooling), warm BONE ink
 * (#e3dac9, never pure white), oxidised bronze/gold gilt, dried-blood pips.
 * Every shape is CSS clip-path + gradients + inline-SVG (no external art) so
 * it survives print; the print sheet already forces print-color-adjust:exact
 * on .dcc-card / .dcc-head / .dcc-section-head / .dcc-stat-cell /
 * .dcc-cont-overlay.
 *
 * Shape architecture (the load-bearing trick): the card element IS the gold
 * plate — its background is the bronze metal, chamfered by clip-path. An
 * inset ::before paints the IRON interior (also chamfered), so the gold only
 * shows as a frame ring. Flow children are lifted to z-index:1 to sit above
 * that iron ::before; ::after stamps the corner rivets. Continuation / back /
 * empty cells opt OUT of the sandwich at the end of this block.
 */
.dcc-card.dcc-tpl-grimdark {
  --gd-ink:         #e3dac9;   /* bone — primary body ink */
  --gd-ink-strong:  #f6efda;   /* brighter bone for <strong> */
  --gd-ink-muted:   #a2977f;   /* ash — fine print, sub-bullets */
  --gd-gold:        #c39a45;   /* oxidised gold accent */
  --gd-gold-bright: #e7c87a;
  --gd-gold-deep:   #7c5a22;
  --gd-rule:        rgba(195, 154, 69, 0.42);
  --gd-iron:        #15120c;   /* interior fill, for matched corner cuts */
  --gd-bezel:       2.6mm;     /* card corner cut */

  color: var(--gd-ink);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: calc(1.5mm + var(--dcc-safe, 0mm)) calc(1.7mm + var(--dcc-safe, 0mm));
  overflow: hidden;
  /* The card background IS the bronze frame (a faceted gold/brown metal
   * sweep). The iron interior is painted by ::before, inset by the frame
   * width, so the gold reads as a gilt ring around the plate. */
  background: linear-gradient(135deg,
    #b98f3c 0%, #e7c87a 17%, #8a6a2a 37%, #caa24a 52%,
    #6f5021 71%, #e7c87a 88%, #a87f33 100%);
  /* Octagonal bevel — the signature "tech-plate" cut corner. */
  clip-path: polygon(
    var(--gd-bezel) 0, calc(100% - var(--gd-bezel)) 0,
    100% var(--gd-bezel), 100% calc(100% - var(--gd-bezel)),
    calc(100% - var(--gd-bezel)) 100%, var(--gd-bezel) 100%,
    0 calc(100% - var(--gd-bezel)), 0 var(--gd-bezel));
}
.dcc-card.dcc-tpl-grimdark::before {
  content: '';
  position: absolute;
  inset: 0.72mm;             /* frame width */
  z-index: 0;
  clip-path: polygon(
    2.0mm 0, calc(100% - 2.0mm) 0,
    100% 2.0mm, 100% calc(100% - 2.0mm),
    calc(100% - 2.0mm) 100%, 2.0mm 100%,
    0 calc(100% - 2.0mm), 0 2.0mm);
  background:
    radial-gradient(ellipse at 50% -12%, rgba(150,116,52,0.14) 0%, rgba(0,0,0,0) 55%),
    radial-gradient(ellipse at 50% 120%, rgba(0,0,0,0.60) 0%, rgba(0,0,0,0) 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' seed='7'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23g)'/></svg>"),
    linear-gradient(180deg, #1b1813 0%, #141109 55%, #0b0905 100%),
    #120f08;
  background-blend-mode: normal, normal, multiply, normal, normal;
  box-shadow: inset 0 0 0 0.18mm rgba(0,0,0,0.7), inset 0 0 6mm rgba(0,0,0,0.5);
}
/* Lift all flow content above the iron ::before layer. */
.dcc-card.dcc-tpl-grimdark > * { position: relative; z-index: 1; }
/* Corner rivets — small domed bronze studs in each bevelled corner. */
.dcc-card.dcc-tpl-grimdark::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    radial-gradient(circle at 1.4mm 1.4mm,                       #f0d589 0 0.18mm, #6a4f1f 0.2mm 0.42mm, rgba(0,0,0,0.55) 0.46mm 0.6mm, transparent 0.62mm),
    radial-gradient(circle at calc(100% - 1.4mm) 1.4mm,          #f0d589 0 0.18mm, #6a4f1f 0.2mm 0.42mm, rgba(0,0,0,0.55) 0.46mm 0.6mm, transparent 0.62mm),
    radial-gradient(circle at 1.4mm calc(100% - 1.4mm),          #f0d589 0 0.18mm, #6a4f1f 0.2mm 0.42mm, rgba(0,0,0,0.55) 0.46mm 0.6mm, transparent 0.62mm),
    radial-gradient(circle at calc(100% - 1.4mm) calc(100% - 1.4mm), #f0d589 0 0.18mm, #6a4f1f 0.2mm 0.42mm, rgba(0,0,0,0.55) 0.46mm 0.6mm, transparent 0.62mm);
  background-repeat: no-repeat;
}

/* Header — a bevelled banner with a double gilt edge and a centred boss. */
.dcc-tpl-grimdark .dcc-head {
  margin: 0.2mm 0 1.0mm;
  border-radius: 0;
  padding: 1.3mm 2.2mm 1.5mm;
  background: linear-gradient(180deg, #262219 0%, #16130c 52%, #0a0805 100%);
  color: #efe3c4;
  /* Octagonal banner — both top + bottom corners cut. */
  clip-path: polygon(
    1.4mm 0, calc(100% - 1.4mm) 0, 100% 1.0mm,
    100% calc(100% - 1.0mm), calc(100% - 1.6mm) 100%,
    1.6mm 100%, 0 calc(100% - 1.0mm), 0 1.0mm);
  box-shadow: inset 0 0.32mm 0 var(--gd-gold), inset 0 -0.46mm 0 var(--gd-gold);
}
/* Base flourish/stripe pseudo-elements are clipped away — repurpose ::before
 * as the banner boss and drop ::after. */
.dcc-tpl-grimdark .dcc-head::after { display: none; }
.dcc-tpl-grimdark .dcc-head::before {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0.18mm;
  margin-left: -1.6mm;
  width: 3.2mm;
  height: 1.5mm;
  background: linear-gradient(135deg, var(--gd-gold-bright) 0%, var(--gd-gold) 45%, var(--gd-gold-deep) 100%);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  z-index: 2;
}
/* Wide tracking + a cut shadow reads as stamped, engraved lettering. */
.dcc-tpl-grimdark .dcc-name {
  letter-spacing: 0.1em;
  text-shadow: 0 0.12mm 0.2mm rgba(0,0,0,0.75);
}

/* Stat pillars — chamfered armour plates with a bronze top bevel (the gold
 * shows through the ::before sandwich) and bone numerals. */
.dcc-tpl-grimdark .dcc-stat-cell {
  background: linear-gradient(180deg, #d8b25a 0%, #a07e34 45%, #6f5021 100%);
  color: #f1e7c9;
  border-radius: 0;
  box-shadow: none;
  clip-path: polygon(0 1.1mm, 1.1mm 0, calc(100% - 1.1mm) 0, 100% 1.1mm, 100% 100%, 0 100%);
}
.dcc-tpl-grimdark .dcc-stat-cell::before {
  content: '';
  position: absolute;
  inset: 0.24mm;
  z-index: 0;
  clip-path: polygon(0 1.0mm, 1.0mm 0, calc(100% - 1.0mm) 0, 100% 1.0mm, 100% 100%, 0 100%);
  background: linear-gradient(180deg, #2a2620 0%, #15120c 100%);
}
.dcc-tpl-grimdark .dcc-stat-cell > * { position: relative; z-index: 1; }
.dcc-tpl-grimdark .dcc-stat-key { color: var(--gd-gold-bright); }
.dcc-tpl-grimdark .dcc-stat-rowlabel { color: var(--gd-gold); }

/* Section bars — arrow-tailed blackened-bronze banners with a left rivet. */
.dcc-tpl-grimdark .dcc-section-head {
  background: linear-gradient(180deg, #2b2417 0%, #1a160d 55%, #100d07 100%);
  color: #e8dcb8;
  border-radius: 0;
  padding-left: 3.0mm;
  position: relative;
  clip-path: polygon(1.6mm 0, 100% 0, 100% 100%, 1.6mm 100%, 0 50%);
  box-shadow: inset 0 0.18mm 0 var(--gd-gold), inset 0 -0.22mm 0 var(--gd-gold-deep);
}
.dcc-tpl-grimdark .dcc-section-head::before {
  content: '';
  position: absolute;
  left: 1.8mm;
  top: 50%;
  transform: translateY(-50%);
  width: 0.9mm;
  height: 0.9mm;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #f0d589, #6a4f1f 70%, #2a1f0e);
  z-index: 1;
}

/* Body ink: flip every dark-on-parchment colour to bone-on-iron. */
.dcc-tpl-grimdark .dcc-abilities-body,
.dcc-tpl-grimdark .dcc-wargear-body,
.dcc-tpl-grimdark .dcc-rule-text { color: var(--gd-ink); }
.dcc-tpl-grimdark .dcc-ability-row strong,
.dcc-tpl-grimdark .dcc-wargear-line strong { color: var(--gd-ink-strong); }
.dcc-tpl-grimdark .dcc-core-row { color: var(--gd-ink-muted); }
.dcc-tpl-grimdark .dcc-wargear-sub li::before { color: var(--gd-gold); }
.dcc-tpl-grimdark .dcc-w-kw { color: var(--gd-ink-muted); }
.dcc-tpl-grimdark .dcc-w-table tr { border-bottom-color: rgba(227,218,201,0.14); }
.dcc-tpl-grimdark .dcc-abilities-primarch .dcc-abilities-body { border-top-color: var(--gd-rule); }

/* Footer keywords. */
.dcc-tpl-grimdark .dcc-foot { border-top-color: var(--gd-rule); }
.dcc-tpl-grimdark .dcc-foot::before {
  background: linear-gradient(90deg,
    rgba(195,154,69,0) 0%, var(--gd-gold) 30%, var(--gd-gold) 70%, rgba(195,154,69,0) 100%);
}
/* Ornamental gilt star boss centred on the footer divider — reads as a
 * stamped Imperial seal / purity stud. */
.dcc-tpl-grimdark .dcc-foot::after {
  content: '';
  position: absolute;
  top: -1.0mm;
  left: 50%;
  transform: translateX(-50%);
  width: 3.4mm;
  height: 1.7mm;
  z-index: 2;
  background:
    radial-gradient(circle at 50% 50%, #1a140a 0 0.28mm, transparent 0.32mm),
    linear-gradient(135deg, var(--gd-gold-bright), var(--gd-gold) 50%, var(--gd-gold-deep));
  clip-path: polygon(50% 0, 82% 30%, 100% 50%, 82% 70%, 50% 100%, 18% 70%, 0 50%, 18% 30%);
}
.dcc-tpl-grimdark .dcc-keywords { color: var(--gd-ink-muted); }
.dcc-tpl-grimdark .dcc-keywords strong { color: var(--gd-ink); }

/* Points pill → bronze; CP + invuln pips → dried blood. */
.dcc-tpl-grimdark .dcc-pts {
  background: linear-gradient(180deg, #3a2a10, #241a09);
  color: #f1e3bf;
  box-shadow: inset 0 0 0 0.1mm var(--gd-gold);
}
.dcc-tpl-grimdark .dcc-head-strat .dcc-cp,
.dcc-tpl-grimdark .dcc-inv {
  background: linear-gradient(180deg, #8a1717, #560505);
  box-shadow: inset 0 0 0 0.12mm rgba(231,200,122,0.5);
}

/* Continuation / duplex-back / empty cells opt OUT of the plate sandwich:
 * the iron ::before + bevel + rivets would fight their special content
 * (a back image, a partial parchment overlay, or nothing). */
.dcc-card.dcc-tpl-grimdark.dcc-card-cont,
.dcc-card.dcc-tpl-grimdark.dcc-card-back,
.dcc-card.dcc-tpl-grimdark.dcc-card-empty {
  clip-path: none;
}
.dcc-card.dcc-tpl-grimdark.dcc-card-cont::before,
.dcc-card.dcc-tpl-grimdark.dcc-card-cont::after,
.dcc-card.dcc-tpl-grimdark.dcc-card-back::before,
.dcc-card.dcc-tpl-grimdark.dcc-card-back::after,
.dcc-card.dcc-tpl-grimdark.dcc-card-empty::before,
.dcc-card.dcc-tpl-grimdark.dcc-card-empty::after {
  display: none;
}
.dcc-card.dcc-tpl-grimdark.dcc-card-empty { background: transparent; }
.dcc-card.dcc-tpl-grimdark.dcc-card-back { background: #15120c; }
/* Continuation overlay keeps the iron surface (0,3,0 beats the runtime
 * texture injection). Its own bevelled top echoes the plate. */
.dcc-card.dcc-tpl-grimdark .dcc-cont-overlay {
  background: linear-gradient(180deg, #1a1712, #0c0a06), #131009;
  box-shadow: 0 2mm 3mm rgba(0,0,0,0.4);
}
.dcc-card.dcc-tpl-grimdark.dcc-card-cont:not(.dcc-card-cont-art) .dcc-cont-overlay {
  border-bottom-color: #050402;
}

/* ===== Industrial Stencil =================================================
 * Light, print-friendly skin recreated from the "Warhammer Datacard Design"
 * handoff (its locked `stencil` renderVals spec). Cream cardstock, near-black
 * ink, a full-bleed dark header bar with a faction-accent bottom rule, Cinzel
 * display + EB Garamond body, ink-chip section heads with an accent diamond
 * tick, faction-accent shield/hex badges, and accent pills. A single accent
 * colour — `--dcc-accent`, auto-derived per faction by cards-mode.js (default
 * Necron green #74c043) — recolours every accented element via color-mix.
 *
 * Tokens: paper #ece5d6 · panel #f5f0e3 · ink #29251f · muted #7c7360 ·
 * dim #4a4337 · hairline = ink @ 24%. EB Garamond + Cinzel are vendored in
 * css/typography.css, so the skin renders identically offline + in print.
 *
 * Several elements only exist on this template (emitted by cards-mode.js when
 * templateId==='stencil'): .dcc-kicker, .dcc-statline(-rows), .dcc-invuln-
 * shield/-val/-lbl, .dcc-w-tag, .dcc-ab-block/-head/-name/-text. The other
 * templates never see them.
 */
.dcc-card.dcc-tpl-stencil {
  --st-paper:  #ece5d6;
  --st-panel:  #f5f0e3;
  --st-ink:    #29251f;
  --st-mut:    #7c7360;
  --st-dim:    #4a4337;
  --st-hair:   color-mix(in srgb, #29251f 24%, transparent);
  --st-accent: var(--dcc-accent, #74c043);
  --st-accent-dark: color-mix(in srgb, var(--st-accent) 58%, #29251f);
  --st-pill:    color-mix(in srgb, var(--st-accent) 22%, transparent);
  --st-pill-bd: color-mix(in srgb, var(--st-accent) 50%, transparent);
  --st-body: 'EB Garamond', Georgia, 'Times New Roman', serif;

  color: var(--st-ink);
  background: var(--st-paper);
  border: 0;
  box-shadow: none;
  font-family: var(--st-body);
}

/* Header — full-bleed dark bar with a faction-accent bottom rule. */
.dcc-tpl-stencil .dcc-head {
  /* Bleed the bar to the card edge by negating the full content padding
   * (base + safe margin); pad the text back in by the same amount so it
   * lines up with the body content and clears the borderless trim. */
  margin: calc(-1.6mm - var(--dcc-safe, 0mm)) calc(-2mm - var(--dcc-safe, 0mm)) 1.4mm;
  padding: calc(1.6mm + var(--dcc-safe, 0mm)) calc(2mm + var(--dcc-safe, 0mm));
  background: var(--st-ink);
  color: var(--st-panel);
  border-radius: 0;
  border-bottom: 0.7mm solid var(--st-accent);
  box-shadow: none;
}
.dcc-tpl-stencil .dcc-head::before,
.dcc-tpl-stencil .dcc-head::after { display: none; }
.dcc-tpl-stencil .dcc-kicker {
  font-family: var(--st-body);
  font-size: calc(2.4mm * var(--dcc-sub-mul, 1));
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--st-accent) 90%, transparent);
  margin-bottom: 0.5mm;
  /* Faction name on the dark header bar — thicken its strokes so the small
   * accent-coloured letters print solid. See `.dcc-section-label`. */
  -webkit-text-stroke: 0.1mm currentColor;
  text-stroke: 0.1mm currentColor;
  paint-order: stroke fill;
}
/* The design wraps long names onto a second line rather than truncating. */
.dcc-tpl-stencil .dcc-name {
  color: var(--st-panel);
  letter-spacing: 0.04em;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.04;
}
.dcc-tpl-stencil .dcc-sub-line { color: color-mix(in srgb, var(--st-panel) 70%, transparent); }
.dcc-tpl-stencil .dcc-pts {
  background: var(--st-accent);
  color: #1c1813;
  border-radius: 0.5mm;
  font-weight: 700;
}

/* Stat strip + per-line invuln shield. Each stat row is wrapped in its own
 * .dcc-statline so the shield sits flush at the end of THAT line (not
 * stretched across multiple profiles). Rows without an invuln carry a
 * spacer of the shield's width so the six stat columns stay aligned. */
.dcc-tpl-stencil .dcc-statline { display: flex; gap: 1.4mm; align-items: stretch; }
.dcc-tpl-stencil .dcc-statline > .dcc-stats { flex: 1 1 auto; min-width: 0; margin-top: 0; }
.dcc-tpl-stencil .dcc-statline + .dcc-statline,
.dcc-tpl-stencil .dcc-stat-rowlabel + .dcc-statline { margin-top: 0.6mm; }
.dcc-tpl-stencil .dcc-invuln-spacer { flex: 0 0 auto; width: 11mm; }
.dcc-tpl-stencil .dcc-stat-cell {
  background: var(--st-panel);
  color: var(--st-ink);
  border: 0.35mm solid var(--st-ink);
  border-radius: 0.5mm;
  box-shadow: none;
}
.dcc-tpl-stencil .dcc-stat-key { color: var(--st-mut); font-family: 'Cinzel', serif; }
.dcc-tpl-stencil .dcc-stat-val { color: var(--st-ink); font-family: 'Cinzel', serif; }
.dcc-tpl-stencil .dcc-stat-rowlabel { color: var(--st-accent-dark); }
.dcc-tpl-stencil .dcc-invuln-shield {
  flex: 0 0 auto;
  width: 11mm;
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.2mm;
  background: var(--st-accent);
  color: #1b1712;
  clip-path: polygon(50% 0, 100% 15%, 100% 58%, 50% 100%, 0 58%, 0 15%);
}
.dcc-tpl-stencil .dcc-invuln-val {
  font-family: 'Cinzel', serif; font-weight: 700; line-height: 1; color: #1b1712;
  font-size: calc(4mm * var(--dcc-stat-mul, 1));
}
.dcc-tpl-stencil .dcc-invuln-lbl {
  font-family: 'Cinzel', serif; font-weight: 700; font-size: 1.7mm;
  letter-spacing: 0.08em; text-transform: uppercase; color: rgba(27,23,18,0.72);
}

/* Section heads — accent diamond tick + ink-chip label. (Keep the head's
 * right padding so the weapon column letters stay aligned over the table.) */
.dcc-tpl-stencil .dcc-section-head {
  background: transparent;
  color: var(--st-ink);
  box-shadow: none;
  border-radius: 0;
  padding: 0 1.4mm 0 0;
  margin: 1.8mm 0 1.0mm;
  gap: 1.4mm;
  align-items: center;
}
.dcc-tpl-stencil .dcc-section-head::before {
  content: '';
  width: 1.5mm; height: 1.5mm;
  background: var(--st-accent);
  transform: rotate(45deg);
  flex: 0 0 auto;
}
.dcc-tpl-stencil .dcc-section-label {
  background: var(--st-ink);
  color: var(--st-panel);
  font-family: 'Cinzel', serif;
  font-weight: 700;
  letter-spacing: 0.14em;
  padding: 0.4mm 1.5mm;
}
.dcc-tpl-stencil .dcc-section-cols { color: var(--st-mut); }

/* Weapon tables — hairline rows, Cinzel numerals, accent keyword pills. */
.dcc-tpl-stencil .dcc-w-table tr { border-bottom-color: var(--st-hair); }
.dcc-tpl-stencil .dcc-w-name { color: var(--st-ink); font-family: var(--st-body); font-weight: 600; }
.dcc-tpl-stencil .dcc-num    { color: var(--st-ink); font-family: 'Cinzel', serif; font-weight: 600; }
/* Keyword pills sit on their own line under the weapon name and wrap as a
 * group, rather than trailing inline off the name and breaking mid-row. */
.dcc-tpl-stencil .dcc-w-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8mm;
  margin-top: 0.5mm;
}
.dcc-tpl-stencil .dcc-w-tag {
  display: inline-block;
  font-family: var(--st-body);
  font-size: calc(2.0mm * var(--dcc-w-mul, 1));
  font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 0.1mm 0.9mm;
  border-radius: 0.6mm;
  background: var(--st-pill);
  border: 0.2mm solid var(--st-pill-bd);
  color: var(--st-ink);
  white-space: nowrap; vertical-align: baseline;
}

/* Abilities — type-pill blocks. */
.dcc-tpl-stencil .dcc-abilities-body { color: var(--st-dim); padding: 0.4mm 0 0; }
.dcc-tpl-stencil .dcc-ab-block { margin-top: 1.3mm; }
.dcc-tpl-stencil .dcc-ab-block:first-child { margin-top: 0.4mm; }
.dcc-tpl-stencil .dcc-ab-head { display: flex; align-items: baseline; gap: 1.2mm; flex-wrap: wrap; margin-bottom: 0.4mm; }
.dcc-tpl-stencil .dcc-type-pill {
  font-family: var(--st-body);
  font-size: 1.9mm; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.2mm 1.1mm; border-radius: 0.6mm;
  background: var(--st-pill); border: 0.2mm solid var(--st-pill-bd); color: var(--st-ink);
}
.dcc-tpl-stencil .dcc-ab-name {
  font-family: var(--st-body); font-weight: 700; color: var(--st-ink);
  font-size: calc(2.7mm * var(--dcc-body-mul, 1));
}
.dcc-tpl-stencil .dcc-ab-text {
  font-family: var(--st-body); color: var(--st-dim); line-height: 1.36; white-space: pre-line;
  font-size: calc(2.5mm * var(--dcc-body-mul, 1));
}

/* Other body text (enhancement, wargear, transport, rule/strat). */
.dcc-tpl-stencil .dcc-ability-row,
.dcc-tpl-stencil .dcc-wargear-body,
.dcc-tpl-stencil .dcc-rule-text { color: var(--st-dim); }
.dcc-tpl-stencil .dcc-ability-row strong,
.dcc-tpl-stencil .dcc-wargear-line strong { color: var(--st-ink); }
.dcc-tpl-stencil .dcc-core-row { color: var(--st-mut); }
.dcc-tpl-stencil .dcc-wargear-sub li::before { color: var(--st-accent-dark); }

/* Footer keywords. */
.dcc-tpl-stencil .dcc-foot { border-top-color: var(--st-hair); }
.dcc-tpl-stencil .dcc-foot::before { display: none; }
.dcc-tpl-stencil .dcc-keywords { color: var(--st-dim); font-family: var(--st-body); }
.dcc-tpl-stencil .dcc-keywords strong { color: var(--st-accent-dark); letter-spacing: 0.08em; }

/* Stratagem CP — faction-accent hex badge. */
.dcc-tpl-stencil .dcc-head-strat .dcc-cp {
  background: var(--st-accent);
  color: #1b1712;
  border-radius: 0;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  padding: 1.5mm 1.4mm;
  align-self: center;
}
.dcc-tpl-stencil .dcc-cp-num { font-family: 'Cinzel', serif; color: #1b1712; }
.dcc-tpl-stencil .dcc-cp-lbl { color: rgba(27,23,18,0.8); }
.dcc-tpl-stencil .dcc-strat-phase,
.dcc-tpl-stencil .dcc-role { color: color-mix(in srgb, var(--st-panel) 70%, transparent); }

/* Continuation / back cells inherit the cream surface. */
.dcc-card.dcc-tpl-stencil .dcc-cont-overlay { background: var(--st-paper); }
.dcc-card.dcc-tpl-stencil.dcc-card-back { background: var(--st-panel); }

/* Responsive: stack the rail above the preview on narrow viewports. */
@media (max-width: 760px) {
  .cards-shell { flex-direction: column; height: auto; min-height: 100vh; }
  .cards-side { width: 100%; max-height: 50vh; border-right: 0; border-bottom: 1px solid #23272e; }
  .cards-preview-wrap { padding: 12px; }
}

/* ── Print stylesheet ───────────────────────────────────────────────────── */
/* JS adds body.cards-printing + a dynamic <style id="cards-print-style">
 * with @page { size: <layout>; margin: 0 } before calling window.print().
 * These rules hide everything except the cards and unwrap the preview's
 * fit-to-viewport scaling so each page prints at full physical size. */
@media print {
  /* Reset html/body so default margins don't add a phantom first page. */
  html, body.cards-printing {
    margin: 0 !important;
    padding: 0 !important;
    background: #fff !important;
    color: #000 !important;
    overflow: visible !important;
    width: auto !important;
    height: auto !important;
  }
  /* Force background colours / images to actually print, even when the
   * user hasn't enabled "Background graphics" in the print dialog.
   * Without this the parchment, gold accents, and border-colour sheet
   * all print as white. */
  body.cards-printing .dcc-page,
  body.cards-printing .dcc-card,
  body.cards-printing .dcc-card-back,
  body.cards-printing .dcc-card-cont,
  body.cards-printing .dcc-cont-overlay,
  body.cards-printing .dcc-cont-bg,
  body.cards-printing .dcc-back-img,
  body.cards-printing .dcc-head,
  body.cards-printing .dcc-section-head,
  body.cards-printing .dcc-stat-cell,
  body.cards-printing .dcc-cp,
  body.cards-printing .dcc-inv,
  body.cards-printing .dcc-invuln-shield,
  body.cards-printing .dcc-section-label,
  body.cards-printing .dcc-w-tag,
  body.cards-printing .dcc-type-pill,
  body.cards-printing .dcc-pts,
  body.cards-printing .dcc-foot::before {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
    color-adjust: exact !important;
  }
  /* Hide everything outside the cards-mode subtree. */
  body.cards-printing > :not(#cards-mode) { display: none !important; }
  /* Override mode-shell.css's `.mode-page { height: calc(100vh - …);
   * overflow: hidden }` (clips past one viewport height during print)
   * and `.mode-page[hidden] { display:none !important }` defensively. */
  body.cards-printing #cards-mode,
  body.cards-printing #cards-mode[hidden] {
    display: block !important;
    background: #fff !important;
    padding: 0 !important;
    margin: 0 !important;
    width: auto !important;
    height: auto !important;
    overflow: visible !important;
  }
  /* Inside cards-mode, hide just the settings rail; everything else
   * (.cards-shell -> .cards-preview-wrap -> ... -> .dcc-page) shows. */
  body.cards-printing .cards-side { display: none !important; }
  body.cards-printing .cards-side-foot { display: none !important; }
  body.cards-printing .cards-shell {
    display: block !important;
    height: auto !important;
    background: #fff !important;
  }
  body.cards-printing .cards-preview-wrap {
    overflow: visible !important;
    background: #fff !important;
    padding: 0 !important;
    display: block !important;
  }
  body.cards-printing .cards-preview {
    display: block !important;
    gap: 0 !important;
  }
  /* Strip the preview scaling — print at 1:1 */
  body.cards-printing .dcc-page-frame {
    width: auto !important;
    height: auto !important;
    overflow: visible !important;
    --dcc-preview-scale: 1 !important;
  }
  body.cards-printing .dcc-page-frame > .dcc-page {
    transform: none !important;
  }
  body.cards-printing .dcc-page {
    box-shadow: none !important;
    margin: 0 !important;
    page-break-after: always !important;
    break-after: page !important;
  }
  body.cards-printing .dcc-page-frame:last-child .dcc-page {
    page-break-after: auto !important;
    break-after: auto !important;
  }
}
