/* =========================================================================
   The looks.
   =========================================================================

   Loaded after app.css, which is written against the variables below. A theme
   is a block of them on [data-theme=...] - never a second opinion about layout,
   spacing or what a page contains. That is the rule that keeps eight of these
   maintainable: if a theme needs a rule that is not a colour, a texture, a
   frame or an icon treatment, the rule belongs in app.css behind a variable.

   What a theme may set:

     --page-bg          the whole page behind everything
     --texture-image    the weave over it, or none
     --texture-opacity  how strongly it shows
     --panel-bg         a panel's own ground
     --frame-source     the border-image around a panel, or none
     --frame-slice/width   its geometry when there is one
     --panel-border     the border when there is no frame
     --panel-radius     square for stone, soft for clinical
     --panel-pad        the frame eats space; a flat panel does not
     --icon-color       what an icon is drawn in
     --icon-glow        a drop-shadow filter, or none
     --chip-bg/--chip-border  the small pills the Vault and the roster lean on
     ...plus the palette app.css already had: --gold, --text, --stone-*, --ok
        and the rest, which every theme redefines to its own ends. Their NAMES
        are historical - "gold" is whatever this theme's accent is - and that is
        deliberate: renaming them across two thousand lines would be a far
        bigger change than the colours are worth.

   Every theme must set the whole palette, not a few interesting parts of it. A
   half-theme is the bug that shows up as black text on a black panel three
   screens deep, which is why each block below is written out in full.
*/

/* ---- What every look but the Hall derives from its own palette ---------------

   The Hall's values for these are literals on :root (app.css). Everywhere else
   they are worked out from the look's own colours, once, here - so a new look
   gets readable buttons, alerts and icons for free, and cannot inherit a brown
   Hall gradient by forgetting to name it. Two attribute tests on purpose: this
   must outrank :root, which the page's own <html> also matches. A look that
   wants something else says so with the same two-part selector, further down. */
[data-theme]:not([data-theme='hall']) {
  --btn-primary-hover-bg: var(--btn-primary-bg);
  --btn-primary-hover-glow: 0 0 0 1px var(--gold);
  --btn-primary-hover-filter: brightness(1.12);
  --seg-on-bg: var(--btn-primary-bg);
  --danger-edge: color-mix(in srgb, var(--bad) 55%, transparent);
  --danger-ink: var(--bad);
  --danger-hover-bg: color-mix(in srgb, var(--bad) 14%, transparent);
  --danger-hover-ink: var(--bad);
  --alert-error-edge: color-mix(in srgb, var(--bad) 45%, transparent);  --alert-error-ink: var(--bad);
  --alert-ok-edge: color-mix(in srgb, var(--ok) 45%, transparent);     --alert-ok-ink: var(--ok);
  --alert-info-edge: color-mix(in srgb, var(--azure) 45%, transparent); --alert-info-ink: var(--azure);
  --alert-warn-edge: color-mix(in srgb, var(--warn) 45%, transparent);  --alert-warn-ink: var(--warn);
  --row-hover: var(--accent-wash);
  --panel-icon-color: var(--icon-color);
  --panel-icon-glow: var(--icon-glow);
  --crest-glow: var(--icon-glow);
  --nav-icon-color: var(--icon-color);
  --nav-icon-glow: var(--icon-glow);
  --list-icon-color: var(--icon-color);
  --nav-bg: var(--surface-2);
  --hall-bg-acct-row: color-mix(in srgb, var(--surface-sunken) 50%, transparent);
  --hall-bg-code-not-pre-code: var(--surface-sunken);
  /* A backdrop is a see-through scrim in every look, never a solid sheet. */
  --hall-bg-drawer-back: color-mix(in srgb, var(--ink) 62%, transparent);
  --hall-bg-map-toolbar: var(--surface-sunken);
  /* A backdrop is a see-through scrim in every look, never a solid sheet. */
  --hall-bg-modal-back: color-mix(in srgb, var(--ink) 78%, transparent);
  --hall-bg-page-card: var(--surface-1);
  --hall-bg-perm-module-head: var(--surface-sunken);
  --hall-bg-portrait-card: var(--surface-1);
  --hall-bg-post: var(--surface-2);
  --hall-bg-role-card: var(--surface-1);
  --hall-bg-sheet-table-tbody-tr-not-sheet-group: var(--surface-1);
  --hall-bg-slideshow: var(--surface-2);
}

/* ---- Daylight: the default since 2026-10-26 ------------------------------

   The owner: "a light weight and pleasant one with no theming", and then "more
   to it than the clinical white, but very casual/passive contrasts and border
   styles". So: no costume - no woven frame, no torchlight, the reader's own
   sans-serif and nothing to download - but not a blank sheet either. A warm
   sand page with a faint sage and peach light across the top and a dotted
   paper grain; warm-white cards with round corners, a soft sage edge along
   their top and a dashed rule under their heading; a stitched line under the
   masthead; ink in warm charcoal rather than black, and one muted teal where
   the Hall has gold. Every pairing a pill or a button draws is held to 4.5:1
   (test/looks.mjs); the quieter greys are for the words around them. */

[data-theme='daylight'] {
  --surface-1: #fffdf9;
  --surface-2: #fbf8f2;
  --surface-sunken: #f5f1e9;
  --accent-wash: rgba(59, 124, 132, .08);
  --btn-primary-bg: #3b7c84;
  --btn-primary-hover-glow: none;
  --btn-primary-hover-filter: brightness(1.07);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 14px 14px 16px;
  --ink:        #ffffff;
  --stone-900:  #fffdf9;
  --stone-800:  #fbf8f2;
  --stone-700:  #f0ebe1;
  --stone-600:  #e5ded1;
  --stone-500:  #d2c9b9;

  --gold:       #3b7c84;
  --gold-bright:#2c6870;
  /* A muted sage-teal: column headings and small labels read in it. */
  --gold-dim:   #55857e;
  /* The pale sage of a card's top edge (private to this look). */
  --dl-edge:    #a9cbc4;
  --parchment:  #2f2d29;
  --text:       #3b3934;
  --text-dim:   #6c675e;
  --text-faint: #8b857b;

  --jade:   #377d56;
  --blood:  #c0453a;
  --violet: #7a68b8;
  --azure:  #4a7fb0;
  --bone:   #6c675e;

  --ok:   #377d56;
  --warn: #a96a12;
  --bad:  #c0453a;

  /* Sand, with sage light at the top left, peach at the top right and a little
     lavender low on the left. */
  --page-bg:
    radial-gradient(1100px 560px at 0% -8%, rgba(190, 222, 211, .62), transparent 70%),
    radial-gradient(900px 520px at 100% -6%, rgba(246, 216, 186, .6), transparent 70%),
    radial-gradient(1000px 640px at -10% 105%, rgba(214, 206, 238, .45), transparent 70%),
    linear-gradient(180deg, #f6f2ea 0%, #f2efe9 100%);
  /* A dotted paper grain, barely there. */
  --texture-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22' viewBox='0 0 22 22'%3E%3Ccircle cx='3' cy='3' r='1' fill='%23bfb4a1'/%3E%3C/svg%3E");
  --texture-opacity: .32;
  --panel-bg: #fffdf9;
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #e5ded1;
  --panel-radius: 14px;
  --panel-pad: 18px 20px 20px;
  --shadow: 0 1px 2px rgba(70, 58, 40, .05), 0 10px 26px -8px rgba(70, 58, 40, .12);
  --radius: 9px;

  --icon-color: #6f8a83;
  --icon-glow: none;
  --chip-bg: #f3eee4;
  --chip-border: #e2d9c9;

  /* The reader's own sans-serif, for headings and text alike: nothing to load. */
  --font-display: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-body: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --btn-primary-ink: #ffffff;
  --badge-ink: #ffffff;
  --notice-ink: #000000;
  --att-track: #4a4740;
  --title-shadow: none;
  /* The masthead's stitched line (app.css draws it in --gold-dim, at half strength). */
  --ornament-display: block;
  --tag-ink-mix: 60%;
  /* A dialog dims the page behind it, softly, rather than whiting it out. */
  --hall-bg-modal-back: rgba(47, 45, 41, .30);
  --hall-bg-drawer-back: rgba(47, 45, 41, .22);
}

/* Headings in warm ink, by weight rather than colour or spacing. */
[data-theme='daylight'] h1,
[data-theme='daylight'] h2,
[data-theme='daylight'] h3,
[data-theme='daylight'] h4,
[data-theme='daylight'] .display { color: #2f2d29; letter-spacing: 0; }

/* The card's soft top edge, inside its round corners, and a dashed rule under
   its heading rather than a hard line, both in the card's own colour. */
[data-theme='daylight'] .panel { box-shadow: inset 0 3px 0 var(--dl-edge), var(--shadow); }
[data-theme='daylight'] .panel-head { border-bottom: 1px dashed color-mix(in srgb, var(--dl-edge) 75%, var(--stone-500)); }

/*
 * A little colour range (the owner: "slightly more color range but still
 * light"): cards take turns in five soft colours - sage, peach, sky, lilac and
 * butter - each with its icon in a deeper shade of the same. A five-long cycle,
 * so a grid of two, three or four columns never lines up in stripes. Edges are
 * pale; icons are drawings, not text, and stay at 3.5:1 or better.
 */
[data-theme='daylight'] .panel { --dl-edge: #a9cbc4; --panel-icon-color: #5c8b84; }
[data-theme='daylight'] .panel:nth-child(5n+2) { --dl-edge: #f1cba8; --panel-icon-color: #b9794a; }
[data-theme='daylight'] .panel:nth-child(5n+3) { --dl-edge: #b9d0e8; --panel-icon-color: #5a82ab; }
[data-theme='daylight'] .panel:nth-child(5n+4) { --dl-edge: #d3c6ea; --panel-icon-color: #8470b0; }
[data-theme='daylight'] .panel:nth-child(5n)   { --dl-edge: #ecdca0; --panel-icon-color: #9c7f22; }

/* The masthead in the same morning light as the page: sage to cream to peach. */
[data-theme='daylight'] .masthead {
  background: linear-gradient(90deg, #edf5f1 0%, #fbf8f2 45%, #fbefe3 100%);
}
/* The masthead's stitching, lighter than the Hall's: a seam, not a border. */
[data-theme='daylight'] .masthead::after { opacity: .32; }

/* ---- Clinical: white, flat, no frills ------------------------------------ */

[data-theme='clinical'] {
  --surface-1: #ffffff;
  --surface-2: #f7f8f9;
  --surface-sunken: #f1f3f5;
  --accent-wash: rgba(31, 111, 235, .08);
  --btn-primary-bg: linear-gradient(180deg, #1f6feb, #1a62d6);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 14px 14px 16px;
  --ink:        #ffffff;
  --stone-900:  #ffffff;
  --stone-800:  #f7f8f9;
  --stone-700:  #eef0f2;
  --stone-600:  #dfe3e7;
  --stone-500:  #c4cad1;

  --gold: #1a62d6;
  --gold-bright:#0b4fc4;
  --gold-dim:   #3f6fc4;
  --parchment:  #1b1f24;
  --text:       #1b1f24;
  --text-dim:   #4a5561;
  --text-faint: #7b8794;

  --jade:   #147d64;
  --blood:  #c0392b;
  --violet: #6b4fbb;
  --azure: #1a62d6;
  --bone:   #4a5561;

  --ok:   #147d64;
  --warn: #b26a00;
  --bad:  #c0392b;

  --page-bg: #ffffff;
  --texture-image: none;
  --texture-opacity: 0;
  --panel-bg: #ffffff;
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #e3e7ec;
  --panel-radius: 6px;
  --panel-pad: 16px 18px 18px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06);
  --radius: 5px;

  /* Icons lose their glow and their gold: flat, one weight, the colour of a
     label rather than an ornament. */
  --icon-color: #5b6673;
  --icon-glow: none;
  --chip-bg: #f1f3f5;
  --chip-border: #dfe3e7;

  --font-display: 'Spectral', Georgia, serif;  /* A white page: primary buttons need white ink, the meter keeps a dark
     track under its pale numbers, and nothing casts a heavy shadow. */
  --btn-primary-ink: #ffffff;
  /* Its --warn is the one dark enough that the Hall's brown-black ink falls
     short on it (4.4:1), so the yellow pill takes black: 4.9:1. */
  --notice-ink: #000000;
  --att-track: #2a3139;
  --title-shadow: none;
  --ornament-display: none;
  --tag-ink-mix: 60%;
}


/* The one thing a white theme cannot inherit: a heading colour meant for gold
   on black. Headings take the ink colour, and weight does the work instead. */
[data-theme='clinical'] h1,
[data-theme='clinical'] h2,
[data-theme='clinical'] h3,
[data-theme='clinical'] h4,
[data-theme='clinical'] .display { color: #11161c; letter-spacing: 0; }

/* ---- Clinical Dark: the same plainness at night -------------------------- */

[data-theme='clinical-dark'] {
  --surface-1: #151b23;
  --surface-2: #11161d;
  --surface-sunken: #0f141a;
  --accent-wash: rgba(88, 166, 255, .12);
  --btn-primary-bg: linear-gradient(180deg, #1f4d7a, #17385a);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 14px 14px 16px;
  --ink:        #0d1117;
  --stone-900:  #0d1117;
  --stone-800:  #151b23;
  --stone-700:  #1c232c;
  --stone-600:  #2a323d;
  --stone-500:  #3d4652;

  --gold:       #58a6ff;
  --gold-bright:#9ecbff;
  --gold-dim:   #5b8fd0;
  --parchment:  #e6edf3;
  --text:       #e6edf3;
  --text-dim:   #a7b3c0;
  --text-faint: #6e7d8d;

  --jade:   #3fb950;
  --blood:  #f85149;
  --violet: #bc8cff;
  --azure:  #58a6ff;
  --bone:   #a7b3c0;

  --ok:   #3fb950;
  --warn: #d29922;
  --bad:  #f85149;

  --page-bg: #0d1117;
  --texture-image: none;
  --texture-opacity: 0;
  --panel-bg: #151b23;
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #2a323d;
  --panel-radius: 6px;
  --panel-pad: 16px 18px 18px;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4);
  --radius: 5px;

  --icon-color: #8b98a5;
  --icon-glow: none;
  --chip-bg: #1c232c;
  --chip-border: #2a323d;

  --font-display: 'Spectral', Georgia, serif;  --title-shadow: none;
  --ornament-display: none;
  --badge-ink: #1a0506;
  --att-track: var(--surface-sunken);
  --tag-ink-mix: 80%;
}


[data-theme='clinical-dark'] h1,
[data-theme='clinical-dark'] h2,
[data-theme='clinical-dark'] h3,
[data-theme='clinical-dark'] h4,
[data-theme='clinical-dark'] .display { color: #e6edf3; letter-spacing: 0; }

/* ---- Deep Dungeon: wet stone, torchlight, iron --------------------------- */

[data-theme='dungeon'] {
  --surface-1: linear-gradient(180deg, rgba(33,38,41,.85), rgba(16,19,21,.9));
  --surface-2: linear-gradient(180deg, rgba(16,19,21,.97), rgba(8,9,10,.95));
  --surface-sunken: rgba(0,0,0,.45);
  --accent-wash: rgba(185, 139, 74, .12);
  --btn-primary-bg: linear-gradient(180deg, #4a3a22, #2a2114);
  --frame-width-narrow: 2px;
  --panel-pad-narrow: 12px 14px 14px;
  --ink:        #08090a;
  --stone-900:  #101315;
  --stone-800:  #171b1e;
  --stone-700:  #212629;
  --stone-600:  #2e3539;
  --stone-500:  #434c52;

  --gold:       #b98b4a;
  --gold-bright:#e0b877;
  --gold-dim: #9a7a4a;
  --parchment:  #cfc9bd;
  --text:       #c3beb4;
  --text-dim:   #a39e94;
  --text-faint: #7d786f;

  --jade:   #5c8f7b;
  --blood:  #9c3b2c;
  --violet: #7d6d9e;
  --azure:  #5f7d99;
  --bone:   #b6afa1;

  --ok:   #6d9b63;
  --warn: #c08a3e;
  --bad: #cf5a42;

  --page-bg: #0b0d0e;
  /* Mortared blocks rather than interlace: straight courses, offset by half a
     block, drawn faintly enough to read text over. */
  --texture-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40' viewBox='0 0 80 40'%3E%3Cg fill='none' stroke='%23434c52' stroke-width='1'%3E%3Cpath d='M0,0 H80 M0,20 H80 M0,40 H80'/%3E%3Cpath d='M20,0 V20 M60,0 V20 M40,20 V40 M0,20 V40 M80,20 V40'/%3E%3C/g%3E%3C/svg%3E");
  --texture-opacity: .16;
  --panel-bg: linear-gradient(180deg, rgba(33,38,41,.95), rgba(16,19,21,.97));
  --frame-source: none;
  --frame-width: 0px;
  /* Iron banding instead of a woven frame: a heavy outer edge and a thin inner
     one, which reads as a plate bolted to the wall. */
  --panel-border: 2px solid #2e3539;
  --panel-radius: 2px;
  --panel-pad: 14px 18px 16px;
  --shadow: 0 12px 34px rgba(0,0,0,.62), inset 0 0 0 1px rgba(255,255,255,.03);
  --radius: 2px;

  --icon-color: #b98b4a;
  --icon-glow: drop-shadow(0 0 3px rgba(185, 139, 74, .35));
  --chip-bg: rgba(46,53,57,.6);
  --chip-border: #434c52;  --font-display: 'Cinzel', Georgia, 'Times New Roman', serif;
  --att-track: var(--surface-sunken);
  --tag-ink-mix: 80%;
  --badge-ink: #1a0506;
}


/* ---- Infernal: char and old blood, lit from below ------------------------ */

[data-theme='demonic'] {
  --surface-1: linear-gradient(180deg, rgba(42,16,17,.85), rgba(20,7,8,.9));
  --surface-2: linear-gradient(180deg, rgba(20,7,8,.97), rgba(10,4,5,.95));
  --surface-sunken: rgba(0,0,0,.5);
  --accent-wash: rgba(217, 79, 61, .14);
  --btn-primary-bg: linear-gradient(180deg, #7a2a20, #4a1712);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 12px 14px 14px;
  --ink:        #0a0405;
  --stone-900:  #140708;
  --stone-800:  #1d0b0c;
  --stone-700:  #2a1011;
  --stone-600:  #3d1718;
  --stone-500:  #5a2223;

  --gold:       #d94f3d;
  --gold-bright:#ff8a6b;
  --gold-dim:   #b3453a;
  --parchment:  #e8cfc6;
  --text:       #d8c3bc;
  --text-dim:   #a08079;
  --text-faint: #7a5a55;

  --jade:   #7a8f4f;
  --blood:  #e0483a;
  --violet: #9b5fb0;
  --azure:  #7a6fb0;
  --bone:   #c9ada4;

  --ok:   #8fae5f;
  --warn: #e09a3e;
  --bad:  #ff5340;

  --page-bg: radial-gradient(120% 90% at 50% 100%, #2a0b0c 0%, #140708 45%, #0a0405 100%);
  /* Embers: sparse, uneven, and warm. */
  --texture-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='70' height='70' viewBox='0 0 70 70'%3E%3Cg fill='%23d94f3d'%3E%3Ccircle cx='12' cy='18' r='1.1'/%3E%3Ccircle cx='48' cy='9' r='.8'/%3E%3Ccircle cx='63' cy='41' r='1.3'/%3E%3Ccircle cx='29' cy='55' r='.9'/%3E%3Ccircle cx='6' cy='62' r='.7'/%3E%3C/g%3E%3C/svg%3E");
  --texture-opacity: .22;
  --panel-bg: linear-gradient(180deg, rgba(42,16,17,.94), rgba(20,7,8,.96));
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #5a2223;
  --panel-radius: 3px;
  --panel-pad: 14px 18px 16px;
  /* Lit from below, as if something is burning under the floor. */
  --shadow: 0 -6px 26px rgba(217, 79, 61, .13), 0 14px 34px rgba(0,0,0,.6);
  --radius: 3px;

  --icon-color: #e0483a;
  --icon-glow: drop-shadow(0 0 5px rgba(224, 72, 58, .55));
  --chip-bg: rgba(61,23,24,.7);
  --chip-border: #5a2223;  --font-display: 'Cinzel', Georgia, 'Times New Roman', serif;
  --badge-ink: #1a0506;
  --att-track: var(--surface-sunken);
  --btn-primary-ink: #ffd9cf;
  --tag-ink-mix: 80%;
}


/* ---- Greenwood: bark, moss, lantern-light through leaves ----------------- */

[data-theme='grove'] {
  --surface-1: linear-gradient(180deg, rgba(36,48,36,.82), rgba(19,26,19,.9));
  --surface-2: linear-gradient(180deg, rgba(19,26,19,.96), rgba(12,17,12,.94));
  --surface-sunken: rgba(0,0,0,.34);
  --accent-wash: rgba(184, 196, 106, .12);
  --btn-primary-bg: linear-gradient(180deg, #4a5c2c, #2d3a1c);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 12px 14px 14px;
  --ink:        #0c110c;
  --stone-900:  #131a13;
  --stone-800:  #1a241a;
  --stone-700:  #243024;
  --stone-600:  #324232;
  --stone-500:  #475c45;

  --gold:       #b8c46a;
  --gold-bright:#dfe9a4;
  --gold-dim:   #6d7a3c;
  --parchment:  #e4e6cf;
  --text:       #d2d8c2;
  --text-dim:   #9aa489;
  --text-faint: #6f7a62;

  --jade:   #6fbf8f;
  --blood:  #b8563f;
  --violet: #a08ac0;
  --azure:  #6f9fb0;
  --bone:   #c8cdb2;

  --ok:   #7fbf6a;
  --warn: #d8b055;
  --bad: #d9694d;

  --page-bg: linear-gradient(180deg, #131a13 0%, #0c110c 100%);
  /* Leaf litter: small strokes at angles, nothing repeating too obviously. */
  --texture-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 64 64'%3E%3Cg fill='none' stroke='%236d7a3c' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M8,14 q6,-7 13,-2'/%3E%3Cpath d='M44,8 q7,5 4,12'/%3E%3Cpath d='M52,44 q-7,6 -13,1'/%3E%3Cpath d='M14,48 q-5,-8 2,-13'/%3E%3C/g%3E%3C/svg%3E");
  --texture-opacity: .14;
  --panel-bg: linear-gradient(180deg, rgba(36,48,36,.92), rgba(19,26,19,.95));
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #324232;
  --panel-radius: 10px;
  --panel-pad: 14px 18px 16px;
  --shadow: 0 10px 28px rgba(0,0,0,.45);
  --radius: 8px;

  --icon-color: #9fbf6a;
  --icon-glow: drop-shadow(0 0 3px rgba(159, 191, 106, .3));
  --chip-bg: rgba(50,66,50,.6);
  --chip-border: #475c45;  --font-display: 'Cinzel', Georgia, 'Times New Roman', serif;
  --att-track: var(--surface-sunken);
  --badge-ink: #1a0506;
  --tag-ink-mix: 80%;
}


/* ---- Crystalline: pale light through cut stone --------------------------- */

[data-theme='crystal'] {
  --surface-1: linear-gradient(180deg, rgba(29,44,77,.8), rgba(17,26,48,.88));
  --surface-2: linear-gradient(180deg, rgba(17,26,48,.96), rgba(11,16,32,.94));
  --surface-sunken: rgba(8, 12, 26, .6);
  --accent-wash: rgba(127, 216, 255, .13);
  --btn-primary-bg: linear-gradient(180deg, #245a7a, #163a52);
  --frame-width-narrow: 1px;
  --panel-pad-narrow: 12px 14px 14px;
  --ink:        #0b1020;
  --stone-900:  #111a30;
  --stone-800:  #16223d;
  --stone-700:  #1d2c4d;
  --stone-600:  #2a3d66;
  --stone-500:  #3e548a;

  --gold:       #7fd8ff;
  --gold-bright:#c9f0ff;
  --gold-dim:   #3f7fa8;
  --parchment:  #e8f3ff;
  --text:       #dbe8f7;
  --text-dim:   #a3b6d0;
  --text-faint: #7286a5;

  --jade:   #6fe0c0;
  --blood:  #ef5f8a;
  --violet: #b79bff;
  --azure:  #7fd8ff;
  --bone:   #cddcf0;

  --ok:   #5fd6a8;
  --warn: #ffc76b;
  --bad:  #ff6b8a;

  --page-bg: radial-gradient(120% 80% at 50% 0%, #1d2c4d 0%, #111a30 50%, #0b1020 100%);
  /* Facets: long thin shards at two angles, catching the light. */
  --texture-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90' viewBox='0 0 90 90'%3E%3Cg fill='none' stroke='%237fd8ff' stroke-width='1'%3E%3Cpath d='M10,0 L30,45 L10,90'/%3E%3Cpath d='M60,0 L80,45 L60,90'/%3E%3Cpath d='M30,45 H60'/%3E%3C/g%3E%3C/svg%3E");
  --texture-opacity: .1;
  --panel-bg: linear-gradient(180deg, rgba(29,44,77,.88), rgba(17,26,48,.93));
  --frame-source: none;
  --frame-width: 0px;
  --panel-border: 1px solid #2a3d66;
  --panel-radius: 4px;
  --panel-pad: 14px 18px 16px;
  --shadow: 0 10px 30px rgba(11, 16, 32, .6), inset 0 0 0 1px rgba(127, 216, 255, .08);
  --radius: 4px;

  --icon-color: #9fe4ff;
  --icon-glow: drop-shadow(0 0 5px rgba(127, 216, 255, .45));
  --chip-bg: rgba(42,61,102,.55);
  --chip-border: #3e548a;  --font-display: 'Cinzel', Georgia, 'Times New Roman', serif;
  --badge-ink: #1a0610;
  --att-track: var(--surface-sunken);
  --tag-ink-mix: 80%;
}


/* The furniture takes the theme's own link colour rather than gold. */
[data-theme='clinical'] .nav a,
[data-theme='clinical-dark'] .nav a,
[data-theme='daylight'] .nav a { color: var(--text-dim); }
[data-theme='clinical'] .nav a.active,
[data-theme='clinical-dark'] .nav a.active,
[data-theme='daylight'] .nav a.active { color: var(--gold); }

/* The plain looks have no ornaments at all: the knot divider becomes a plain
   hairline, keeping its spacing. */
[data-theme='clinical'] hr.knot,
[data-theme='clinical-dark'] hr.knot {
  -webkit-mask: none;
  mask: none;
  height: 1px;
  background: var(--stone-600);
}
/* Daylight's divider is a dashed line in the same sand as its borders. */
[data-theme='daylight'] hr.knot {
  -webkit-mask: none;
  mask: none;
  height: 0;
  background: none;
  border: 0;
  border-top: 1px dashed var(--stone-500);
}

/* ==== Illustrated borders ===========================================
   The four dark looks frame their panels in art, not only colour: stone,
   thorns and blood, bark and vines, cut glass and crystal shards. Each is
   built from free art credited on /credits, and each block below is scoped
   to its own look, so the Hall, the two clinical looks and Daylight never see it.
   Ornaments sit in .panel::before and ::after, under the panel content and
   over its frame, with pointer-events off. */

/* ---- Deep Dungeon: hewn stone ------------------------------------------ */
/* ---- Dungeon: a frame of hewn stone ------------------------------------------

   frame.webp is a 9-slice: a course of hewn blocks on each side, cut from the
   Stone Brick Wall photo, greyed, darkened and lit from above, with dark mortar
   joints. The course sits in the inner 18px of the 26px band, so the transparent
   outer 8px lets the corner stones stand out beyond it. Every tile starts and
   ends on a half joint, so with `round` every corner meets a clean joint and
   the repeats are hidden in the mortar.

   The top and bottom tiles are short (148.5px: three blocks, the long one in
   the middle), because `round` can only squeeze a whole tile into a narrow
   card: a 200px card shows the tile at its own size, a 90px card squeezes it
   about 4x, and what shows between the quoins there is the middle block. The
   side tiles (104.5px) and the corner squares are the first cut's, unchanged.

   The two pseudo-elements carry the heavy corner stones (quoins), two to each,
   drawn over the frame's own corner squares. They stay inside the border box
   (so they never widen a scroll box), and z-index -1 puts them above the frame
   but below every piece of panel content. */
[data-theme='dungeon'] {
  --frame-source: url('/img/looks/dungeon/frame.webp');
  --frame-slice: 52;
  --frame-width: 26px;
  --panel-border: 26px solid transparent;
  --panel-radius: 0px;
  --panel-pad: 10px 16px 14px;
  --frame-width-narrow: 15px;
  --panel-pad-narrow: 8px 10px 12px;
  --dq-size: 34px;          /* quoin: the frame's 26px corner plus 8px */
  --dq-out: 26px;           /* = the frame width, so it lands on the corner */
}

[data-theme='dungeon'] .panel {
  /* The panel's ground stops at the stone; the band's outer 8px shows the wall. */
  background-clip: padding-box;
  border-image-repeat: round;
  /* A drop shadow onto the wall, and the recess the frame casts onto the panel
     (from above and the left, where the light comes from). */
  box-shadow: 0 10px 26px rgba(0,0,0,.55),
              inset 0 7px 9px -6px rgba(0,0,0,.75),
              inset 6px 0 8px -7px rgba(0,0,0,.5);
}

[data-theme='dungeon'] .panel::before,
[data-theme='dungeon'] .panel::after {
  content: '';
  position: absolute;
  left: calc(-1 * var(--dq-out));
  right: calc(-1 * var(--dq-out));
  height: var(--dq-size);
  z-index: -1;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size: var(--dq-size) var(--dq-size);
}
[data-theme='dungeon'] .panel::before {
  top: calc(-1 * var(--dq-out));
  background-image: url('/img/looks/dungeon/quoin-a.webp'), url('/img/looks/dungeon/quoin-b.webp');
  background-position: left top, right top;
}
[data-theme='dungeon'] .panel::after {
  bottom: calc(-1 * var(--dq-out));
  background-image: url('/img/looks/dungeon/quoin-b.webp'), url('/img/looks/dungeon/quoin-a.webp');
  background-position: left bottom, right bottom;
}

/* Phones. app.css swaps in --frame-width-narrow at max-width 560px (not 700px),
   so the quoins shrink at exactly that width: they have to match the frame's
   corner squares, and at 561-700px those are still the full 26px. */
@media (max-width: 560px) {
  [data-theme='dungeon'] {
    --dq-size: 20px;
    --dq-out: 15px;         /* = --frame-width-narrow */
  }
}

/* ---- Infernal: thorns and blood ---------------------------------------- */
/*
 * Demonic: a dark thorn frame, blood dripping from its top run, and on some
 * panels a splash soaked into one corner. Everything sits in the frame band,
 * the top padding, or the outer corner: nothing is drawn over content.
 */
[data-theme='demonic'] {
  --frame-source: url('/img/looks/demonic/frame.svg');
  --frame-slice: 116.3;
  --frame-width: 20px;
  --panel-border: 20px solid transparent;
  --panel-pad: 20px 20px 18px;
  --frame-width-narrow: 12px;
  --panel-pad-narrow: 14px 12px 12px;
  --panel-radius: 0px;
  /* ornament geometry, private to this look */
  --dm-bw: var(--frame-width);   /* the frame width actually in force */
  --dm-drip-h: 28px;
  --dm-drip-x: 0px;
  --dm-splat: 38px;              /* the splash on a big panel */
  --dm-splat-min: 15px;          /* what it starts from on the smallest card */
  --dm-splat-off: calc(var(--dm-bw) * -0.78);
}

/* The thorns' outer tips stand on the page, not on the panel's fill. */
[data-theme='demonic'] .panel { background-clip: padding-box; }

/* Blood hanging from the top run of the vine. */
[data-theme='demonic'] .panel::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--dm-bw) * -0.66);
  height: var(--dm-drip-h);
  background: url('/img/looks/demonic/drips.svg') var(--dm-drip-x) 0 / auto var(--dm-drip-h) repeat-x;
  /* thin out where the run meets the side vines rather than stopping in a cut */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14px, #000 calc(100% - 14px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 14px, #000 calc(100% - 14px), transparent);
  pointer-events: none;
}
/* Neighbouring panels should not drip in step. */
/* Seven drip offsets: a cycle no card grid shares (2, 3 and 4 columns all fall
   out of step with it) and one the splash's five-cycle never lines up with. */
[data-theme='demonic'] .panel:nth-child(7n+2) { --dm-drip-x: -130px; }
[data-theme='demonic'] .panel:nth-child(7n+3) { --dm-drip-x: -255px; }
[data-theme='demonic'] .panel:nth-child(7n+4) { --dm-drip-x: -60px; }
[data-theme='demonic'] .panel:nth-child(7n+5) { --dm-drip-x: -190px; }
[data-theme='demonic'] .panel:nth-child(7n+6) { --dm-drip-x: -95px; }
[data-theme='demonic'] .panel:nth-child(7n) { --dm-drip-x: -220px; }

/*
 * A splash soaked into one corner of the frame. Its size follows the panel:
 * the box grows with the panel's width one way and its height the other,
 * and the splash is drawn to fit that box from the corner outwards. A 90px
 * card gets a blot that stays on the frame band, a 280px card about 25px, a
 * short strip is held down by its height, and only a big panel gets 38px.
 */
[data-theme='demonic'] .panel::after {
  content: '';
  position: absolute;
  right: var(--dm-splat-off);
  bottom: var(--dm-splat-off);
  width: min(calc(var(--dm-splat-min) + 4%), var(--dm-splat));
  height: min(calc(var(--dm-splat-min) + 16%), var(--dm-splat));
  background: url('/img/looks/demonic/spatter.svg') right bottom / contain no-repeat;
  /* over the frame, under the panel's content (the panel is a stacking context) */
  z-index: -1;
  pointer-events: none;
}
/*
 * Not every panel is splashed, nor at the same corner. The cycle is five
 * long so it never falls in step with the three-long drip cycle, nor with a
 * grid of two, three or four columns. The first panel of a page keeps the
 * bottom-right splash.
 */
[data-theme='demonic'] .panel:nth-child(5n+2)::after {   /* top left, turned over */
  top: var(--dm-splat-off);
  bottom: auto;
  left: var(--dm-splat-off);
  right: auto;
  transform: rotate(180deg);
}
[data-theme='demonic'] .panel:nth-child(5n+3)::after,     /* clean */
[data-theme='demonic'] .panel:nth-child(5n)::after { content: none; }
[data-theme='demonic'] .panel:nth-child(5n+4)::after {   /* bottom left, mirrored */
  left: var(--dm-splat-off);
  right: auto;
  transform: scaleX(-1);
}

@media (max-width: 700px) {
  [data-theme='demonic'] { --dm-drip-h: 22px; --dm-splat: 31px; }
}
@media (max-width: 560px) {
  /* app.css narrows the frame here */
  [data-theme='demonic'] { --dm-bw: var(--frame-width-narrow); --dm-drip-h: 17px; --dm-splat: 25px; --dm-splat-min: 11px; }
}

/* ---- Greenwood: bark and vines ----------------------------------------- */
/* ---- grove: a bark frame with vines -------------------------------------
 * The band is Tree Bark 03 (Poly Haven, CC0), darkened and moss-tinted, laid
 * out as a 9-slice whose edges each carry one whole texture period, so
 * `round` joins tile to tile and edge to corner without a seam. All four
 * edges come from the clean middle of the bark and share one tone curve, so
 * no side is mossier or darker than another.
 * Two vines ride over it: the Celtic vine corner at top-left and (turned
 * half round) bottom-right, and a run of ivy along the top edge into the
 * top-right corner (and, turned, bottom-left). Both are painted by ::before
 * and ::after as panel-sized overlays whose middles are empty; they sit
 * under the panel's content (z-index -1 inside the panel's own stacking
 * context) and never take a click.
 */
[data-theme='grove'] {
  --frame-source: url('/img/looks/grove/bark-frame.webp');
  --frame-slice: 36;
  --frame-width: 18px;
  --panel-border: 18px solid transparent;
  --panel-radius: 0px;
  /* 2px more on the left keeps the knot at top-left clear of a heading */
  --panel-pad: 14px 20px 16px 22px;
  --frame-width-narrow: 10px;
  --panel-pad-narrow: 12px 14px 14px;
}

/*
 * The knot is drawn at one fixed scale per frame width, the scale at which
 * its two arms lie along the bark band, so it never shrinks to hairlines or
 * drifts off the bark. What changes with the panel is how far the arms run:
 * six drawings of the same knot, horizontal arm long or short (L/S) and
 * vertical arm long, medium or short (L/M/S), each cut arm ending in one of
 * the source's own leaves. Exactly one is shown: each layer's width is
 * switched on or off by the box width and its height by the box height,
 * clamp(0px, (100% - threshold) * 100000, size) being a step at the
 * threshold, and a layer with a zero side is not painted. The thresholds
 * are where a longer arm still clears the ivy at the far end of that edge.
 * (Thresholds sit off whole 1/64 px so a layout size never lands on the step.)
 */
[data-theme='grove'] .panel::before,
[data-theme='grove'] .panel::after {
  content: '';
  position: absolute;
  /* the 18px border + 5px of overhang past the outer edge */
  top: -23px; right: -23px; bottom: -23px; left: -23px;
  pointer-events: none;
  z-index: -1;
  --k: 0.28602;          /* px per unit of the vine drawing (150px for the full 524-unit height) */
  --tw: 280.3px;         /* box width from which the long top arm fits beside the ivy */
  --thm: 141.3px;        /* box height from which the medium side arm fits above the ivy */
  --thl: 202.3px;        /* ... and the long one */
  /* the ivy follows the width; on a box too narrow for it to read, it is left out */
  --ivy: min(130px, 40%, clamp(0px, (100% - 150.3px) * 100000, 130px));
  --wl: clamp(0px, (100% - var(--tw)) * 100000, 556.22px * var(--k));
  /* An exact tie at a threshold (it happens under the big-screen zoom, where the
     thresholds land on the layout grid) picks the SHORTER vine: each threshold
     moves one side of its switch by 0.005px, a third of a layout step - never
     both, or a tie would draw two knots at once. */
  --ws: clamp(0px, (var(--tw) + 0.005px - 100%) * 100000, 217.5px * var(--k));
  --hl: clamp(0px, (100% - var(--thl)) * 100000, 524.43px * var(--k));
  --hm: clamp(0px, min(100% - var(--thm), var(--thl) + 0.005px - 100%) * 100000, 311px * var(--k));
  --hs: clamp(0px, (var(--thm) + 0.005px - 100%) * 100000, 191.5px * var(--k));
  /* a browser without clamp() gets the full vine and the ivy at fixed sizes */
  background-image: url('/img/looks/grove/vine-corner.svg'), url('/img/looks/grove/ivy-corner.svg');
  background-repeat: no-repeat;
  background-position: left top, right top;
  background-size: auto 150px, 130px auto;
}
/* The same pair, turned half round: knot at bottom-right, ivy at bottom-left. */
[data-theme='grove'] .panel::after { transform: rotate(180deg); }

@media (max-width: 700px) {
  [data-theme='grove'] .panel::before,
  [data-theme='grove'] .panel::after { --ivy: min(112px, 38%, clamp(0px, (100% - 150.3px) * 100000, 112px)); }
}
/* app.css narrows the frame itself at 560px; the vines follow it down. */
@media (max-width: 560px) {
  [data-theme='grove'] .panel::before,
  [data-theme='grove'] .panel::after {
    /* the 10px narrow border + 3px of overhang */
    top: -13px; right: -13px; bottom: -13px; left: -13px;
    --k: 0.1678;         /* 88px for the full drawing: the arms on a 10px band */
    --tw: 156.3px;
    --thm: 83.3px;
    --thl: 119.3px;
    --ivy: min(72px, 36%, clamp(0px, (100% - 110.3px) * 100000, 72px));
    background-size: auto 88px, 72px auto;
  }
}

/* Kept last so it wins over the fixed sizes above at every width. */
@supports (width: clamp(1px, 1px, 1px)) {
  [data-theme='grove'] .panel::before,
  [data-theme='grove'] .panel::after {
    background-image:
      url('/img/looks/grove/vine-corner.svg'), url('/img/looks/grove/vine-lm.svg'), url('/img/looks/grove/vine-ls.svg'),
      url('/img/looks/grove/vine-sl.svg'), url('/img/looks/grove/vine-sm.svg'), url('/img/looks/grove/vine-ss.svg'),
      url('/img/looks/grove/ivy-corner.svg');
    background-position: left top, left top, left top, left top, left top, left top, right top;
    background-size:
      var(--wl) var(--hl), var(--wl) var(--hm), var(--wl) var(--hs),
      var(--ws) var(--hl), var(--ws) var(--hm), var(--ws) var(--hs),
      var(--ivy) auto;
  }
}

/* ---- Crystalline: cut glass and shards --------------------------------- */
/* ---- Crystalline: the frame ------------------------------------------------
   A cut-glass bevel - two facets and a lit ridge, a faceted stud at each
   corner - drawn as a 9-slice with plain, even edges, and a cluster of shards
   growing out of the top-left and bottom-right corners. Both images are
   vector; the two clusters are one sprite of two square cells.

   The shards sit on the frame and outside it, never over the content: they
   paint at z-index -1 inside the panel (above its ground and frame, below
   anything in it) and are placed from the frame's outer corner, so they need
   to know how thick the frame is - --crystal-bw, which follows the frame's
   own narrowing at 560px (app.css).

   A cell is --crystal-orn wide, or 40% of the panel's width on a small card.
   Every length that depends on it is a width or a margin, because a margin's
   percentage is always of the panel's width - so a small card gets a
   proportionally smaller cluster.

   The top-left cluster leans LEFT and the bottom-right one DOWN, mirror images
   across the panel's rising diagonal, because neither may go far the other
   way. Above a panel there can be a row of Admin tabs, a read-only banner or
   an alert only 14-18px away, so the top-left cluster, glow included, reaches
   at most 12px above the panel (8px on phones); to the left it has main's
   side padding (22px, or 14px on phones) and reaches 20px (13px). The panel's
   corner sits .53125 of a cell in from that cell's left edge and .40625 in
   from its top. The bottom-right cell overhangs the corner by only .25 of a
   cell to the right (16px at most, 10.5px on phones), since overflow to the
   right can be scrolled and must stay inside main's side padding. Each glow
   fades out inside its own cell, so no cell edge ever shows. */

[data-theme='crystal'] {
  --frame-source: url('/img/looks/crystal/frame.svg');
  --frame-slice: 33;
  --frame-width: 11px;
  --panel-border: 11px solid transparent;
  --panel-radius: 6px;          /* clips the ground to the frame's chamfer */
  --panel-pad: 10px 18px 15px;
  --frame-width-narrow: 6px;
  --panel-pad-narrow: 8px 12px 12px;
  --crystal-bw: 11px;
  --crystal-orn: 64px;
}

[data-theme='crystal'] .panel::before,
[data-theme='crystal'] .panel::after {
  --crystal-cell: min(var(--crystal-orn), 40%);
  content: '';
  position: absolute;
  width: var(--crystal-cell);
  aspect-ratio: 1;
  background: url('/img/looks/crystal/shards.svg') no-repeat;
  background-size: 200% 100%;
  pointer-events: none;
  z-index: -1;
}
[data-theme='crystal'] .panel::before {
  top: calc(-1 * var(--crystal-bw));
  left: calc(-1 * var(--crystal-bw));
  margin: calc(var(--crystal-cell) * -.40625) 0 0 calc(var(--crystal-cell) * -.53125);
  background-position: 0 0;
}
[data-theme='crystal'] .panel::after {
  bottom: calc(-1 * var(--crystal-bw));
  right: calc(-1 * var(--crystal-bw));
  margin: 0 calc(var(--crystal-cell) * -.25) calc(var(--crystal-cell) * -.375) 0;
  background-position: 100% 0;
}

/* Phones: a thinner frame, and clusters to match it. */
@media (max-width: 560px) {
  [data-theme='crystal'] { --crystal-bw: 6px; --crystal-orn: 42px; }
}
