@charset "UTF-8";
/*
 * Basalt, a Bootstrap 5.3 admin template. SCSS entry point; compiles to
 * assets/basalt/css/basalt.css, which loads after assets/basalt/css/bootstrap.css (built
 * from bootstrap.scss beside this file).
 *
 * The partials hold the same rules, in the same order, as the shipped
 * basalt.css; compiling this file reproduces it. Edit a partial, then
 * rebuild (see documentation.html, "Compiling SCSS").
 */
/* The two self-hosted variable webfonts, Schibsted Grotesk for text and Chivo
   Mono for figures and code. One file per subset holds every weight. Both are
   licensed under the SIL Open Font License 1.1 (assets/basalt/fonts/OFL.txt). */
/* Unicode ranges of the two subsets each family ships. */
/* Each family lists its weight span and the file prefix of its subsets. */
@font-face {
	font-family: "Schibsted Grotesk";
	font-style: normal;
	font-weight: 400 900;
	font-display: swap;
	unicode-range:
		U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
		U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
	src: url("../fonts/schibsted-latin-ext.woff2") format("woff2");
}
@font-face {
	font-family: "Schibsted Grotesk";
	font-style: normal;
	font-weight: 400 900;
	font-display: swap;
	unicode-range:
		U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
		U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
	src: url("../fonts/schibsted-latin.woff2") format("woff2");
}
@font-face {
	font-family: "Chivo Mono";
	font-style: normal;
	font-weight: 300 700;
	font-display: swap;
	unicode-range:
		U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
		U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
	src: url("../fonts/chivomono-latin-ext.woff2") format("woff2");
}
@font-face {
	font-family: "Chivo Mono";
	font-style: normal;
	font-weight: 300 700;
	font-display: swap;
	unicode-range:
		U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
		U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
	src: url("../fonts/chivomono-latin.woff2") format("woff2");
}
/* themes/_tokens.scss holds the palette values: every palette's light and
   dark set, and the two surface switches. A dark set lists only what changes;
   anything it leaves out keeps its light value. The other theme partials
   write them out as custom properties. */
/* Basalt stylesheet, built from assets/basalt/scss/basalt.scss. This first layer
   holds the color tokens; every later rule reads them and none repeats a hex. */
/**
 * Writes one palette's map out as `--basalt-*` custom properties. A `series`
 * entry is a list and becomes the numbered chart slots, series-1 upward.
 * Values that carry an alpha or a comma list are kept as quoted strings in the
 * maps, so they reach the stylesheet exactly as written.
 */
/* Dusk is Basalt's own palette and what the page wears before any palette
   attribute is set, so its light set sits on the root itself. */
:root,
[data-bs-theme="light"] {
	--basalt-canvas: #fbfbfe;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #eeebf8;
	--basalt-wash: #f3f1fb;
	--basalt-edge: rgba(38, 28, 70, 0.09);
	--basalt-edge-strong: rgba(38, 28, 70, 0.15);
	--basalt-copy: #191430;
	--basalt-copy-body: #403a5e;
	--basalt-copy-muted: #6e6790;
	--basalt-copy-faint: #a49dc2;
	--basalt-hue: #6d3fe0;
	--basalt-hue-deep: #4e23b8;
	--basalt-hue-soft: #eee8fd;
	--basalt-hue-border: rgba(109, 63, 224, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #8ecdf7;
	--basalt-flare-soft: #e6f3fd;
	--basalt-grad: linear-gradient(120deg, #8b3fd0 0%, #6d3fe0 48%, #4a1f9e 100%);
	--basalt-grad-soft: linear-gradient(135deg, #eee8fd 0%, #f7e8f2 100%);
	--basalt-success: #17a673;
	--basalt-success-soft: rgba(23, 166, 115, 0.12);
	--basalt-warning: #e0952a;
	--basalt-warning-soft: rgba(224, 149, 42, 0.14);
	--basalt-danger: #e0446b;
	--basalt-danger-soft: rgba(224, 68, 107, 0.12);
	--basalt-info: #5b7ce8;
	--basalt-info-soft: rgba(91, 124, 232, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(38, 28, 70, 0.05), 0 10px 28px rgba(38, 28, 70, 0.07);
	--basalt-scrim: rgba(25, 20, 48, 0.44);
	--basalt-series-1: #6d3fe0;
	--basalt-series-2: #6c7ae0;
	--basalt-series-3: #8ecdf7;
	--basalt-series-4: #b8a9f0;
	--basalt-series-5: #d98ab8;
	--basalt-series-6: #f0a9cf;
	--basalt-series-7: #9c5ce8;
	--basalt-series-8: #7fb3e8;
}

/* Every core palette is also keyed by the value `data-basalt-palette` takes,
   Dusk included, so an element can wear any palette whatever the page is set
   to. Only their light sets are written here; themes/_dark.scss follows with
   the dark ones, and that later position is what lets dark win the equal
   tie. A named palette answers both to its bare attribute and to an explicit
   light scheme, which keeps it ahead of the root set above. */
[data-basalt-palette="dusk"],
[data-basalt-palette="dusk"][data-bs-theme="light"] {
	--basalt-canvas: #fbfbfe;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #eeebf8;
	--basalt-wash: #f3f1fb;
	--basalt-edge: rgba(38, 28, 70, 0.09);
	--basalt-edge-strong: rgba(38, 28, 70, 0.15);
	--basalt-copy: #191430;
	--basalt-copy-body: #403a5e;
	--basalt-copy-muted: #6e6790;
	--basalt-copy-faint: #a49dc2;
	--basalt-hue: #6d3fe0;
	--basalt-hue-deep: #4e23b8;
	--basalt-hue-soft: #eee8fd;
	--basalt-hue-border: rgba(109, 63, 224, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #8ecdf7;
	--basalt-flare-soft: #e6f3fd;
	--basalt-grad: linear-gradient(120deg, #8b3fd0 0%, #6d3fe0 48%, #4a1f9e 100%);
	--basalt-grad-soft: linear-gradient(135deg, #eee8fd 0%, #f7e8f2 100%);
	--basalt-success: #17a673;
	--basalt-success-soft: rgba(23, 166, 115, 0.12);
	--basalt-warning: #e0952a;
	--basalt-warning-soft: rgba(224, 149, 42, 0.14);
	--basalt-danger: #e0446b;
	--basalt-danger-soft: rgba(224, 68, 107, 0.12);
	--basalt-info: #5b7ce8;
	--basalt-info-soft: rgba(91, 124, 232, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(38, 28, 70, 0.05), 0 10px 28px rgba(38, 28, 70, 0.07);
	--basalt-scrim: rgba(25, 20, 48, 0.44);
	--basalt-series-1: #6d3fe0;
	--basalt-series-2: #6c7ae0;
	--basalt-series-3: #8ecdf7;
	--basalt-series-4: #b8a9f0;
	--basalt-series-5: #d98ab8;
	--basalt-series-6: #f0a9cf;
	--basalt-series-7: #9c5ce8;
	--basalt-series-8: #7fb3e8;
}

[data-basalt-palette="tide"],
[data-basalt-palette="tide"][data-bs-theme="light"] {
	--basalt-canvas: #f9fbfd;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #e6eef7;
	--basalt-wash: #eef4fb;
	--basalt-edge: rgba(16, 42, 72, 0.09);
	--basalt-edge-strong: rgba(16, 42, 72, 0.15);
	--basalt-copy: #12233a;
	--basalt-copy-body: #35485f;
	--basalt-copy-muted: #5f7186;
	--basalt-copy-faint: #97a7b8;
	--basalt-hue: #2b6fd4;
	--basalt-hue-deep: #1b4e9e;
	--basalt-hue-soft: #e2edfb;
	--basalt-hue-border: rgba(43, 111, 212, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #16a5bf;
	--basalt-flare-soft: #dcf2f6;
	--basalt-grad: linear-gradient(135deg, #4f96ea 0%, #2b6fd4 52%, #1b4e9e 100%);
	--basalt-grad-soft: linear-gradient(135deg, #e2edfb 0%, #dcf2f6 100%);
	--basalt-success: #12c08f;
	--basalt-success-soft: rgba(18, 192, 143, 0.12);
	--basalt-warning: #f5a524;
	--basalt-warning-soft: rgba(245, 165, 36, 0.12);
	--basalt-danger: #ef4d63;
	--basalt-danger-soft: rgba(239, 77, 99, 0.12);
	--basalt-info: #2b6fd4;
	--basalt-info-soft: rgba(43, 111, 212, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(16, 42, 72, 0.05), 0 10px 28px rgba(16, 42, 72, 0.08);
	--basalt-scrim: rgba(18, 35, 58, 0.42);
	--basalt-series-1: #2b6fd4;
	--basalt-series-2: #00a3c4;
	--basalt-series-3: #1fc6a8;
	--basalt-series-4: #6e8ae8;
	--basalt-series-5: #f0a93c;
	--basalt-series-6: #ef5d6b;
	--basalt-series-7: #55b8f0;
	--basalt-series-8: #9b6de0;
}

[data-basalt-palette="scarlet"],
[data-basalt-palette="scarlet"][data-bs-theme="light"] {
	--basalt-canvas: #fdfbfb;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #f3ecec;
	--basalt-wash: #f8f1f1;
	--basalt-edge: rgba(48, 18, 20, 0.09);
	--basalt-edge-strong: rgba(48, 18, 20, 0.15);
	--basalt-copy: #1d1214;
	--basalt-copy-body: #463136;
	--basalt-copy-muted: #775f63;
	--basalt-copy-faint: #b0a0a3;
	--basalt-hue: #dc2b3f;
	--basalt-hue-deep: #ab1327;
	--basalt-hue-soft: #fde7ea;
	--basalt-hue-border: rgba(220, 43, 63, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #e07a1f;
	--basalt-flare-soft: #fdeeda;
	--basalt-grad: linear-gradient(135deg, #f4566a 0%, #dc2b3f 52%, #ab1327 100%);
	--basalt-grad-soft: linear-gradient(135deg, #fde7ea 0%, #fdeeda 100%);
	--basalt-success: #2fb573;
	--basalt-success-soft: rgba(47, 181, 115, 0.12);
	--basalt-warning: #f5852a;
	--basalt-warning-soft: rgba(245, 133, 42, 0.12);
	--basalt-danger: #dc2b3f;
	--basalt-danger-soft: rgba(220, 43, 63, 0.12);
	--basalt-info: #2f7fc4;
	--basalt-info-soft: rgba(47, 127, 196, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(48, 18, 20, 0.06), 0 10px 28px rgba(48, 18, 20, 0.08);
	--basalt-scrim: rgba(29, 18, 20, 0.44);
	--basalt-series-1: #dc2b3f;
	--basalt-series-2: #f2762e;
	--basalt-series-3: #f5b32b;
	--basalt-series-4: #00a38c;
	--basalt-series-5: #e8628f;
	--basalt-series-6: #9b4dc4;
	--basalt-series-7: #f09a7a;
	--basalt-series-8: #4d8fd9;
}

[data-basalt-palette="verdant"],
[data-basalt-palette="verdant"][data-bs-theme="light"] {
	--basalt-canvas: #f8fcfa;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #e3f0e8;
	--basalt-wash: #edf7f1;
	--basalt-edge: rgba(16, 56, 38, 0.09);
	--basalt-edge-strong: rgba(16, 56, 38, 0.15);
	--basalt-copy: #13291f;
	--basalt-copy-body: #35503f;
	--basalt-copy-muted: #5b7565;
	--basalt-copy-faint: #97ae9f;
	--basalt-hue: #267e57;
	--basalt-hue-deep: #1a6746;
	--basalt-hue-soft: #dcf0e6;
	--basalt-hue-border: rgba(38, 126, 87, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #1f9ba0;
	--basalt-flare-soft: #dcf1f2;
	--basalt-grad: linear-gradient(135deg, #52bd8b 0%, #2b8f63 52%, #1a6746 100%);
	--basalt-grad-soft: linear-gradient(135deg, #dcf0e6 0%, #dcf1f2 100%);
	--basalt-success: #267e57;
	--basalt-success-soft: rgba(38, 126, 87, 0.12);
	--basalt-warning: #f5a524;
	--basalt-warning-soft: rgba(245, 165, 36, 0.12);
	--basalt-danger: #ef4d63;
	--basalt-danger-soft: rgba(239, 77, 99, 0.12);
	--basalt-info: #2f7fa8;
	--basalt-info-soft: rgba(47, 127, 168, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(16, 56, 38, 0.05), 0 10px 28px rgba(16, 56, 38, 0.08);
	--basalt-scrim: rgba(19, 41, 31, 0.42);
	--basalt-series-1: #2b8f63;
	--basalt-series-2: #12b5a0;
	--basalt-series-3: #7fbf3f;
	--basalt-series-4: #e8a33c;
	--basalt-series-5: #c4603f;
	--basalt-series-6: #4d8fd9;
	--basalt-series-7: #8e6dc4;
	--basalt-series-8: #5fd9a8;
}

[data-basalt-palette="mono"],
[data-basalt-palette="mono"][data-bs-theme="light"] {
	--basalt-canvas: #f8f8f7;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #e8e7e4;
	--basalt-wash: #edecea;
	--basalt-edge: rgba(0, 0, 0, 0.09);
	--basalt-edge-strong: rgba(0, 0, 0, 0.15);
	--basalt-copy: #1a1a19;
	--basalt-copy-body: #44433f;
	--basalt-copy-muted: #716f68;
	--basalt-copy-faint: #a8a69f;
	--basalt-hue: #111110;
	--basalt-hue-deep: #000000;
	--basalt-hue-soft: #ebeae7;
	--basalt-hue-border: rgba(17, 17, 16, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #e0533f;
	--basalt-flare-soft: #fbe7e2;
	--basalt-grad: linear-gradient(135deg, #3f3e3b 0%, #161615 55%, #000000 100%);
	--basalt-grad-soft: linear-gradient(135deg, #eeedea 0%, #e6e5e1 100%);
	--basalt-success: #1f9d55;
	--basalt-success-soft: #e3f3e8;
	--basalt-warning: #d9901f;
	--basalt-warning-soft: #fbf0dc;
	--basalt-danger: #e0533f;
	--basalt-danger-soft: #fbe6e0;
	--basalt-info: #3b7fe0;
	--basalt-info-soft: #e4edfb;
	--basalt-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
	--basalt-scrim: rgba(0, 0, 0, 0.46);
	--basalt-series-1: #1a1a19;
	--basalt-series-2: #e0533f;
	--basalt-series-3: #3b7fe0;
	--basalt-series-4: #1f9d55;
	--basalt-series-5: #d9901f;
	--basalt-series-6: #9b60f2;
	--basalt-series-7: #78766f;
	--basalt-series-8: #14a5a0;
}

/* The dark side of every core palette. An accent that holds up on white tends
   to buzz against a near-black surface, so each one comes back lighter and a
   little less saturated than its light twin. The four status washes are their
   own tone at 16% alpha and the accent outline is the accent at 45%; white
   hairlines at low alpha suit any of the dark canvases. Dusk, the base,
   answers to the theme attribute alone; every palette also answers to its
   data-basalt-palette value. Dusk's dark set has a few tokens the others
   leave to their light set (its deeper card shadow and scrim), so each other
   palette repeats its own light value for those, or it would wear Dusk's. */
[data-bs-theme="dark"] {
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #0b0918;
	--basalt-plane: #14102a;
	--basalt-plane-alt: #221a48;
	--basalt-wash: #1b1538;
	--basalt-copy: #f1eefb;
	--basalt-copy-body: #d2cbe9;
	--basalt-copy-muted: #a39ac6;
	--basalt-copy-faint: #6f6795;
	--basalt-hue: #8f5eff;
	--basalt-hue-border: rgba(143, 94, 255, 0.55);
	--basalt-hue-deep: #6f3cf2;
	--basalt-hue-soft: #2e1f66;
	--basalt-on-hue: #0e0b1c;
	--basalt-flare: #22b8ff;
	--basalt-flare-soft: #0f2f4a;
	--basalt-grad: linear-gradient(120deg, #c45cff 0%, #8f5eff 50%, #4f22d6 100%);
	--basalt-grad-soft: linear-gradient(135deg, #2e1f66 0%, #3d1a5c 100%);
	--basalt-success: #3ecb9a;
	--basalt-success-soft: rgba(62, 203, 154, 0.16);
	--basalt-warning: #efb45c;
	--basalt-warning-soft: rgba(239, 180, 92, 0.16);
	--basalt-danger: #f2738f;
	--basalt-danger-soft: rgba(242, 115, 143, 0.16);
	--basalt-info: #8fa4f5;
	--basalt-info-soft: rgba(143, 164, 245, 0.16);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	--basalt-series-1: #8f5eff;
	--basalt-series-2: #6a78ff;
	--basalt-series-3: #22b8ff;
	--basalt-series-4: #c06bff;
	--basalt-series-5: #ff4fa8;
	--basalt-series-6: #ff86c8;
	--basalt-series-7: #a24dff;
	--basalt-series-8: #3fd0e6;
}

[data-basalt-palette="dusk"][data-bs-theme="dark"] {
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #0b0918;
	--basalt-plane: #14102a;
	--basalt-plane-alt: #221a48;
	--basalt-wash: #1b1538;
	--basalt-copy: #f1eefb;
	--basalt-copy-body: #d2cbe9;
	--basalt-copy-muted: #a39ac6;
	--basalt-copy-faint: #6f6795;
	--basalt-hue: #8f5eff;
	--basalt-hue-border: rgba(143, 94, 255, 0.55);
	--basalt-hue-deep: #6f3cf2;
	--basalt-hue-soft: #2e1f66;
	--basalt-on-hue: #0e0b1c;
	--basalt-flare: #22b8ff;
	--basalt-flare-soft: #0f2f4a;
	--basalt-grad: linear-gradient(120deg, #c45cff 0%, #8f5eff 50%, #4f22d6 100%);
	--basalt-grad-soft: linear-gradient(135deg, #2e1f66 0%, #3d1a5c 100%);
	--basalt-success: #3ecb9a;
	--basalt-success-soft: rgba(62, 203, 154, 0.16);
	--basalt-warning: #efb45c;
	--basalt-warning-soft: rgba(239, 180, 92, 0.16);
	--basalt-danger: #f2738f;
	--basalt-danger-soft: rgba(242, 115, 143, 0.16);
	--basalt-info: #8fa4f5;
	--basalt-info-soft: rgba(143, 164, 245, 0.16);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	--basalt-series-1: #8f5eff;
	--basalt-series-2: #6a78ff;
	--basalt-series-3: #22b8ff;
	--basalt-series-4: #c06bff;
	--basalt-series-5: #ff4fa8;
	--basalt-series-6: #ff86c8;
	--basalt-series-7: #a24dff;
	--basalt-series-8: #3fd0e6;
}

[data-basalt-palette="tide"][data-bs-theme="dark"] {
	--basalt-scrim: rgba(18, 35, 58, 0.42);
	--basalt-card-shadow: 0 1px 3px rgba(16, 42, 72, 0.05), 0 10px 28px rgba(16, 42, 72, 0.08);
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #0b1522;
	--basalt-plane: #122032;
	--basalt-plane-alt: #1c314a;
	--basalt-wash: #17283e;
	--basalt-copy: #eaf2fb;
	--basalt-copy-body: #c6d8ea;
	--basalt-copy-muted: #94abc2;
	--basalt-copy-faint: #5f7590;
	--basalt-hue: #3d86f3;
	--basalt-hue-border: rgba(61, 134, 243, 0.55);
	--basalt-hue-deep: #0e65e7;
	--basalt-hue-soft: #1c3860;
	--basalt-on-hue: #0b1522;
	--basalt-flare: #10a9c5;
	--basalt-flare-soft: #123e52;
	--basalt-grad: linear-gradient(120deg, #63caf5 0%, #3d86f3 50%, #0d5cd1 100%);
	--basalt-grad-soft: linear-gradient(135deg, #1c3860 0%, #102e37 100%);
	--basalt-success: #45d49f;
	--basalt-success-soft: rgba(69, 212, 159, 0.16);
	--basalt-warning: #efb44f;
	--basalt-warning-soft: rgba(239, 180, 79, 0.16);
	--basalt-danger: #fb6f87;
	--basalt-danger-soft: rgba(251, 111, 135, 0.16);
	--basalt-info: #62a6f2;
	--basalt-info-soft: rgba(98, 166, 242, 0.16);
	--basalt-series-1: #2572e4;
	--basalt-series-2: #00a3c4;
	--basalt-series-3: #19ccac;
	--basalt-series-4: #6988ed;
	--basalt-series-5: #f0a93c;
	--basalt-series-6: #ef5d6b;
	--basalt-series-7: #55b8f0;
	--basalt-series-8: #9961ec;
}

[data-basalt-palette="scarlet"][data-bs-theme="dark"] {
	--basalt-scrim: rgba(29, 18, 20, 0.44);
	--basalt-card-shadow: 0 1px 3px rgba(48, 18, 20, 0.06), 0 10px 28px rgba(48, 18, 20, 0.08);
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #1a0c0f;
	--basalt-plane: #271317;
	--basalt-plane-alt: #3a1f24;
	--basalt-wash: #31191e;
	--basalt-copy: #faeef0;
	--basalt-copy-body: #e0c8cc;
	--basalt-copy-muted: #b8969b;
	--basalt-copy-faint: #82656a;
	--basalt-hue: #f23b50;
	--basalt-hue-border: rgba(242, 59, 80, 0.55);
	--basalt-hue-deep: #d70e25;
	--basalt-hue-soft: #561c24;
	--basalt-on-hue: #1a0c0f;
	--basalt-flare: #ec7913;
	--basalt-flare-soft: #522916;
	--basalt-grad: linear-gradient(120deg, #f5619e 0%, #f23b50 50%, #ce0e24 100%);
	--basalt-grad-soft: linear-gradient(135deg, #561c24 0%, #362515 100%);
	--basalt-success: #56c791;
	--basalt-success-soft: rgba(86, 199, 145, 0.16);
	--basalt-warning: #fba04f;
	--basalt-warning-soft: rgba(251, 160, 79, 0.16);
	--basalt-danger: #f4596e;
	--basalt-danger-soft: rgba(244, 89, 110, 0.16);
	--basalt-info: #64a8e0;
	--basalt-info-soft: rgba(100, 168, 224, 0.16);
	--basalt-series-1: #e42339;
	--basalt-series-2: #f2762e;
	--basalt-series-3: #f5b32b;
	--basalt-series-4: #00b299;
	--basalt-series-5: #eb5f8e;
	--basalt-series-6: #a935e6;
	--basalt-series-7: #f09a7a;
	--basalt-series-8: #3f8ee7;
}

[data-basalt-palette="verdant"][data-bs-theme="dark"] {
	--basalt-scrim: rgba(19, 41, 31, 0.42);
	--basalt-card-shadow: 0 1px 3px rgba(16, 56, 38, 0.05), 0 10px 28px rgba(16, 56, 38, 0.08);
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #0a1812;
	--basalt-plane: #10251b;
	--basalt-plane-alt: #1a382b;
	--basalt-wash: #162e24;
	--basalt-copy: #e9f6ee;
	--basalt-copy-body: #c5ddd0;
	--basalt-copy-muted: #93b3a2;
	--basalt-copy-faint: #5f7e6d;
	--basalt-hue: #0ba862;
	--basalt-hue-border: rgba(11, 168, 98, 0.55);
	--basalt-hue-deep: #087d49;
	--basalt-hue-soft: #0f462d;
	--basalt-on-hue: #0a1812;
	--basalt-flare: #0eaab1;
	--basalt-flare-soft: #10423c;
	--basalt-grad: linear-gradient(120deg, #0ece3f 0%, #0ba862 50%, #09864e 100%);
	--basalt-grad-soft: linear-gradient(135deg, #0f462d 0%, #103332 100%);
	--basalt-success: #4fbd8a;
	--basalt-success-soft: rgba(79, 189, 138, 0.16);
	--basalt-warning: #efb44f;
	--basalt-warning-soft: rgba(239, 180, 79, 0.16);
	--basalt-danger: #fb6f87;
	--basalt-danger-soft: rgba(251, 111, 135, 0.16);
	--basalt-info: #64abd4;
	--basalt-info-soft: rgba(100, 171, 212, 0.16);
	--basalt-series-1: #14a666;
	--basalt-series-2: #12b5a0;
	--basalt-series-3: #7fe21c;
	--basalt-series-4: #e8a33c;
	--basalt-series-5: #e35020;
	--basalt-series-6: #3f8ee7;
	--basalt-series-7: #9058ea;
	--basalt-series-8: #4fe9ab;
}

[data-basalt-palette="mono"][data-bs-theme="dark"] {
	--basalt-scrim: rgba(0, 0, 0, 0.46);
	--basalt-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-canvas: #080808;
	--basalt-plane: #101010;
	--basalt-plane-alt: #1e1e1e;
	--basalt-wash: #171717;
	--basalt-copy: #fafafa;
	--basalt-copy-body: #d6d6d6;
	--basalt-copy-muted: #a0a0a0;
	--basalt-copy-faint: #6b6b6b;
	--basalt-hue: #fafafa;
	--basalt-hue-border: rgba(250, 250, 250, 0.45);
	--basalt-hue-deep: #cfcfcf;
	--basalt-hue-soft: #222222;
	--basalt-on-hue: #080808;
	--basalt-flare: #ee4831;
	--basalt-flare-soft: #411c17;
	--basalt-grad: linear-gradient(135deg, #ffffff 0%, #dcdcdc 55%, #a8a8a8 100%);
	--basalt-grad-soft: linear-gradient(135deg, #262626 0%, #1e1e1e 100%);
	--basalt-success: #2fd4b8;
	--basalt-success-soft: rgba(47, 212, 184, 0.16);
	--basalt-warning: #ffc04d;
	--basalt-warning-soft: rgba(255, 192, 77, 0.16);
	--basalt-danger: #ff6369;
	--basalt-danger-soft: rgba(255, 99, 105, 0.16);
	--basalt-info: #62a6f8;
	--basalt-info-soft: rgba(98, 166, 248, 0.16);
	--basalt-series-1: #fafafa;
	--basalt-series-2: #e64e39;
	--basalt-series-3: #357ee6;
	--basalt-series-4: #15a754;
	--basalt-series-5: #dd911b;
	--basalt-series-6: #9b60f2;
	--basalt-series-7: #78766f;
	--basalt-series-8: #14a5a0;
}

/* With `data-basalt-gradients="off"` on <html> the hero gradient becomes its
   own primary and the soft wash becomes the bare card surface. Both tokens
   already resolve per palette and per scheme, so one rule serves them all. */
:root[data-basalt-gradients="off"] {
	--basalt-grad: var(--basalt-hue);
	--basalt-grad-soft: var(--basalt-plane);
}

/* Four louder palettes sit beside the core five in the appearance panel:
   Electric, Jewel, Duotone and Pastel Pop. Each one keeps its light and dark
   sets together, and both are written out right after each other. Every
   dark set of this group shares one frame: hairline borders in white, a heavy
   black shadow and a deep scrim.

   The light set answers to the bare attribute as well, so it also covers a
   page with no scheme set. The dark set needs both attributes, which already
   outranks the bare one, and it tells form controls to draw dark. */
[data-basalt-palette="electric"],
[data-basalt-palette="electric"][data-bs-theme="light"] {
	--basalt-canvas: #fdfdff;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #f0f0fa;
	--basalt-wash: #f5f5fd;
	--basalt-edge: rgba(20, 18, 50, 0.09);
	--basalt-edge-strong: rgba(20, 18, 50, 0.15);
	--basalt-copy: #121026;
	--basalt-copy-body: #3a3658;
	--basalt-copy-muted: #6a6690;
	--basalt-copy-faint: #a3a0c0;
	--basalt-hue: #8e3ee9;
	--basalt-hue-deep: #5a1fb3;
	--basalt-hue-soft: #f0e8ff;
	--basalt-hue-border: rgba(142, 62, 233, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #06c8d8;
	--basalt-flare-soft: #d9f8fc;
	--basalt-grad: linear-gradient(135deg, #b759f3 0%, #8e3ee9 52%, #5a1fb3 100%);
	--basalt-grad-soft: linear-gradient(135deg, #f0e8ff 0%, #d9f8fc 100%);
	--basalt-success: #00b874;
	--basalt-success-soft: rgba(0, 184, 116, 0.12);
	--basalt-warning: #ffa50f;
	--basalt-warning-soft: rgba(255, 165, 15, 0.12);
	--basalt-danger: #ff2d62;
	--basalt-danger-soft: rgba(255, 45, 98, 0.12);
	--basalt-info: #2e7dff;
	--basalt-info-soft: rgba(46, 125, 255, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(20, 18, 50, 0.05), 0 10px 28px rgba(20, 18, 50, 0.08);
	--basalt-scrim: rgba(18, 16, 38, 0.44);
	--basalt-series-1: #8e3ee9;
	--basalt-series-2: #2e7dff;
	--basalt-series-3: #06c8d8;
	--basalt-series-4: #00c98a;
	--basalt-series-5: #ffa50f;
	--basalt-series-6: #ff2d62;
	--basalt-series-7: #e040fb;
	--basalt-series-8: #ff7a45;
}
[data-basalt-palette="electric"][data-bs-theme="dark"] {
	--basalt-canvas: #0d091b;
	--basalt-plane: #17102b;
	--basalt-plane-alt: #251b41;
	--basalt-wash: #1e1735;
	--basalt-copy: #f2f0ff;
	--basalt-copy-body: #d5d0f0;
	--basalt-copy-muted: #a49ecb;
	--basalt-copy-faint: #6e6894;
	--basalt-hue: #a259f4;
	--basalt-hue-deep: #8f38f2;
	--basalt-hue-soft: #3e2463;
	--basalt-hue-border: rgba(162, 89, 244, 0.55);
	--basalt-on-hue: #0d091b;
	--basalt-flare: #06c8d8;
	--basalt-flare-soft: #133851;
	--basalt-grad: linear-gradient(120deg, #947ff7 0%, #a259f4 50%, #7710ec 100%);
	--basalt-grad-soft: linear-gradient(135deg, #3e2463 0%, #0c2e35 100%);
	--basalt-success: #21e39a;
	--basalt-success-soft: rgba(33, 227, 154, 0.16);
	--basalt-warning: #ffc046;
	--basalt-warning-soft: rgba(255, 192, 70, 0.16);
	--basalt-danger: #ff5c87;
	--basalt-danger-soft: rgba(255, 92, 135, 0.16);
	--basalt-info: #5f9bff;
	--basalt-info-soft: rgba(95, 155, 255, 0.16);
	--basalt-series-1: #9143ea;
	--basalt-series-2: #2e7dff;
	--basalt-series-3: #06c8d8;
	--basalt-series-4: #00c98a;
	--basalt-series-5: #ffa50f;
	--basalt-series-6: #ff2d62;
	--basalt-series-7: #e040fb;
	--basalt-series-8: #ff7a45;
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	color-scheme: dark;
}

[data-basalt-palette="jewel"],
[data-basalt-palette="jewel"][data-bs-theme="light"] {
	--basalt-canvas: #fdfcfa;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #f0ebe3;
	--basalt-wash: #f6f2ea;
	--basalt-edge: rgba(60, 40, 20, 0.1);
	--basalt-edge-strong: rgba(60, 40, 20, 0.16);
	--basalt-copy: #1f1a2e;
	--basalt-copy-body: #463f58;
	--basalt-copy-muted: #6e6680;
	--basalt-copy-faint: #a49db4;
	--basalt-hue: #5a1fb3;
	--basalt-hue-deep: #3b0f80;
	--basalt-hue-soft: #ece2ff;
	--basalt-hue-border: rgba(91, 33, 182, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #11668d;
	--basalt-flare-soft: #daedf2;
	--basalt-grad: linear-gradient(135deg, #8b4dd8 0%, #5a1fb3 52%, #3b0f80 100%);
	--basalt-grad-soft: linear-gradient(135deg, #ece2ff 0%, #daedf2 100%);
	--basalt-success: #077561;
	--basalt-success-soft: rgba(4, 120, 87, 0.12);
	--basalt-warning: #b0640d;
	--basalt-warning-soft: rgba(180, 83, 9, 0.12);
	--basalt-danger: #9c1137;
	--basalt-danger-soft: rgba(159, 18, 57, 0.12);
	--basalt-info: #223ed3;
	--basalt-info-soft: rgba(29, 78, 216, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(60, 40, 20, 0.06), 0 10px 28px rgba(60, 40, 20, 0.09);
	--basalt-scrim: rgba(31, 26, 46, 0.46);
	--basalt-series-1: #5a1fb3;
	--basalt-series-2: #223ed3;
	--basalt-series-3: #11668d;
	--basalt-series-4: #077561;
	--basalt-series-5: #b0640d;
	--basalt-series-6: #9c1137;
	--basalt-series-7: #84178c;
	--basalt-series-8: #bd5411;
}
[data-basalt-palette="jewel"][data-bs-theme="dark"] {
	--basalt-canvas: #120e1c;
	--basalt-plane: #1b152a;
	--basalt-plane-alt: #2c2241;
	--basalt-wash: #241c39;
	--basalt-copy: #f3effa;
	--basalt-copy-body: #d6cfe6;
	--basalt-copy-muted: #a89fbe;
	--basalt-copy-faint: #71698a;
	--basalt-hue: #9c62f5;
	--basalt-hue-deep: #853ef3;
	--basalt-hue-soft: #3d295f;
	--basalt-hue-border: rgba(156, 98, 245, 0.55);
	--basalt-on-hue: #120e1c;
	--basalt-flare: #0d75a5;
	--basalt-flare-soft: #182a45;
	--basalt-grad: linear-gradient(120deg, #9388f7 0%, #9c62f5 50%, #6c15f0 100%);
	--basalt-grad-soft: linear-gradient(135deg, #3d295f 0%, #0e2b33 100%);
	--basalt-success: #3fae82;
	--basalt-success-soft: rgba(63, 174, 130, 0.16);
	--basalt-warning: #d99436;
	--basalt-warning-soft: rgba(217, 148, 54, 0.16);
	--basalt-danger: #e05575;
	--basalt-danger-soft: rgba(224, 85, 117, 0.16);
	--basalt-info: #5b8ef0;
	--basalt-info-soft: rgba(91, 142, 240, 0.16);
	--basalt-series-1: #8b4de9;
	--basalt-series-2: #4c65e9;
	--basalt-series-3: #147aa8;
	--basalt-series-4: #0aa88c;
	--basalt-series-5: #b0640d;
	--basalt-series-6: #dd184e;
	--basalt-series-7: #c21acf;
	--basalt-series-8: #bd5411;
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	color-scheme: dark;
}

[data-basalt-palette="duotone"],
[data-basalt-palette="duotone"][data-bs-theme="light"] {
	--basalt-canvas: #fdfdfd;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #efefef;
	--basalt-wash: #f5f5f5;
	--basalt-edge: rgba(0, 0, 0, 0.1);
	--basalt-edge-strong: rgba(0, 0, 0, 0.16);
	--basalt-copy: #18181b;
	--basalt-copy-body: #3f3f46;
	--basalt-copy-muted: #6f6f78;
	--basalt-copy-faint: #a1a1aa;
	--basalt-hue: #7f2cd5;
	--basalt-hue-deep: #4a1b92;
	--basalt-hue-soft: #efeafd;
	--basalt-hue-border: rgba(109, 40, 217, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #b8cf1f;
	--basalt-flare-soft: #f4fad2;
	--basalt-grad: linear-gradient(135deg, #9a5cf0 0%, #7f2cd5 52%, #4a1b92 100%);
	--basalt-grad-soft: linear-gradient(135deg, #efeafd 0%, #f4fad2 100%);
	--basalt-success: #7d9c1f;
	--basalt-success-soft: rgba(125, 156, 31, 0.12);
	--basalt-warning: #b8912e;
	--basalt-warning-soft: rgba(184, 145, 46, 0.12);
	--basalt-danger: #be3e52;
	--basalt-danger-soft: rgba(190, 62, 82, 0.12);
	--basalt-info: #7f2cd5;
	--basalt-info-soft: rgba(109, 40, 217, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 10px 28px rgba(0, 0, 0, 0.08);
	--basalt-scrim: rgba(24, 24, 27, 0.46);
	--basalt-series-1: #7f2cd5;
	--basalt-series-2: #b8cf1f;
	--basalt-series-3: #b38ef7;
	--basalt-series-4: #7d9c1f;
	--basalt-series-5: #3f3f46;
	--basalt-series-6: #ccb7fb;
	--basalt-series-7: #71717a;
	--basalt-series-8: #d6e878;
}
[data-basalt-palette="duotone"][data-bs-theme="dark"] {
	--basalt-canvas: #100c16;
	--basalt-plane: #191521;
	--basalt-plane-alt: #282333;
	--basalt-wash: #211d29;
	--basalt-copy: #f4f4f5;
	--basalt-copy-body: #d4d4d8;
	--basalt-copy-muted: #a1a1aa;
	--basalt-copy-faint: #71717a;
	--basalt-hue: #a75bf5;
	--basalt-hue-deep: #9437f3;
	--basalt-hue-soft: #42295e;
	--basalt-hue-border: rgba(167, 91, 245, 0.55);
	--basalt-on-hue: #100c16;
	--basalt-flare: #c2dc12;
	--basalt-flare-soft: #3e411e;
	--basalt-grad: linear-gradient(120deg, #9881f7 0%, #a75bf5 50%, #7e0ff0 100%);
	--basalt-grad-soft: linear-gradient(135deg, #42295e 0%, #2b2f10 100%);
	--basalt-success: #a8c43a;
	--basalt-success-soft: rgba(168, 196, 58, 0.16);
	--basalt-warning: #d4b544;
	--basalt-warning-soft: rgba(212, 181, 68, 0.16);
	--basalt-danger: #e0616f;
	--basalt-danger-soft: rgba(224, 97, 111, 0.16);
	--basalt-info: #b38ef7;
	--basalt-info-soft: rgba(167, 139, 250, 0.16);
	--basalt-series-1: #9544e8;
	--basalt-series-2: #bcd41a;
	--basalt-series-3: #b38ef7;
	--basalt-series-4: #82a615;
	--basalt-series-5: #6f6f7b;
	--basalt-series-6: #ccb7fb;
	--basalt-series-7: #71717a;
	--basalt-series-8: #daee72;
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	color-scheme: dark;
}

[data-basalt-palette="pastelpop"],
[data-basalt-palette="pastelpop"][data-bs-theme="light"] {
	--basalt-canvas: #fefefe;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #f1f2f9;
	--basalt-wash: #f7f8fc;
	--basalt-edge: rgba(30, 32, 60, 0.09);
	--basalt-edge-strong: rgba(30, 32, 60, 0.15);
	--basalt-copy: #1f2033;
	--basalt-copy-body: #454863;
	--basalt-copy-muted: #6b6e88;
	--basalt-copy-faint: #a8abc4;
	--basalt-hue: #5c5fe0;
	--basalt-hue-deep: #4a3cc0;
	--basalt-hue-soft: #edeefd;
	--basalt-hue-border: rgba(92, 95, 224, 0.45);
	--basalt-on-hue: #ffffff;
	--basalt-flare: #ec5fa6;
	--basalt-flare-soft: #fbe8f1;
	--basalt-grad: linear-gradient(135deg, #8b8ef7 0%, #6a64ea 52%, #4a3cc0 100%);
	--basalt-grad-soft: linear-gradient(135deg, #edeefd 0%, #fbe8f1 100%);
	--basalt-success: #14b590;
	--basalt-success-soft: rgba(20, 181, 144, 0.12);
	--basalt-warning: #f0a91c;
	--basalt-warning-soft: rgba(240, 169, 28, 0.12);
	--basalt-danger: #ef4450;
	--basalt-danger-soft: rgba(239, 68, 80, 0.12);
	--basalt-info: #6497f6;
	--basalt-info-soft: rgba(96, 165, 250, 0.12);
	--basalt-card-shadow: 0 1px 3px rgba(30, 32, 60, 0.05), 0 10px 28px rgba(30, 32, 60, 0.07);
	--basalt-scrim: rgba(31, 32, 51, 0.42);
	--basalt-series-1: #8a8ff0;
	--basalt-series-2: #6497f6;
	--basalt-series-3: #3fd0e0;
	--basalt-series-4: #38cfa7;
	--basalt-series-5: #f6d129;
	--basalt-series-6: #f8747a;
	--basalt-series-7: #ea7cfa;
	--basalt-series-8: #fac777;
}
[data-basalt-palette="pastelpop"][data-bs-theme="dark"] {
	--basalt-canvas: #111223;
	--basalt-plane: #1a1c34;
	--basalt-plane-alt: #272a4a;
	--basalt-wash: #21233e;
	--basalt-copy: #f0f1fb;
	--basalt-copy-body: #cfd2ea;
	--basalt-copy-muted: #9ea2c4;
	--basalt-copy-faint: #6a6e92;
	--basalt-hue: #7679f6;
	--basalt-hue-deep: #5256f4;
	--basalt-hue-soft: #323466;
	--basalt-hue-border: rgba(118, 121, 246, 0.55);
	--basalt-on-hue: #111223;
	--basalt-flare: #f259a6;
	--basalt-flare-soft: #4a294d;
	--basalt-grad: linear-gradient(120deg, #96b6f8 0%, #7679f6 50%, #292ef1 100%);
	--basalt-grad-soft: linear-gradient(135deg, #323466 0%, #381a2e 100%);
	--basalt-success: #38cfa7;
	--basalt-success-soft: rgba(56, 207, 167, 0.16);
	--basalt-warning: #f6d129;
	--basalt-warning-soft: rgba(246, 209, 41, 0.16);
	--basalt-danger: #f8747a;
	--basalt-danger-soft: rgba(248, 116, 122, 0.16);
	--basalt-info: #6497f6;
	--basalt-info-soft: rgba(96, 165, 250, 0.16);
	--basalt-series-1: #8a8ff0;
	--basalt-series-2: #6497f6;
	--basalt-series-3: #39d5e6;
	--basalt-series-4: #23e4b1;
	--basalt-series-5: #f6d129;
	--basalt-series-6: #f8747a;
	--basalt-series-7: #ea7cfa;
	--basalt-series-8: #fac777;
	--basalt-edge: rgba(255, 255, 255, 0.08);
	--basalt-edge-strong: rgba(255, 255, 255, 0.14);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 34px rgba(0, 0, 0, 0.32);
	--basalt-scrim: rgba(0, 0, 0, 0.55);
	color-scheme: dark;
}

/* Two switches on <html> overrule the surface half of whichever palette is
   active, while hue, accent, status colors and the chart ramp stay with it.
   They come after every palette block on purpose: the specificity is equal,
   so source order decides.

   neutral  strips the tint from page, surfaces and borders. Text keeps its
            faint tint, which stops the grays from looking dead; add `copy`
            to its sets in _tokens.scss for a fully neutral page.
   plain    goes further: the page matches the cards, which stand apart by
            their hairline alone, with no shadow.

   Plain is listed second so it wins the same tie over neutral. The dark set
   adds the scheme attribute, and the shadow it inherits from light is kept. */
:root[data-basalt-surfaces="neutral"] {
	--basalt-canvas: #f6f6f7;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #ececee;
	--basalt-wash: #f2f2f4;
	--basalt-edge: rgba(0, 0, 0, 0.1);
	--basalt-edge-strong: rgba(0, 0, 0, 0.16);
	--basalt-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 10px 28px rgba(0, 0, 0, 0.07);
}
:root[data-basalt-surfaces="neutral"][data-bs-theme="dark"] {
	--basalt-canvas: #121213;
	--basalt-plane: #1b1b1d;
	--basalt-plane-alt: #292a2c;
	--basalt-wash: #232426;
	--basalt-edge: rgba(255, 255, 255, 0.09);
	--basalt-edge-strong: rgba(255, 255, 255, 0.15);
}

:root[data-basalt-surfaces="plain"] {
	--basalt-canvas: #ffffff;
	--basalt-plane: #ffffff;
	--basalt-plane-alt: #f4f4f5;
	--basalt-wash: #f4f4f5;
	--basalt-edge: rgba(0, 0, 0, 0.1);
	--basalt-edge-strong: rgba(0, 0, 0, 0.16);
	--basalt-card-shadow: none;
}
:root[data-basalt-surfaces="plain"][data-bs-theme="dark"] {
	--basalt-canvas: #161617;
	--basalt-plane: #161617;
	--basalt-plane-alt: #242426;
	--basalt-wash: #1f1f21;
	--basalt-edge: rgba(255, 255, 255, 0.1);
	--basalt-edge-strong: rgba(255, 255, 255, 0.16);
}

/*
 * Hands Bootstrap's own classes over to the Basalt palette. The stock build
 * colors .text-info, .bg-success-subtle, checkboxes, cards and the rest from
 * --bs-* variables, so without this file they would stay stock blue under
 * every palette. Each page that loads basalt.css relies on it.
 *
 * Bootstrap's tinted and emphasis variables take any color, so they are
 * simply re-pointed here. Its solid color utilities (.text-*, .bg-*,
 * .border-*) are built with the tokens in assets/basalt/scss/bootstrap.scss.
 */
/* A palette token pulled toward the text color, which is how colored text
   and emphasis keep 4.5:1 against the page. */
/* Bootstrap color name, the palette token behind it, and three strengths:
   emphasis text in the light scheme, emphasis text in the dark scheme, and
   the tinted border. Each strength was tuned until its text passed contrast. */
/* Keyboard focus on any form control draws the same primary ring. */
/* Bootstrap's variable set, written for one scheme. $column picks the light
   or dark emphasis strength; $shade is what solid fills darken toward so
   text laid on them still reads (the copy color by day, the page by night). */
:root {
	--bs-link-color: var(--basalt-hue);
	--bs-link-hover-color: var(--basalt-hue-deep);
	--bs-border-color: var(--basalt-edge);
	--bs-border-color-translucent: var(--basalt-edge);
	--bs-primary: var(--basalt-hue);
	--bs-primary-bg-subtle: var(--basalt-hue-soft);
	--bs-primary-text-emphasis: color-mix(in srgb, var(--basalt-hue) 60%, var(--basalt-copy));
	--bs-primary-border-subtle: color-mix(in srgb, var(--basalt-hue) 30%, transparent);
	--bs-success: var(--basalt-success);
	--bs-success-bg-subtle: var(--basalt-success-soft);
	--bs-success-text-emphasis: color-mix(in srgb, var(--basalt-success) 48%, var(--basalt-copy));
	--bs-success-border-subtle: color-mix(in srgb, var(--basalt-success) 30%, transparent);
	--bs-danger: var(--basalt-danger);
	--bs-danger-bg-subtle: var(--basalt-danger-soft);
	--bs-danger-text-emphasis: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
	--bs-danger-border-subtle: color-mix(in srgb, var(--basalt-danger) 30%, transparent);
	--bs-warning: var(--basalt-warning);
	--bs-warning-bg-subtle: var(--basalt-warning-soft);
	--bs-warning-text-emphasis: color-mix(in srgb, var(--basalt-warning) 42%, var(--basalt-copy));
	--bs-warning-border-subtle: color-mix(in srgb, var(--basalt-warning) 36%, transparent);
	--bs-info: var(--basalt-flare);
	--bs-info-bg-subtle: var(--basalt-flare-soft);
	--bs-info-text-emphasis: color-mix(in srgb, var(--basalt-flare) 44%, var(--basalt-copy));
	--bs-info-border-subtle: color-mix(in srgb, var(--basalt-flare) 30%, transparent);
	--bs-secondary-bg-subtle: var(--basalt-wash);
	--bs-secondary-text-emphasis: var(--basalt-copy-body);
	--bs-secondary-border-subtle: var(--basalt-edge-strong);
	--basalt-shade: var(--basalt-copy);
	/* Bootstrap leaves these outside its theme colors: inline code is fixed
      pink and validation brings its own green and red. Messages lean toward
      the copy, as the fill tokens alone drop below 4.5:1 as text. */
	--bs-code-color: var(--basalt-hue);
	--bs-highlight-bg: var(--basalt-warning-soft);
	--bs-form-valid-color: color-mix(in srgb, var(--basalt-success) 52%, var(--basalt-copy));
	--bs-form-valid-border-color: var(--basalt-success);
	--bs-form-invalid-color: color-mix(in srgb, var(--basalt-danger) 58%, var(--basalt-copy));
	--bs-form-invalid-border-color: var(--basalt-danger);
	/* Spacing every data surface shares (card heads, list rows, table cells,
      toolbars) and the two title sizes above body text, so density and
      hierarchy are tuned here once for the whole template. */
	--basalt-pad-head: 1.5rem;
	--basalt-pad-row-y: 1.2rem;
	--basalt-pad-x: 1.5rem;
	--basalt-pad-x-narrow: 1rem;
	--basalt-fs-card-title: 1.2rem;
	--basalt-fs-section: 1.05rem;
}

/* Bootstrap sets its dark values on [data-bs-theme="dark"], which outweighs
   plain :root, so the dark scheme repeats the set at that weight. */
:root[data-bs-theme="dark"],
[data-bs-theme="dark"] {
	--bs-link-color: var(--basalt-hue);
	--bs-link-hover-color: var(--basalt-hue-deep);
	--bs-border-color: var(--basalt-edge);
	--bs-border-color-translucent: var(--basalt-edge);
	--bs-primary: var(--basalt-hue);
	--bs-primary-bg-subtle: var(--basalt-hue-soft);
	--bs-primary-text-emphasis: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	--bs-primary-border-subtle: color-mix(in srgb, var(--basalt-hue) 30%, transparent);
	--bs-success: var(--basalt-success);
	--bs-success-bg-subtle: var(--basalt-success-soft);
	--bs-success-text-emphasis: color-mix(in srgb, var(--basalt-success) 55%, var(--basalt-copy));
	--bs-success-border-subtle: color-mix(in srgb, var(--basalt-success) 30%, transparent);
	--bs-danger: var(--basalt-danger);
	--bs-danger-bg-subtle: var(--basalt-danger-soft);
	--bs-danger-text-emphasis: color-mix(in srgb, var(--basalt-danger) 45%, var(--basalt-copy));
	--bs-danger-border-subtle: color-mix(in srgb, var(--basalt-danger) 30%, transparent);
	--bs-warning: var(--basalt-warning);
	--bs-warning-bg-subtle: var(--basalt-warning-soft);
	--bs-warning-text-emphasis: color-mix(in srgb, var(--basalt-warning) 55%, var(--basalt-copy));
	--bs-warning-border-subtle: color-mix(in srgb, var(--basalt-warning) 36%, transparent);
	--bs-info: var(--basalt-flare);
	--bs-info-bg-subtle: var(--basalt-flare-soft);
	--bs-info-text-emphasis: color-mix(in srgb, var(--basalt-flare) 55%, var(--basalt-copy));
	--bs-info-border-subtle: color-mix(in srgb, var(--basalt-flare) 30%, transparent);
	--bs-secondary-bg-subtle: var(--basalt-wash);
	--bs-secondary-text-emphasis: var(--basalt-copy-body);
	--bs-secondary-border-subtle: var(--basalt-edge-strong);
	--basalt-shade: var(--basalt-canvas);
}

/* Checkboxes and radios fill with a primary that leans to the copy color,
   so the white tick survives light palettes, and an empty box keeps an edge
   the page can show. A mouse click leaves no ring; the keyboard gets one. */
.form-check-input {
	border-color: color-mix(in srgb, var(--basalt-copy-muted) 60%, transparent);
}
.form-check-input:checked,
.form-check-input[type="checkbox"]:indeterminate {
	border-color: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	background-color: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
}
.form-check-input:focus-visible {
	border-color: var(--basalt-hue);
	box-shadow: 0 0 0 0.25rem var(--basalt-hue-border);
}
.form-check-input:focus:not(:focus-visible) {
	border-color: color-mix(in srgb, var(--basalt-copy-muted) 60%, transparent);
	box-shadow: none;
}
.form-check-input:checked:focus:not(:focus-visible),
.form-check-input[type="checkbox"]:indeterminate:focus:not(:focus-visible) {
	border-color: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
}

/* Text inputs and selects ring the same way. A select drawn as a button only
   keeps it while its list is open or the keyboard put it there. */
.form-control:focus,
.form-select:focus {
	border-color: var(--basalt-hue);
	box-shadow: 0 0 0 0.25rem var(--basalt-hue-border);
}

button.form-select:focus:not(:focus-visible):not([aria-expanded="true"]) {
	border-color: var(--bs-border-color);
	box-shadow: none;
}

.form-range::-webkit-slider-thumb {
	background-color: var(--basalt-hue);
}
.form-range::-moz-range-thumb {
	background-color: var(--basalt-hue);
}

/* Progress bars and spinners run in the primary; nav, pagination, list
   groups and buttons are recolored by their own partials. */
.progress-bar {
	background-color: var(--basalt-hue);
}

.spinner-border,
.spinner-grow {
	color: var(--basalt-hue);
}

/* Validation edges follow the focus ring so a field marked wrong stays red
   while someone corrects it. */
.was-validated .form-control:invalid,
.form-control.is-invalid {
	border-color: var(--basalt-danger);
}

.was-validated .form-control:valid,
.form-control.is-valid {
	border-color: var(--basalt-success);
}

.invalid-feedback {
	color: var(--bs-form-invalid-color);
}

.valid-feedback {
	color: var(--bs-form-valid-color);
}

/* Switches are scoped under .form-switch by Bootstrap, so they need that
   extra class to take the plain primary. */
.form-switch .form-check-input:checked {
	border-color: var(--basalt-hue);
	background-color: var(--basalt-hue);
}
.form-switch .form-check-input:focus-visible {
	border-color: var(--basalt-hue);
	box-shadow: 0 0 0 0.25rem var(--basalt-hue-border);
}

.table {
	--bs-table-border-color: var(--basalt-edge);
	--bs-table-color: var(--basalt-copy-body);
}

/* Cards pad from the shared spacing and pull their sides in on a phone. */
.card {
	--bs-card-border-color: var(--basalt-edge);
	--bs-card-bg: var(--basalt-plane);
	--bs-card-spacer-y: var(--basalt-pad-x);
	--bs-card-spacer-x: var(--basalt-pad-x);
	--bs-card-cap-padding-y: 1.1rem;
	--bs-card-cap-padding-x: var(--basalt-pad-x);
}
@media (max-width: 575.98px) {
	.card {
		--bs-card-spacer-x: var(--basalt-pad-x-narrow);
		--bs-card-cap-padding-x: var(--basalt-pad-x-narrow);
	}
}

.modal-content {
	border-color: var(--basalt-edge);
	background-color: var(--basalt-plane);
}

/* Between 576 and 991px Bootstrap shrinks large dialogs to 500px, too narrow
   for two columns, so on a tablet they spread to the width available. */
@media (min-width: 576px) and (max-width: 991.98px) {
	.modal-lg,
	.modal-xl {
		--bs-modal-width: calc(100vw - 3rem);
		max-width: 720px;
	}
}
.offcanvas {
	color: var(--basalt-copy);
	background-color: var(--basalt-plane);
}

.accordion {
	--bs-accordion-bg: var(--basalt-plane);
	--bs-accordion-border-color: var(--basalt-edge);
	--bs-accordion-active-bg: var(--basalt-hue-soft);
	--bs-accordion-active-color: var(--basalt-hue);
}

/* The chosen menu entry is tinted instead of filled solid, so its label
   reads under every palette. */
.dropdown-menu {
	--bs-dropdown-bg: var(--basalt-plane);
	--bs-dropdown-border-color: var(--basalt-edge);
	--bs-dropdown-link-active-bg: var(--basalt-hue-soft);
	--bs-dropdown-link-active-color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
}

/* Bootstrap rings these on :focus, which a click also sets off; only
   keyboard focus keeps the ring. */
.accordion-button:focus:not(:focus-visible),
.page-link:focus:not(:focus-visible),
.btn-close:focus:not(:focus-visible),
.navbar-toggler:focus:not(:focus-visible) {
	box-shadow: none;
}

/* The ground every page stands on. The document carries the page's type and
   colors, the heading scale is softened, and only after that come the media,
   link, button and focus defaults that keep the parts from fighting it. */
html {
	-webkit-text-size-adjust: 100%;
}

body.basalt-doc {
	min-height: 100vh;
	margin: 0;
	font-family: "Schibsted Grotesk", sans-serif;
	font-size: 0.92rem;
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	color: var(--basalt-copy);
	background-color: var(--basalt-canvas);
}

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

/* Bold and tighter for the three biggest levels, the larger the tighter;
   semibold with barely any tracking below them. */
h1,
.h1 {
	font-weight: 700;
	letter-spacing: -0.02em;
}

h2,
.h2 {
	font-weight: 700;
	letter-spacing: -0.015em;
}

h3,
.h3 {
	font-weight: 700;
	letter-spacing: -0.01em;
}

h4,
h5,
h6,
.h4,
.h5,
.h6 {
	font-weight: 600;
	letter-spacing: -0.005em;
}

small,
.small {
	font-size: 0.81rem;
}

/* Images and icons stay inside their box, links take the color around them,
   and buttons speak in the page font. */
svg,
img {
	display: block;
	max-width: 100%;
}

a {
	color: inherit;
}

button {
	font-family: inherit;
}

/* A keyboard user sees a tinted ring where the browser outline would be. */
:focus-visible {
	outline: 0;
	box-shadow: 0 0 0 3px var(--basalt-hue-border);
}

/* The frame holds the top bar, the page and its footer, and keeps clear of
   the fixed menu with a left margin that follows the menu's width. */
.basalt-frame {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
	margin-left: 300px;
	transition: margin-left 240ms cubic-bezier(0.32, 0.72, 0, 1);
}
@media (max-width: 991.98px) {
	.basalt-frame {
		margin-left: 0;
	}
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-frame {
		margin-left: 80px;
	}
}

/* Behind the open menu on small screens the page dims; a tap on the dimmed
   part closes the menu again. It is a plain tint, not a blur: a blurred
   backdrop shows a mirrored copy of the page at its edges in some browsers,
   most of all when the page sits inside a scaled frame. */
.basalt-dim {
	position: fixed;
	inset: 0;
	z-index: 1036;
	visibility: hidden;
	background: color-mix(in srgb, var(--basalt-scrim) 85%, #000 15%);
	opacity: 0;
	transition:
		opacity 240ms cubic-bezier(0.32, 0.72, 0, 1),
		visibility 240ms cubic-bezier(0.32, 0.72, 0, 1);
}
.basalt-dim.is-visible {
	visibility: visible;
	opacity: 1;
}

/* The menu panel is fixed to the left edge. Below 992px it waits off screen
   until the menu button slides it in; from 992px up it can also fold to an
   80px rail of section tiles, which body.basalt-menu-narrow switches on. */
.basalt-mainmenu {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 1038;
	display: flex;
	flex-direction: column;
	width: 300px;
	border-right: 1px solid var(--basalt-edge);
	background-color: var(--basalt-plane);
	transition:
		transform 240ms cubic-bezier(0.32, 0.72, 0, 1),
		width 240ms cubic-bezier(0.32, 0.72, 0, 1);
}
@media (max-width: 991.98px) {
	.basalt-mainmenu {
		transform: translateX(-100%);
		box-shadow: var(--basalt-card-shadow);
	}
	.basalt-mainmenu.is-open {
		transform: translateX(0);
	}
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu {
		width: 80px;
	}
}

/* Top row: the logo, then the fold button on wide screens or the close
   button on small ones. On the rail the row stacks into a column and only
   the mark is left of the logo. */
.basalt-mainmenu-top {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	min-height: 72px;
	padding: 1.125rem 0.875rem 0.75rem 1.125rem;
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-top {
		gap: 0.625rem;
		flex-direction: column;
		padding: 1.125rem 0 0.5rem;
	}
	body.basalt-menu-narrow .basalt-mainmenu-top .basalt-logo-word,
	body.basalt-menu-narrow .basalt-mainmenu-top .basalt-logo-plan {
		display: none;
	}
}

.basalt-mainmenu-shrink {
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	margin-left: auto;
	border: 0;
	border-radius: 8px;
	color: var(--basalt-copy-muted);
	background: transparent;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
.basalt-mainmenu-shrink:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
@media (max-width: 991.98px) {
	.basalt-mainmenu-shrink {
		display: none;
	}
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-shrink {
		width: 40px;
		height: 38px;
		margin: 0;
		border-radius: 12px;
		border: 1px dashed var(--basalt-edge-strong);
	}
	body.basalt-menu-narrow .basalt-mainmenu-shrink:hover {
		border-style: solid;
	}
}

/* The button carries both pictures: panel open, and panel folded. */
.basalt-mainmenu-shrink-narrow,
body.basalt-menu-narrow .basalt-mainmenu-shrink-wide {
	display: none;
}

body.basalt-menu-narrow .basalt-mainmenu-shrink-narrow {
	display: inline;
}

.basalt-mainmenu-shut {
	margin-left: auto;
	border: 0;
	color: var(--basalt-copy-muted);
	background: transparent;
}
.basalt-mainmenu-shut:hover {
	color: var(--basalt-copy);
}

/* Jump to a page: a plain field that filters the menu below it. The
   gradient edge is a border-box background, so with gradients off it turns
   into a solid line in the primary color. Focus adds no glow or ring; the
   caret is the cue. */
.basalt-mainmenu-find {
	display: flex;
	gap: 0.625rem;
	align-items: center;
	height: 42px;
	margin: 0 1rem 0.75rem;
	padding: 0 0.5rem 0 0.8rem;
	border-radius: 13px;
	border: 1px solid transparent;
	color: var(--basalt-copy-muted);
	background:
		linear-gradient(var(--basalt-plane), var(--basalt-plane)) padding-box,
		var(--basalt-grad) border-box;
	cursor: text;
}
.basalt-mainmenu-find > .bi-search {
	font-size: 1rem;
	line-height: 1;
	color: var(--basalt-hue);
}

.basalt-mainmenu-find-field {
	flex: 1;
	min-width: 0;
	padding: 0;
	border: 0;
	outline: 0;
	font: inherit;
	font-size: 0.84rem;
	font-weight: 500;
	color: var(--basalt-copy);
	background: transparent;
}
.basalt-mainmenu-find-field::placeholder {
	color: var(--basalt-copy-muted);
	opacity: 1;
}
.basalt-mainmenu-find-field::-webkit-search-cancel-button {
	display: none;
}
.basalt-mainmenu-find-field:focus,
.basalt-mainmenu-find-field:focus-visible {
	outline: 0;
	box-shadow: none;
}

.basalt-mainmenu-find-reset {
	display: grid;
	place-items: center;
	width: 24px;
	height: 24px;
	border: 0;
	border-radius: 7px;
	font-size: 0.7rem;
	color: var(--basalt-copy-muted);
	background: transparent;
}
.basalt-mainmenu-find-reset:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}

/* The sections scroll on their own between the field and the account row. */
.basalt-mainmenu-scroll {
	flex: 1;
	min-height: 0;
	padding: 0 0.75rem 1rem;
	overflow-y: auto;
	scrollbar-width: thin;
	scrollbar-color: var(--basalt-edge-strong) transparent;
}
.basalt-mainmenu-scroll::-webkit-scrollbar {
	width: 6px;
}
.basalt-mainmenu-scroll::-webkit-scrollbar-thumb {
	border-radius: 6px;
	background: var(--basalt-edge-strong);
}

.basalt-mainmenu-nomatch {
	margin: 0.75rem 0.25rem;
	padding: 1rem;
	border-radius: 12px;
	border: 1px dashed var(--basalt-edge-strong);
	font-size: 0.81rem;
	text-align: center;
	color: var(--basalt-copy-muted);
}

@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-find,
	body.basalt-menu-narrow .basalt-mainmenu-scroll {
		display: none;
	}
}
/* The account row closes the panel: the initials on a disc inside a 2px
   gradient ring, the name over the role, and a settings link. On the rail
   only the ring is left, centered. */
.basalt-mainmenu-account {
	display: flex;
	gap: 0.625rem;
	align-items: center;
	margin: 0.5rem 0.875rem 0.875rem;
	padding: 0.625rem;
	border-radius: 14px;
	border: 1px solid var(--basalt-edge);
	background: var(--basalt-canvas);
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-account {
		justify-content: center;
		margin: 0.5rem;
		padding: 0.5rem 0;
	}
}

.basalt-mainmenu-face {
	flex: none;
	width: 36px;
	height: 36px;
	padding: 2px;
	border-radius: 50%;
	background: var(--basalt-grad);
}
.basalt-mainmenu-face > span {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	font-size: 0.75rem;
	font-weight: 800;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
}

.basalt-mainmenu-account-text {
	display: grid;
	min-width: 0;
	line-height: 1.2;
}

.basalt-mainmenu-person {
	font-size: 0.81rem;
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-mainmenu-jobline {
	font-size: 0.71rem;
	color: var(--basalt-copy-muted);
}

.basalt-mainmenu-account-gear {
	display: grid;
	place-items: center;
	width: 30px;
	height: 30px;
	margin-left: auto;
	border-radius: 8px;
	text-decoration: none;
	color: var(--basalt-copy-muted);
}
.basalt-mainmenu-account-gear:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}

@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-account-text,
	body.basalt-menu-narrow .basalt-mainmenu-account-gear {
		display: none;
	}
}
/* The rail menu.js builds for the folded panel: a search tile, then one
   tile per section in the section's color, the current section's tile
   larger and solid. It only shows while the panel is folded. */
.basalt-mainmenu-strip {
	display: none;
}
@media (min-width: 992px) {
	body.basalt-menu-narrow .basalt-mainmenu-strip {
		display: flex;
		gap: 0.3rem;
		flex: 1;
		flex-direction: column;
		align-items: center;
		min-height: 0;
		padding: 0.25rem 0 0.5rem;
		overflow-y: auto;
		scrollbar-width: none;
	}
	body.basalt-menu-narrow .basalt-mainmenu-strip::-webkit-scrollbar {
		display: none;
	}
}

/* The list wrapper adds no box of its own, and its tiles take the section
   colors in the same order as the sections do. */
.basalt-mainmenu-strip-list {
	display: contents;
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 2) {
	--basalt-section: var(--basalt-series-2);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 3) {
	--basalt-section: var(--basalt-series-3);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 4) {
	--basalt-section: var(--basalt-series-4);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 5) {
	--basalt-section: var(--basalt-series-5);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 6) {
	--basalt-section: var(--basalt-series-6);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 7) {
	--basalt-section: var(--basalt-series-7);
}
.basalt-mainmenu-strip-list > :nth-of-type(8n + 8) {
	--basalt-section: var(--basalt-series-8);
}

.basalt-mainmenu-strip-btn {
	--basalt-section: var(--basalt-series-1);
	position: relative;
	display: grid;
	flex: none;
	place-items: center;
	width: 40px;
	height: 38px;
	border: 0;
	border-radius: 12px;
	font-size: 1.05rem;
	color: color-mix(in srgb, var(--basalt-section) 78%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-section) 13%, transparent);
	transition:
		width 200ms cubic-bezier(0.3, 0.8, 0.3, 1),
		height 200ms cubic-bezier(0.3, 0.8, 0.3, 1),
		border-radius 200ms ease,
		background-color 170ms ease;
}
.basalt-mainmenu-strip-btn:hover,
.basalt-mainmenu-strip-btn.is-hot {
	background: color-mix(in srgb, var(--basalt-section) 22%, transparent);
}
.basalt-mainmenu-strip-btn.is-active {
	width: 50px;
	height: 48px;
	border-radius: 15px;
	font-size: 1.25rem;
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-section) 72%, var(--basalt-copy));
}

.basalt-mainmenu-strip-btn-find {
	--basalt-section: var(--basalt-hue);
}

/* On the narrow strip, a section holding a count shows a small ring in its
   own color at the tile's corner. */
.basalt-mainmenu-strip-mark {
	position: absolute;
	top: 7px;
	right: 7px;
	width: 9px;
	height: 9px;
	border: 2px solid var(--basalt-section, var(--basalt-hue));
	border-radius: 50%;
	background: var(--basalt-plane);
}

/* The flyout beside a rail tile lists that section's pages, grouped as
   they are in the open menu. menu.js places it next to the tile. */
.basalt-mainmenu-pop {
	position: fixed;
	z-index: 1045;
	width: 240px;
	max-height: calc(100vh - 24px);
	padding: 0.375rem;
	border-radius: 14px;
	border: 1px solid var(--basalt-edge-strong);
	overflow-y: auto;
	background: var(--basalt-plane);
	box-shadow: 0 18px 44px -14px rgba(0, 0, 0, 0.4);
	animation: basalt-flyout-in 130ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-mainmenu-pop {
		animation: none;
	}
}

@keyframes basalt-flyout-in {
	from {
		transform: translateX(-4px);
		opacity: 0;
	}
}
.basalt-mainmenu-pop-head {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	padding: 0.5rem 0.625rem 0.375rem;
	font-weight: 700;
	font-size: 0.875rem;
	color: var(--basalt-copy);
}

.basalt-mainmenu-pop-set {
	padding: 0.5rem 0.625rem 0.125rem;
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--basalt-copy-muted);
}

.basalt-mainmenu-pop-link {
	display: flex;
	gap: 0.625rem;
	align-items: center;
	padding: 0.4rem 0.625rem;
	border-radius: 9px;
	font-size: 0.84rem;
	font-weight: 500;
	text-decoration: none;
	color: var(--basalt-copy-body);
}
.basalt-mainmenu-pop-link .bi {
	color: var(--basalt-copy-muted);
}
.basalt-mainmenu-pop-link:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-mainmenu-pop-link.active {
	font-weight: 600;
	color: var(--basalt-hue);
	background: var(--basalt-hue-soft);
}
.basalt-mainmenu-pop-link.active .bi {
	color: var(--basalt-hue);
}
.basalt-mainmenu-pop-link .basalt-menu-count {
	margin-left: auto;
}

/* The logo: the mark, the word and the plan tag in one row. The mark is a
   24px drawing with a pixel of air on every side. */
.basalt-logo {
	display: inline-flex;
	gap: 0.5rem;
	align-items: center;
	text-decoration: none;
	color: var(--basalt-copy);
}

.basalt-logo-art {
	flex: none;
	width: 24px;
	height: 24px;
	margin: 1px;
}

/* The mark's gradient stops are set here so they follow the palette. With
   gradients switched off the mark takes the first series color instead;
   a stylesheet rule outranks the fill attribute on the path. */
.basalt-logo-fade-a {
	stop-color: var(--basalt-series-1);
}

.basalt-logo-fade-b {
	stop-color: var(--basalt-series-3);
}

:root[data-basalt-gradients="off"] .basalt-logo-glyph {
	fill: var(--basalt-series-1);
}

/* A mark drawn as a line carries its gradient on the stroke. */
:root[data-basalt-gradients="off"] .basalt-logo-glyph[stroke] {
	fill: none;
	stroke: var(--basalt-series-1);
}

.basalt-logo-word {
	font-size: 1.2rem;
	font-weight: 800;
	letter-spacing: -0.025em;
	color: var(--basalt-copy);
}

.basalt-logo-plan {
	padding: 3px 7px;
	border-radius: 6px;
	font-size: 0.625rem;
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: 0.055em;
	text-transform: uppercase;
	color: var(--basalt-on-hue);
	background: var(--basalt-grad);
}

/* A section takes its color from the palette's chart ramp by its place in
   the menu, so a section added later is colored without a class of its own.
   Everything inside reads the color from --basalt-section. */
.basalt-menu-group {
	--basalt-section: var(--basalt-series-1);
}
.basalt-menu-group:nth-of-type(8n + 2) {
	--basalt-section: var(--basalt-series-2);
}
.basalt-menu-group:nth-of-type(8n + 3) {
	--basalt-section: var(--basalt-series-3);
}
.basalt-menu-group:nth-of-type(8n + 4) {
	--basalt-section: var(--basalt-series-4);
}
.basalt-menu-group:nth-of-type(8n + 5) {
	--basalt-section: var(--basalt-series-5);
}
.basalt-menu-group:nth-of-type(8n + 6) {
	--basalt-section: var(--basalt-series-6);
}
.basalt-menu-group:nth-of-type(8n + 7) {
	--basalt-section: var(--basalt-series-7);
}
.basalt-menu-group:nth-of-type(8n + 8) {
	--basalt-section: var(--basalt-series-8);
}

/* The section heading is a button that folds the section. The small color
   chip in front of the name is drawn by ::before; the caret turns sideways
   while the section is folded. */
.basalt-menu-group-heading {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	width: 100%;
	padding: 0.75rem 0.5rem 0.375rem;
	border: 0;
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	text-align: left;
	text-transform: uppercase;
	color: var(--basalt-copy-muted);
	background: transparent;
}
.basalt-menu-group-heading::before {
	content: "";
	flex: none;
	width: 8px;
	height: 8px;
	border-radius: 3px;
	background: var(--basalt-section);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--basalt-section) 18%, transparent);
}
.basalt-menu-group-heading:hover {
	color: var(--basalt-copy);
}

.basalt-menu-group-caret {
	margin-left: auto;
	font-size: 0.625rem;
	opacity: 0.7;
	transition: transform 200ms ease;
}

.basalt-menu-group-shut .basalt-menu-group-caret {
	transform: rotate(-90deg);
}
.basalt-menu-group-shut > .basalt-menu-links {
	display: none;
}

/* A menu row: the glyph tile, the label, and on some rows a new-tab arrow
   or a count. The row of the page you are on grows a size, with a taller
   row and a larger solid tile. */
.basalt-menu-links {
	margin: 0;
	padding: 0;
	list-style: none;
}

.basalt-menu-entry,
.basalt-menu-child {
	display: flex;
	gap: 0.7rem;
	align-items: center;
	height: 38px;
	padding: 0 0.5rem 0 0.375rem;
	border-radius: 12px;
	font-size: 0.84rem;
	font-weight: 500;
	text-decoration: none;
	color: var(--basalt-copy-body);
	transition:
		height 200ms cubic-bezier(0.3, 0.8, 0.3, 1),
		font-size 200ms ease,
		background-color 170ms ease,
		color 170ms ease;
}

.basalt-menu-label {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	/* The menu filter marks the typed letters in the section's color. */
}
.basalt-menu-label mark {
	padding: 0;
	border-radius: 3px;
	color: inherit;
	background: color-mix(in srgb, var(--basalt-section) 24%, transparent);
	box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--basalt-section) 24%, transparent);
}

/* A row that opens in a new tab ends in a small arrow after the name. */
.basalt-menu-newtab {
	flex-shrink: 0;
	margin-left: 0.3rem;
	font-size: 0.7rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
body.basalt-menu-narrow .basalt-menu-newtab {
	display: none;
}

/* The glyph element is the tile itself; its icon is drawn by the icon
   font's ::before, centered in the tile. */
.basalt-menu-glyph {
	display: grid;
	flex: none;
	place-items: center;
	width: 28px;
	height: 28px;
	border-radius: 8px;
	font-size: 0.92rem;
	line-height: 1;
	color: color-mix(in srgb, var(--basalt-section) 78%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-section) 13%, transparent);
	transition:
		width 200ms cubic-bezier(0.3, 0.8, 0.3, 1),
		height 200ms cubic-bezier(0.3, 0.8, 0.3, 1),
		border-radius 200ms ease,
		font-size 200ms ease,
		background-color 170ms ease,
		color 170ms ease;
}

.basalt-menu-entry:hover,
.basalt-menu-child:hover {
	color: var(--basalt-copy);
	background-color: var(--basalt-wash);
}

.basalt-menu-entry.active,
.basalt-menu-child.active {
	height: 48px;
	font-size: 0.9rem;
	font-weight: 700;
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-section) 11%, transparent);
}
.basalt-menu-entry.active .basalt-menu-glyph,
.basalt-menu-child.active .basalt-menu-glyph {
	width: 36px;
	height: 36px;
	border-radius: 11px;
	font-size: 1.1rem;
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-section) 72%, var(--basalt-copy));
}

.basalt-menu-entry.trail-current {
	font-weight: 600;
	color: var(--basalt-copy);
}

/* A parent row folds its own list open and shut; its caret turns sideways
   while the list is shut. */
.basalt-menu-caret {
	margin-left: auto;
	font-size: 0.625rem;
	opacity: 0.6;
	transition: transform 200ms ease;
}

.basalt-menu-count + .basalt-menu-caret {
	margin-left: 0.375rem;
}

.basalt-menu-entry-parent[aria-expanded="false"] .basalt-menu-caret {
	transform: rotate(-90deg);
}

/* The list under a parent hangs from a line in the section color, with
   rows and tiles a step smaller than the rows above it. */
.basalt-menu-children {
	margin: 0.125rem 0 0.375rem 1.2rem;
	padding: 0.125rem 0 0.125rem 0.56rem;
	border-left: 2px solid color-mix(in srgb, var(--basalt-section) 28%, transparent);
	list-style: none;
}

.basalt-menu-child {
	height: 34px;
	padding-left: 0.3rem;
	font-size: 0.81rem;
}
.basalt-menu-child .basalt-menu-glyph {
	width: 24px;
	height: 24px;
	border-radius: 7px;
	font-size: 0.8rem;
}
.basalt-menu-child.active {
	height: 42px;
	font-size: 0.875rem;
}
.basalt-menu-child.active .basalt-menu-glyph {
	width: 30px;
	height: 30px;
	border-radius: 9px;
	font-size: 0.95rem;
}

/* A count of things waiting on a menu entry, tinted in its section's color
   so it reads as part of the menu rather than an alert. */
.basalt-menu-count {
	min-width: 22px;
	margin-left: auto;
	padding: 4px 6px;
	border-radius: 6px;
	font-size: 0.7rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	line-height: 1;
	text-align: center;
	color: color-mix(in srgb, var(--basalt-section, var(--basalt-hue)) 54%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-section, var(--basalt-hue)) 15%, transparent);
}

/* A dashboard row tells how many pages wait in its business area, quietly
   and only while the row is pointed at or focused. The count is plain text
   in each page's menu, matching the area's pages in data/areas.js. */
.basalt-menu-pages {
	flex-shrink: 0;
	margin-left: auto;
	font-family: "Chivo Mono", monospace;
	font-size: 0.66rem;
	font-weight: 400;
	white-space: nowrap;
	color: color-mix(in srgb, currentColor 62%, transparent);
	opacity: 0;
	transition: opacity 150ms ease;
}
a:hover > .basalt-menu-pages,
a:focus-visible > .basalt-menu-pages {
	opacity: 1;
}
body.basalt-menu-narrow .basalt-menu-pages {
	display: none;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-menu-pages {
		transition: none;
	}
}

/* While the filter has text, every section and list that still holds a
   match is shown open; menu.js hides the rows that do not match. */
.basalt-mainmenu.is-filtering .basalt-menu-group > .basalt-menu-links,
.basalt-mainmenu.is-filtering .basalt-menu-children {
	display: block;
}
.basalt-mainmenu.is-filtering .basalt-menu-group-caret,
.basalt-mainmenu.is-filtering .basalt-menu-caret {
	transform: none;
}

/* Four looks for one menu, chosen by data-basalt-menu-look on <html> from
   the Appearance panel, or fixed in a build by writing the attribute into
   the page. Without the attribute the menu is Quiet: line icons, no tiles,
   and a fine bar beside the page you are on. Pop gives every section its
   own color and fills the current row with it. Ink is a dark menu beside a
   light page. Floating is a detached card, and choosing it floats the
   header too. */
/* Quiet, Ink and Floating share the line icons and the plain rows. */
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-group-heading {
	padding: 1.1rem 0.75rem 0.4rem;
	font-size: 0.7rem;
	letter-spacing: 0.08em;
	color: color-mix(in srgb, var(--basalt-copy-muted) 80%, var(--basalt-copy));
}
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-group-heading::before {
	display: none;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-entry,
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-child {
	position: relative;
	gap: 0.75rem;
	height: 38px;
	padding: 0 0.75rem;
	border-radius: 10px;
	font-size: 0.875rem;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-glyph,
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-entry.active .basalt-menu-glyph,
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-child.active .basalt-menu-glyph {
	width: 20px;
	height: 20px;
	border-radius: 0;
	font-size: 1rem;
	color: var(--basalt-copy-muted);
	background: transparent;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-entry.active,
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-child.active {
	height: 38px;
	font-size: 0.875rem;
	font-weight: 600;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-menu-children {
	padding-left: 1.1rem;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-mainmenu-find {
	margin: 0.25rem 1rem 0.5rem;
	border: 1px solid var(--basalt-edge-strong);
	background: transparent;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-mainmenu-find > .bi-search {
	color: var(--basalt-copy-muted);
}
:root:not([data-basalt-menu-look="pop"]) .basalt-mainmenu-account {
	background: transparent;
}
:root:not([data-basalt-menu-look="pop"]) .basalt-mainmenu-face {
	background: var(--basalt-edge-strong);
}

/* Quiet: the current row gets a soft fill, a palette-colored icon and a
   fine bar on its left edge. */
:root:not([data-basalt-menu-look]) .basalt-menu-entry.active,
:root:not([data-basalt-menu-look]) .basalt-menu-child.active {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
:root:not([data-basalt-menu-look]) .basalt-menu-entry.active::before,
:root:not([data-basalt-menu-look]) .basalt-menu-child.active::before {
	content: "";
	position: absolute;
	top: 9px;
	bottom: 9px;
	left: 0;
	width: 3px;
	border-radius: 0 3px 3px 0;
	background: var(--basalt-hue);
}
:root:not([data-basalt-menu-look]) .basalt-menu-entry.active .basalt-menu-glyph,
:root:not([data-basalt-menu-look]) .basalt-menu-child.active .basalt-menu-glyph {
	color: var(--basalt-hue);
}

/* Pop: each section in its own color, the current row filled with it. */
[data-basalt-menu-look="pop"] .basalt-menu-group-heading {
	padding: 1rem 0.6rem 0.4rem;
}
[data-basalt-menu-look="pop"] .basalt-menu-group-heading::before {
	width: 14px;
	height: 4px;
	border-radius: 4px;
	box-shadow: none;
}
[data-basalt-menu-look="pop"] .basalt-menu-entry,
[data-basalt-menu-look="pop"] .basalt-menu-child {
	gap: 0.7rem;
	height: 40px;
	padding: 0 0.6rem;
	border-radius: 12px;
	font-size: 0.875rem;
}
[data-basalt-menu-look="pop"] .basalt-menu-glyph,
[data-basalt-menu-look="pop"] .basalt-menu-entry.active .basalt-menu-glyph,
[data-basalt-menu-look="pop"] .basalt-menu-child.active .basalt-menu-glyph {
	width: 22px;
	height: 22px;
	border-radius: 0;
	font-size: 1.05rem;
	background: transparent;
}
[data-basalt-menu-look="pop"] .basalt-menu-glyph {
	color: color-mix(in srgb, var(--basalt-section) 80%, var(--basalt-copy));
}
[data-basalt-menu-look="pop"] .basalt-menu-entry:hover,
[data-basalt-menu-look="pop"] .basalt-menu-child:hover {
	background: color-mix(in srgb, var(--basalt-section) 10%, transparent);
}
[data-basalt-menu-look="pop"] .basalt-menu-entry.active,
[data-basalt-menu-look="pop"] .basalt-menu-child.active {
	height: 44px;
	font-size: 0.9rem;
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-section) 78%, var(--basalt-copy));
	box-shadow: 0 10px 22px -14px color-mix(in srgb, var(--basalt-section) 90%, transparent);
}
[data-basalt-menu-look="pop"] .basalt-menu-entry.active .basalt-menu-glyph,
[data-basalt-menu-look="pop"] .basalt-menu-child.active .basalt-menu-glyph {
	color: var(--basalt-plane);
}

/* Ink: a dark menu beside a light page. Its shade comes from the palette's
   deep color; in dark mode it sits on the page color. Inside the menu the
   surface and text tokens are swapped for the ink ones, so every part of
   the menu follows without rules of its own. */
[data-basalt-menu-look="ink"] {
	--basalt-ink: color-mix(in srgb, var(--basalt-hue-deep) 24%, var(--basalt-copy));
	--basalt-ink-fg: var(--basalt-plane);
}
[data-basalt-menu-look="ink"][data-bs-theme="dark"] {
	--basalt-ink: var(--basalt-canvas);
	--basalt-ink-fg: var(--basalt-copy);
}
[data-basalt-menu-look="ink"] .basalt-mainmenu {
	--basalt-plane: var(--basalt-ink);
	--basalt-canvas: color-mix(in srgb, var(--basalt-ink-fg) 6%, var(--basalt-ink));
	--basalt-copy: var(--basalt-ink-fg);
	--basalt-copy-body: color-mix(in srgb, var(--basalt-ink-fg) 82%, var(--basalt-ink));
	--basalt-copy-muted: color-mix(in srgb, var(--basalt-ink-fg) 62%, var(--basalt-ink));
	--basalt-edge: color-mix(in srgb, var(--basalt-ink-fg) 10%, transparent);
	--basalt-edge-strong: color-mix(in srgb, var(--basalt-ink-fg) 18%, transparent);
	--basalt-wash: color-mix(in srgb, var(--basalt-ink-fg) 8%, transparent);
	border-right-color: transparent;
	color-scheme: dark;
}
[data-basalt-menu-look="ink"] .basalt-menu-entry.active,
[data-basalt-menu-look="ink"] .basalt-menu-child.active {
	color: var(--basalt-on-hue);
	background: var(--basalt-hue);
}
[data-basalt-menu-look="ink"] .basalt-menu-entry.active .basalt-menu-glyph,
[data-basalt-menu-look="ink"] .basalt-menu-child.active .basalt-menu-glyph {
	color: var(--basalt-on-hue);
}

/* Floating: a detached card, inset from the window edges. Closed on a
   small screen it has to travel further to hide its edge and shadow. */
[data-basalt-menu-look="floating"] .basalt-mainmenu {
	border: 1px solid var(--basalt-edge);
	border-radius: 18px;
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--basalt-copy) 5%, transparent),
		0 18px 40px -28px color-mix(in srgb, var(--basalt-copy) 50%, transparent);
}
@media (min-width: 992px) {
	[data-basalt-menu-look="floating"] body:not(.basalt-menu-narrow) .basalt-mainmenu {
		top: 12px;
		bottom: 12px;
		left: 12px;
		width: 276px;
	}
	[data-basalt-menu-look="floating"] body.basalt-menu-narrow .basalt-mainmenu {
		top: 12px;
		bottom: 12px;
		left: 12px;
		width: 68px;
	}
}
@media (max-width: 991.98px) {
	[data-basalt-menu-look="floating"] .basalt-mainmenu {
		top: 8px;
		bottom: 8px;
		left: 8px;
	}
	[data-basalt-menu-look="floating"] .basalt-mainmenu:not(.is-open) {
		transform: translateX(calc(-100% - 3rem));
	}
}
[data-basalt-menu-look="floating"] .basalt-menu-entry.active,
[data-basalt-menu-look="floating"] .basalt-menu-child.active {
	color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
}
[data-basalt-menu-look="floating"] .basalt-menu-entry.active .basalt-menu-glyph,
[data-basalt-menu-look="floating"] .basalt-menu-child.active .basalt-menu-glyph {
	color: var(--basalt-hue);
}

/* The top bar sticks to the top of the page column. Its side padding is the
   same as the page content's, so the search box lines up with the cards
   below it. --basalt-header-bg is the surface the unread marks cut into. */
.basalt-topbar {
	--basalt-header-bg: var(--basalt-plane);
	position: sticky;
	top: 0;
	z-index: 1028;
	display: flex;
	gap: 1rem;
	align-items: center;
	justify-content: space-between;
	min-height: 72px;
	padding: 0.5rem 1.5rem;
	border-bottom: 1px solid var(--basalt-edge);
	background-color: var(--basalt-header-bg);
}
@media (max-width: 575.98px) {
	.basalt-topbar {
		padding: 0.5rem 1rem;
	}
}
.basalt-topbar {
	/* Icon buttons are square and quiet. */
}
.basalt-topbar .btn-icon {
	width: 40px;
	height: 40px;
	padding: 0;
}

/* The start holds the menu button and the search box and takes the spare
   width. The end holds three groups of controls, spaced exactly as one
   row: tools, the inbox trays, and the account. */
.basalt-topbar-start {
	display: flex;
	gap: 0.5rem;
	flex: 1 1 auto;
	align-items: center;
	min-width: 0;
}

.basalt-topbar-end,
.basalt-topbar-tools,
.basalt-topbar-inbox {
	display: flex;
	gap: 0.25rem;
	align-items: center;
}

.basalt-topbar-menubtn {
	color: var(--basalt-copy-muted);
}
.basalt-topbar-menubtn:hover {
	color: var(--basalt-copy);
}

/* The search box shows from tablet width up. On phones only its icon
   button shows; tapping it lays the box across the bar, and Esc or leaving
   the field closes it again. */
.basalt-topbar .basalt-topbar-find {
	display: none;
	max-width: 22rem;
}
@media (min-width: 768px) {
	.basalt-topbar .basalt-topbar-find {
		display: flex;
	}
}
.basalt-topbar .basalt-find .form-control {
	height: 40px;
	background-color: color-mix(in srgb, var(--basalt-copy) 5%, transparent);
}

@media (max-width: 767.98px) {
	.basalt-topbar.is-searching .basalt-topbar-find {
		position: absolute;
		inset: 50% 1rem auto;
		z-index: 2;
		transform: translateY(-50%);
		display: flex;
		/* Its width comes from the insets: a width of its own would push it
       past the right edge and scroll the page sideways. */
		width: auto;
		max-width: none;
	}
	.basalt-topbar.is-searching .basalt-topbar-find .form-control {
		border-color: var(--basalt-hue);
		background-color: var(--basalt-plane);
	}
	.basalt-topbar.is-searching .basalt-find-hint {
		display: none;
	}
}
/* Anything unread is one small dot: red for notifications, the palette
   color for messages. The dot is painted over the badge's own fill, so the
   badges keep their utility classes. */
.basalt-topbar .basalt-pip,
.basalt-topbar .basalt-tally {
	top: 9px;
	right: 9px;
	width: 8px;
	min-width: 0;
	height: 8px;
	padding: 0;
	border: 0;
	font-size: 0;
	background-image: linear-gradient(var(--basalt-hue), var(--basalt-hue));
	box-shadow: 0 0 0 2px var(--basalt-header-bg);
}
.basalt-topbar .basalt-pip {
	background-image: linear-gradient(var(--basalt-danger), var(--basalt-danger));
}
.basalt-topbar .basalt-me .basalt-avatar {
	width: 34px;
	height: 34px;
	font-size: 0.75rem;
}

/* Three header looks for one bar, chosen by data-basalt-header on <html>
   from the Appearance panel, or fixed in a build by writing the attribute
   into the page. Without it the bar is Hairline: plain, with a fine line
   underneath. data-basalt-header-sticky="off" lets the bar scroll away
   with the page. --basalt-header-h is the height the bar covers at the top
   of the window, for anything else that has to stay clear of it. */
:root {
	--basalt-header-h: 72px;
}

[data-basalt-header="floating"] {
	--basalt-header-h: 86px;
}

[data-basalt-header="grouped"] {
	--basalt-header-h: 76px;
}

[data-basalt-header-sticky="off"] {
	--basalt-header-h: 0px;
}
[data-basalt-header-sticky="off"] .basalt-topbar {
	position: relative;
	top: auto;
}

/* Floating: a detached bar with a fine border and a soft shadow. */
[data-basalt-header="floating"] .basalt-topbar {
	--basalt-header-bg: var(--basalt-plane);
	top: 0.75rem;
	min-height: 62px;
	margin: 0.75rem 1.5rem 0;
	padding: 0.375rem 0.5rem 0.375rem 0.75rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 14px;
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--basalt-copy) 5%, transparent),
		0 12px 28px -20px color-mix(in srgb, var(--basalt-copy) 45%, transparent);
}
[data-basalt-header="floating"] .basalt-topbar-find {
	max-width: 25rem;
}

/* Grouped: a little taller, with the account in a quiet box of its own. */
[data-basalt-header="grouped"] .basalt-topbar {
	--basalt-header-bg: var(--basalt-plane);
	min-height: 76px;
}
[data-basalt-header="grouped"] .basalt-topbar-find {
	max-width: 21rem;
}
[data-basalt-header="grouped"] .basalt-me {
	padding: 0.3rem 0.75rem 0.3rem 0.3rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	background-color: color-mix(in srgb, var(--basalt-copy) 3%, var(--basalt-plane));
}
[data-basalt-header="grouped"] .basalt-me .basalt-avatar {
	border-radius: 9px;
}
[data-basalt-header="grouped"] .basalt-me {
	/* Below 992px the name is hidden, so the box hugs the avatar evenly. */
}
@media (max-width: 991.98px) {
	[data-basalt-header="grouped"] .basalt-me {
		padding: 0.3rem;
	}
}

[data-basalt-header="floating"] .basalt-find .form-control,
[data-basalt-header="grouped"] .basalt-find .form-control {
	border-color: var(--basalt-edge-strong);
	background-color: var(--basalt-plane);
}

/* From tablet width up, fine rules part the groups: before the inbox and
   the account in Hairline and Grouped, and in Floating only before the
   account, which then sits closer. */
@media (min-width: 768px) {
	.basalt-topbar-inbox {
		margin-left: 0.75rem;
		padding-left: 0.75rem;
		border-left: 1px solid var(--basalt-edge);
	}
	.basalt-topbar .basalt-me {
		margin-left: 0.75rem;
	}
	[data-basalt-header="floating"] .basalt-topbar-inbox {
		margin-left: 0;
		padding-left: 0;
		border-left: 0;
	}
	[data-basalt-header="floating"] .basalt-topbar .basalt-me {
		margin-left: 0;
	}
	[data-basalt-header="floating"] .basalt-topbar-account {
		margin-left: 0.5rem;
		padding-left: 0.5rem;
		border-left: 1px solid var(--basalt-edge);
	}
}
@media (max-width: 575.98px) {
	[data-basalt-header="floating"] {
		--basalt-header-h: 74px;
	}
	[data-basalt-header="floating"] .basalt-topbar {
		top: 0.5rem;
		margin: 0.5rem 0.75rem 0;
	}
}
/* An icon button is a quiet square with no border. Its icon color is the
   muted token pulled toward the text color, so it reads against the page
   and the top bar in every palette. */
.btn-icon {
	--bs-btn-padding-x: 0.5rem;
	--bs-btn-padding-y: 0.5rem;
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 0;
	border-radius: 10px;
	font-size: 1.05rem;
	line-height: 1;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: transparent;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
.btn-icon:hover,
.btn-icon:focus-visible {
	color: var(--basalt-copy);
	background-color: var(--basalt-wash);
}

/* The unread dot and the count follow a live number, so they must be able
   to disappear: the class with [hidden] outranks their display below. */
.basalt-pip[hidden],
.basalt-tally[hidden],
[data-basalt-mark-read][hidden] {
	display: none;
}

.basalt-pip {
	position: absolute;
	top: 6px;
	right: 8px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	border: 2px solid var(--basalt-plane);
}

.basalt-tally {
	position: absolute;
	top: 2px;
	right: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 18px;
	height: 18px;
	padding: 0 5px;
	border-radius: 999px;
	border: 2px solid var(--basalt-plane);
	font-size: 0.625rem;
	font-weight: 700;
	color: #fff;
}

/* The account button: avatar, then name over role. Both lines refuse to
   wrap, which keeps the column from shrinking to fit and breaking a
   two-word name; the width cap then bounds that, so a longer name than the
   demo's ends in an ellipsis instead of widening the bar. */
.basalt-me {
	display: inline-flex;
	gap: 0.625rem;
	align-items: center;
	padding: 0.3rem 0.5rem;
	border: 0;
	border-radius: 10px;
	color: var(--basalt-copy);
	background: transparent;
}
.basalt-me:hover {
	background-color: var(--basalt-wash);
}

.basalt-me-info {
	flex-direction: column;
	align-items: flex-start;
	min-width: 0;
	max-width: 11rem;
	line-height: 1.15;
	text-align: left;
	white-space: nowrap;
}

.basalt-me-name,
.basalt-me-job {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
}

.basalt-me-name {
	font-weight: 600;
	font-size: 0.81rem;
}

.basalt-me-job {
	font-size: 0.6875rem;
	color: var(--basalt-copy-muted);
}

/*
 * The top-bar find box, read left to right: a lens tucked inside the field,
 * the field itself, and a ⌘K key that bows out as soon as there is a query.
 * The second half styles what a list search leaves behind: hidden matches
 * and the "nothing found" panel.
 */
.basalt-find {
	position: relative;
	display: flex;
	align-items: center;
	width: 100%;
	max-width: 320px;
}

/* Both decorations float over the field, centered on its height. */
.basalt-find-lens,
.basalt-find-hint {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
}

.basalt-find-lens {
	left: 0.75rem;
	font-size: 0.9rem;
	color: var(--basalt-copy-muted);
	pointer-events: none;
}

/* The field leaves room for the lens on the left and the key on the right,
   and gives that right-hand room back once the key is gone. */
.basalt-find .form-control {
	padding-left: 2.25rem;
	padding-right: 3rem;
	border-color: transparent;
	border-radius: 10px;
	font-size: 0.875rem;
	background-color: var(--basalt-wash);
}
.basalt-find .form-control:focus {
	border-color: var(--basalt-hue);
	background-color: var(--basalt-plane);
	box-shadow: 0 0 0 3px var(--basalt-hue-border);
}
.basalt-find .form-control:not(:placeholder-shown) {
	padding-right: 0.75rem;
}
.basalt-find .form-control:not(:placeholder-shown) ~ .basalt-find-hint {
	display: none;
}

.basalt-find-hint {
	right: 0.5rem;
	min-width: 0;
	padding: 0.1rem 0.3rem;
	border: 0;
	border-radius: 6px;
	font-size: 0.7rem;
	font-weight: 600;
	line-height: inherit;
	color: var(--basalt-copy-muted);
	background-color: var(--basalt-wash);
}

/* When nothing matches, a centered panel says so. In a grid it spans every
   column, and in a table it sits in a row whose cell drops its own chrome. */
.basalt-empty {
	display: flex;
	gap: 0.25rem;
	flex-direction: column;
	grid-column: 1/-1;
	align-items: center;
	padding: 2.5rem 1rem;
	text-align: center;
}

.basalt-empty-icon {
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	margin-bottom: 0.5rem;
	border-radius: 50%;
	font-size: 1.25rem;
	color: var(--basalt-hue);
	background-color: var(--basalt-hue-soft);
}

.basalt-empty-title {
	max-width: 32rem;
	margin: 0;
	font-weight: 600;
	overflow-wrap: anywhere;
	color: var(--basalt-copy);
}

.basalt-empty-text {
	margin: 0 0 0.75rem;
	font-size: 0.875rem;
	color: var(--basalt-copy-muted);
}

.basalt-empty-row > td,
.table-hover > tbody > .basalt-empty-row > td {
	--bs-table-bg-state: transparent;
	padding: 0;
	border-bottom: 0;
	box-shadow: none;
}

/* The house card: a flat plane on a hairline edge that keeps its resting shadow under the pointer instead of lifting. */
.basalt-box {
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	background-color: var(--basalt-plane);
	box-shadow: var(--basalt-card-shadow);
	transition:
		box-shadow 200ms ease,
		transform 200ms ease;
}

.basalt-box:hover {
	box-shadow: var(--basalt-card-shadow);
}

/* Bodies get a touch more room than Bootstrap gives them, and small headings sit just under body size.
   The side and bottom padding are named so a chart at the foot can reach back out through them. */
.basalt-box .card-body {
	--basalt-foot-x: 1.25rem;
	--basalt-foot-y: 1.25rem;
	padding: 1.25rem var(--basalt-foot-x) var(--basalt-foot-y);
}

/* A chart at a card's foot bleeds to the card's edges: flush with the left,
   right and bottom, clipped by the card's rounded corners, while the text
   above keeps its padding. The body it sits in names its side and bottom
   padding in --basalt-foot-x and --basalt-foot-y (none when the chart sits
   straight inside the card), and the chart reaches back out by exactly that.
   A Chart.js chart in it turns layout.autoPadding off, so its plot meets the edges. */
.basalt-card-foot {
	width: calc(100% + 2 * var(--basalt-foot-x, 0px));
	max-width: none;
	margin-inline: calc(-1 * var(--basalt-foot-x, 0px));
	margin-bottom: calc(-1 * var(--basalt-foot-y, 0px));
}

:is(.card, .basalt-box):has(.basalt-card-foot) {
	overflow: hidden;
}

.basalt-box h6 {
	font-size: 0.95rem;
	font-weight: 600;
}

/* An avatar is a fixed circle that centers initials or crops a photo. The
   steps change only its box and type size, and inside a stack each one
   overlaps the last behind a ring of the surface color. */
.basalt-avatar {
	display: inline-flex;
	flex-shrink: 0;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	overflow: hidden;
	font-size: 0.875rem;
	font-weight: 600;
}
.basalt-avatar-group .basalt-avatar {
	box-sizing: content-box;
	margin-left: -8px;
	border: 2px solid var(--basalt-plane);
}
.basalt-avatar-group .basalt-avatar:first-child {
	margin-left: 0;
}

.basalt-avatar-xs {
	width: 26px;
	height: 26px;
	font-size: 0.625rem;
}

.basalt-avatar-sm {
	width: 32px;
	height: 32px;
	font-size: 0.75rem;
}

.basalt-avatar-lg {
	width: 56px;
	height: 56px;
	font-size: 1.1rem;
}

.basalt-avatar-group {
	display: inline-flex;
	align-items: center;
}

/* Badges are pinned to a compact table size; an icon inside shrinks to
   match and keeps a hair of room before the label. */
.badge {
	padding: 0.35em 0.55em;
	border-radius: 6px;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.01em;
}

.badge i {
	margin-right: 0.1rem;
	font-size: 0.75rem;
}

/* A tray is a top-bar dropdown laid out as a card: a title row, the rows,
   and a link row at the foot. */
.basalt-tray {
	min-width: 320px;
	padding: 0;
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	overflow: hidden;
	background-color: var(--basalt-plane);
	box-shadow: var(--basalt-card-shadow);
}

.basalt-tray-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 0.875rem 1rem;
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-tray-top a {
	text-decoration: none;
	color: var(--basalt-hue);
}

/* The tray's one action, a plain-text button in the accent color. */
.basalt-tray-action {
	padding: 0;
	border: 0;
	color: var(--basalt-hue);
	background: none;
}
.basalt-tray-action:hover {
	text-decoration: underline;
}

.basalt-tray-rows {
	max-height: 320px;
	margin: 0;
	padding: 0;
	overflow-y: auto;
	list-style: none;
}
.basalt-tray-rows::-webkit-scrollbar {
	width: 6px;
}
.basalt-tray-rows::-webkit-scrollbar-thumb {
	border-radius: 6px;
	background: var(--basalt-edge-strong);
}

/* A row is the avatar, then a line of what happened over a smaller line of
   when or a preview. */
.basalt-tray-row {
	display: flex;
	gap: 0.75rem;
	align-items: flex-start;
	padding: 0.75rem 1rem;
	border-bottom: 1px solid var(--basalt-edge);
	text-decoration: none;
	color: var(--basalt-copy);
	transition: background-color 170ms ease;
}
.basalt-tray-row:hover {
	background-color: var(--basalt-wash);
}
.basalt-tray-row:last-child {
	border-bottom: 0;
}
.basalt-tray-row small {
	font-size: 0.6875rem;
}

.basalt-tray-what {
	display: block;
	font-size: 0.81rem;
}

/* An unread row is tinted, a little bolder and marked with a dot at its
   end. The header mark counts these rows, so the two always agree. */
.basalt-tray-row-new {
	position: relative;
	background-color: var(--basalt-flare-soft);
}
.basalt-tray-row-new:hover {
	background-color: var(--basalt-wash);
}
.basalt-tray-row-new .basalt-tray-what {
	font-weight: 600;
}
.basalt-tray-row-new::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 0.85rem;
	width: 0.4rem;
	height: 0.4rem;
	margin-top: -0.2rem;
	border-radius: 50%;
	background-color: var(--basalt-flare);
}
.basalt-tray-row-new > .basalt-tray-copy {
	padding-right: 0.9rem;
}

.basalt-tray-end {
	padding: 0.625rem 1rem;
	border-top: 1px solid var(--basalt-edge);
	text-align: center;
}
.basalt-tray-end a {
	font-size: 0.81rem;
	font-weight: 600;
	text-decoration: none;
	color: var(--basalt-hue);
}

/* The account tray opens on the person, then plain links with an icon each. */
.basalt-tray-account {
	min-width: 240px;
}
.basalt-tray-account .dropdown-item {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	padding: 0.5rem 1rem;
	font-size: 0.875rem;
}
.basalt-tray-account .dropdown-item i {
	width: 20px;
	font-size: 1rem;
	color: var(--basalt-copy-muted);
}

.basalt-tray-me {
	gap: 0.5rem;
	justify-content: flex-start;
}

/* Every Bootstrap dropdown, not just the trays, sits on the page surface. */
.dropdown-menu {
	border-color: var(--basalt-edge);
	color: var(--basalt-copy);
	background-color: var(--basalt-plane);
}

.dropdown-divider {
	border-color: var(--basalt-edge);
}

.dropdown-item {
	color: var(--basalt-copy);
}

.dropdown-item:hover,
.dropdown-item:focus {
	color: var(--basalt-copy);
	background-color: var(--basalt-wash);
}

/* The ledger table borrows the card's surface instead of painting its own,
   and a hovered row picks up the wash tone. */
.basalt-ledger {
	--bs-table-bg: transparent;
	--bs-table-hover-bg: var(--basalt-wash);
	--bs-table-color: var(--basalt-copy);
	--bs-table-color-state: var(--basalt-copy);
	/* A hairline runs under every cell, header and body alike. */
}
.basalt-ledger thead th,
.basalt-ledger tbody td {
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-ledger {
	/* Column labels are small, spaced capitals in the muted ink. */
}
.basalt-ledger thead th {
	padding: 0.625rem 0.75rem;
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.035em;
	text-transform: uppercase;
	color: var(--basalt-copy-muted);
	background: transparent;
}
.basalt-ledger tbody td {
	padding: 0.875rem 0.75rem;
	font-size: 0.875rem;
	vertical-align: middle;
}
.basalt-ledger tbody {
	/* The card edge already closes the table, so the last row drops its rule. */
}
.basalt-ledger tbody tr:last-child td {
	border-bottom: 0;
}

/* Canvas charts never overflow their frame, whatever width the library asks for. */
.basalt-graph canvas {
	max-width: 100%;
}

/* The frame fills its column and anchors the canvas; the size classes fix its height to a strip or a full panel. */
.basalt-graph {
	position: relative;
	width: 100%;
}
.basalt-graph-short {
	height: 120px;
}
.basalt-graph-tall {
	height: 280px;
}

/* The full-screen button carries both icons. While the page is full screen
   it is pressed, and shows the way back instead. */
.basalt-fullscreen-exit {
	display: none;
}

.basalt-fullscreen[aria-pressed="true"] .basalt-fullscreen-enter {
	display: none;
}
.basalt-fullscreen[aria-pressed="true"] .basalt-fullscreen-exit {
	display: inline-block;
}
.basalt-fullscreen[hidden] {
	display: none;
}

/* The light/dark switch carries the sun and the moon. The theme attribute
   on <html> turns one in and the other out, with a quarter turn. */
.basalt-modeswitch {
	position: relative;
}

.basalt-modeswitch-day,
.basalt-modeswitch-night {
	transition:
		opacity 200ms ease,
		transform 300ms ease;
}

.basalt-modeswitch-night {
	position: absolute;
	inset: 0;
	transform: rotate(-90deg);
	display: flex;
	align-items: center;
	justify-content: center;
	opacity: 0;
}

[data-bs-theme="dark"] .basalt-modeswitch-day {
	transform: rotate(90deg);
	opacity: 0;
}
[data-bs-theme="dark"] .basalt-modeswitch-night {
	transform: rotate(0deg);
	opacity: 1;
}

/* The page column grows to fill the window, so on a short page the footer
   still sits at the bottom of the screen. */
.basalt-stage {
	display: flex;
	flex: 1;
	flex-direction: column;
	min-height: calc(100vh - var(--basalt-header-h, 72px));
}
.basalt-stage:focus {
	outline: none;
}

/* The footer is one row: the note on the left, the links on the right, and
   the links drop under the note once the two no longer fit side by side.
   Its text and links share the muted secondary gray and stay that color on
   hover. */
.basalt-pagefoot {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	margin-top: auto;
	padding: 1.25rem 1rem;
	border-top: 1px solid var(--basalt-edge);
	background-color: var(--basalt-plane);
}
@media (min-width: 992px) {
	.basalt-pagefoot {
		padding-inline: 1.5rem;
	}
}
.basalt-pagefoot a {
	text-decoration: none;
}

.basalt-pagefoot-note,
.basalt-pagefoot-links a {
	color: color-mix(in srgb, var(--basalt-copy-muted) 82%, var(--basalt-copy));
}

.basalt-pagefoot-note,
.basalt-pagefoot-links {
	margin: 0;
	font-size: 0.81rem;
}

.basalt-pagefoot-links {
	padding: 0;
	list-style: none;
}
.basalt-pagefoot-links > li {
	display: inline-block;
}
.basalt-pagefoot-links > li:not(:last-child) {
	margin-right: 0.5rem;
}

/* No button here carries a color of its own. Each variant hands palette
   colors to Bootstrap through the --bs-btn-* variables it already reads,
   so rest, hover, press and disabled all follow whichever palette is on,
   in light and in dark. Filled buttons sink toward the text color and set
   their label in the surface color (on-primary for the primary) to hold
   4.5:1 everywhere; outline labels stay legible on the page and on cards.
   buttons.html lays out the whole family. */
/* One palette color stirred into a second one at the given share. The
   second is the text color unless named; "clear" means transparent. */
/* Writes Bootstrap's label, background and border variables for each
   button phase handed in. A phase is a (label, background, border) list;
   a null entry, or a missing phase, leaves Bootstrap's value alone.
   Pressed copies hover unless it is given. */
/* Shared shape: rounder corners than Bootstrap, the palette's focus halo,
   and a disabled look that keeps full opacity on a quiet raised fill. */
.btn {
	--bs-btn-focus-box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--basalt-hue) 40%, transparent);
	--bs-btn-disabled-opacity: 1;
	--bs-btn-disabled-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-btn-disabled-bg: var(--basalt-plane-alt);
	--bs-btn-disabled-border-color: var(--basalt-edge-strong);
	border-radius: 10px;
}
.btn-sm {
	border-radius: 8px;
}
.btn {
	/* Bootstrap leaves a toggle at rest under the pointer; here it answers
      hover like every other button does. */
}
.btn-check + .btn:hover {
	border-color: var(--bs-btn-hover-border-color);
	color: var(--bs-btn-hover-color);
	background-color: var(--bs-btn-hover-bg);
}

/* The dismiss cross wears the same halo, not Bootstrap's blue one. */
.btn-close {
	--bs-btn-close-focus-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--basalt-hue) 40%, transparent);
}

/* The toned variants. Each entry names its palette color, the label that
   sits on its fill, and how much of that color goes into the resting fill,
   the pressed fill and the outline label (the rest is text color), plus
   how strongly the outline border shows over transparent. */
/* Selector list for every toned variant plus dark, under one prefix. */
/* A filled button rests on its fill and drops to the pressed fill on hover
   and on press. */
:is(.btn-primary, .btn-success, .btn-danger, .btn-warning, .btn-info, .btn-dark) {
	--bs-btn-color: var(--btn-ink);
	--bs-btn-bg: var(--btn-fill);
	--bs-btn-border-color: var(--btn-fill);
	--bs-btn-hover-color: var(--btn-ink);
	--bs-btn-hover-bg: var(--btn-fill-deep);
	--bs-btn-hover-border-color: var(--btn-fill-deep);
	--bs-btn-active-color: var(--btn-ink);
	--bs-btn-active-bg: var(--btn-fill-deep);
	--bs-btn-active-border-color: var(--btn-fill-deep);
}

/* An outline button shows a label and a border only; hover borrows the
   filled look and press the deeper fill. */
:is(
	.btn-outline-primary,
	.btn-outline-success,
	.btn-outline-danger,
	.btn-outline-warning,
	.btn-outline-info,
	.btn-outline-dark
) {
	--bs-btn-color: var(--btn-text);
	--bs-btn-bg: transparent;
	--bs-btn-border-color: var(--btn-edge);
	--bs-btn-hover-color: var(--btn-ink);
	--bs-btn-hover-bg: var(--btn-fill);
	--bs-btn-hover-border-color: var(--btn-fill);
	--bs-btn-active-color: var(--btn-ink);
	--bs-btn-active-bg: var(--btn-fill-deep);
	--bs-btn-active-border-color: var(--btn-fill-deep);
	--bs-btn-disabled-bg: transparent;
}

:is(.btn-primary, .btn-outline-primary) {
	--btn-ink: var(--basalt-on-hue);
	--btn-fill: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--btn-fill-deep: color-mix(in srgb, var(--basalt-hue) 74%, var(--basalt-copy));
	--btn-text: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
	--btn-edge: color-mix(in srgb, var(--basalt-hue) 70%, transparent);
	/* The primary alone is set a weight heavier. */
	font-weight: 600;
}

:is(.btn-success, .btn-outline-success) {
	--btn-ink: var(--basalt-plane);
	--btn-fill: color-mix(in srgb, var(--basalt-success) 58%, var(--basalt-copy));
	--btn-fill-deep: color-mix(in srgb, var(--basalt-success) 50%, var(--basalt-copy));
	--btn-text: color-mix(in srgb, var(--basalt-success) 52%, var(--basalt-copy));
	--btn-edge: color-mix(in srgb, var(--basalt-success) 70%, transparent);
}

:is(.btn-danger, .btn-outline-danger) {
	--btn-ink: var(--basalt-plane);
	--btn-fill: color-mix(in srgb, var(--basalt-danger) 76%, var(--basalt-copy));
	--btn-fill-deep: color-mix(in srgb, var(--basalt-danger) 66%, var(--basalt-copy));
	--btn-text: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
	--btn-edge: color-mix(in srgb, var(--basalt-danger) 70%, transparent);
}

:is(.btn-warning, .btn-outline-warning) {
	--btn-ink: var(--basalt-plane);
	--btn-fill: color-mix(in srgb, var(--basalt-warning) 50%, var(--basalt-copy));
	--btn-fill-deep: color-mix(in srgb, var(--basalt-warning) 42%, var(--basalt-copy));
	--btn-text: color-mix(in srgb, var(--basalt-warning) 48%, var(--basalt-copy));
	--btn-edge: color-mix(in srgb, var(--basalt-warning) 80%, transparent);
}

:is(.btn-info, .btn-outline-info) {
	--btn-ink: var(--basalt-plane);
	--btn-fill: color-mix(in srgb, var(--basalt-flare) 50%, var(--basalt-copy));
	--btn-fill-deep: color-mix(in srgb, var(--basalt-flare) 42%, var(--basalt-copy));
	--btn-text: color-mix(in srgb, var(--basalt-flare) 46%, var(--basalt-copy));
	--btn-edge: color-mix(in srgb, var(--basalt-flare) 80%, transparent);
}

/* Dark mixes nothing: it is the text color, pressing to body copy. */
:is(.btn-dark, .btn-outline-dark) {
	--btn-ink: var(--basalt-plane);
	--btn-fill: var(--basalt-copy);
	--btn-fill-deep: var(--basalt-copy-body);
	--btn-text: var(--basalt-copy);
	--btn-edge: var(--basalt-copy);
}

/* Secondary rests on the raised surface tinted faintly by the primary, so
   it moves with the palette while staying second to it. Hover and press
   label in the text color; primary-deep missed 4.5:1 on the dark fills. */
.btn-secondary {
	--bs-btn-color: color-mix(in srgb, var(--basalt-hue) 34%, var(--basalt-copy-body));
	--bs-btn-bg: color-mix(in srgb, var(--basalt-hue) 9%, var(--basalt-plane-alt));
	--bs-btn-border-color: color-mix(in srgb, var(--basalt-hue) 26%, var(--basalt-edge-strong));
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-bg: color-mix(in srgb, var(--basalt-hue) 16%, var(--basalt-plane-alt));
	--bs-btn-hover-border-color: var(--basalt-hue-border);
	--bs-btn-active-color: var(--basalt-copy);
	--bs-btn-active-bg: color-mix(in srgb, var(--basalt-hue) 22%, var(--basalt-plane-alt));
	--bs-btn-active-border-color: var(--basalt-hue-border);
}

/* Its outline twin turns brand-colored when pressed or checked, since in
   a toggle group that state is the selection. */
.btn-outline-secondary {
	--bs-btn-color: color-mix(in srgb, var(--basalt-hue) 34%, var(--basalt-copy-body));
	--bs-btn-border-color: color-mix(in srgb, var(--basalt-hue) 30%, var(--basalt-edge-strong));
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-bg: color-mix(in srgb, var(--basalt-hue) 10%, var(--basalt-plane-alt));
	--bs-btn-hover-border-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
	--bs-btn-active-color: var(--basalt-on-hue);
	--bs-btn-active-bg: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--bs-btn-active-border-color: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	/* An open dropdown has chosen nothing yet, so its toggle stays calm. */
}
.btn-outline-secondary.show {
	border-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
	color: var(--basalt-copy);
	background-color: var(--basalt-wash);
}

/* Light and outline light share every phase; only light gets a fill. */
.btn-light,
.btn-outline-light {
	--bs-btn-color: var(--basalt-copy-body);
	--bs-btn-border-color: var(--basalt-edge);
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-bg: var(--basalt-wash);
	--bs-btn-hover-border-color: var(--basalt-edge-strong);
	--bs-btn-active-color: var(--basalt-copy);
	--bs-btn-active-bg: var(--basalt-wash);
	--bs-btn-active-border-color: var(--basalt-edge-strong);
}

.btn-light {
	--bs-btn-bg: var(--basalt-plane-alt);
}

/* A link button behaves as a link: primary text eased toward the body
   color so it reads on the page and on tints, with no fill or border in
   any phase. */
.btn-link {
	--bs-btn-color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
	--bs-btn-bg: transparent;
	--bs-btn-border-color: transparent;
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-bg: transparent;
	--bs-btn-hover-border-color: transparent;
	--bs-btn-active-color: var(--basalt-copy);
	--bs-btn-active-bg: transparent;
	--bs-btn-active-border-color: transparent;
	--bs-btn-disabled-bg: transparent;
	--bs-btn-disabled-border-color: transparent;
	font-weight: 600;
	text-decoration-color: color-mix(in srgb, var(--basalt-hue) 45%, transparent);
	text-underline-offset: 0.2em;
}

.btn-group > .btn {
	font-weight: 600;
}

/* Exports and data downloads (.btn-export) make a file nobody opens on a
   phone, so they step aside below 576px, along with the dropdown or group
   an export toggle opens. */
@media (max-width: 575.98px) {
	.btn.btn-export,
	.dropdown:has(> .btn-export),
	.btn-group:has(> .btn-export) {
		display: none;
	}
}
/* Down a vertical group, a button that leads with an icon lines up at the
   start, and each leading icon fills a 1em cell so mixed glyph widths
   still form one column. Icon-only buttons are named with aria-label and
   stay centered. */
.btn-group-vertical > .btn:has(> .bi:first-child):not([aria-label]) {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	text-align: start;
}
.btn-group-vertical > .btn > .bi:first-child {
	display: inline-block;
	flex-shrink: 0;
	width: 1em;
	text-align: center;
}

/* Gradient buttons carry the single lead action of a view, such as a hero
   or an upgrade prompt. The plain, warm and cool sweeps each join two
   palette colors darkened toward the text color until the on-primary label
   clears 4.5:1 end to end, in every palette and mode. Hover and focus
   shift the sweep sideways instead of lightening it. */
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool) {
	--btn-grad-a: color-mix(in srgb, var(--basalt-hue) 84%, var(--basalt-copy));
	--btn-grad-b: color-mix(in srgb, var(--basalt-series-2) 50%, var(--basalt-copy));
	--bs-btn-color: var(--basalt-on-hue);
	--bs-btn-bg: var(--btn-grad-a);
	--bs-btn-border-color: transparent;
	--bs-btn-hover-color: var(--basalt-on-hue);
	--bs-btn-hover-bg: var(--btn-grad-b);
	--bs-btn-hover-border-color: transparent;
	--bs-btn-active-color: var(--basalt-on-hue);
	--bs-btn-active-bg: var(--btn-grad-b);
	--bs-btn-active-border-color: transparent;
	font-weight: 600;
	background-image: linear-gradient(120deg, var(--btn-grad-a) 0%, var(--btn-grad-b) 50%, var(--btn-grad-a) 100%);
	background-size: 200% 100%;
	background-position: 0 0;
}
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool):is(:hover, :focus-visible, :active, .active) {
	background-position: 100% 0;
}
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool):is(:active, .active) {
	box-shadow: inset 0 2px 6px color-mix(in srgb, var(--basalt-copy) 24%, transparent);
}
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool) {
	/* With gradients switched off it is a flat button in its first color. */
}
:root[data-basalt-gradients="off"] :is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool) {
	background-image: none;
}
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool) {
	/* The sideways shift is motion, so it animates only when that is welcome. */
}
@media (prefers-reduced-motion: no-preference) {
	:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool) {
		transition:
			color 170ms ease-in-out,
			background-position 450ms ease,
			border-color 170ms ease-in-out,
			box-shadow 170ms ease-in-out;
	}
}

.btn-gradient-warm {
	--btn-grad-a: color-mix(in srgb, var(--basalt-series-5) 46%, var(--basalt-copy));
	--btn-grad-b: color-mix(in srgb, var(--basalt-series-6) 50%, var(--basalt-copy));
}

.btn-gradient-cool {
	--btn-grad-a: color-mix(in srgb, var(--basalt-series-3) 48%, var(--basalt-copy));
	--btn-grad-b: color-mix(in srgb, var(--basalt-series-4) 50%, var(--basalt-copy));
}

/* The outline sweep is a gradient border round a surface fill with a
   primary label; the fill picks up a touch of primary under hover and
   a little more when pressed. */
.btn-gradient-outline {
	--btn-grad-a: var(--basalt-hue);
	--btn-grad-b: var(--basalt-series-2);
	--btn-grad-fill: var(--basalt-plane);
	--bs-btn-color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
	--bs-btn-border-color: transparent;
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-border-color: transparent;
	--bs-btn-active-color: var(--basalt-copy);
	--bs-btn-active-border-color: transparent;
	border: 1.5px solid transparent;
	font-weight: 600;
	background:
		linear-gradient(var(--btn-grad-fill), var(--btn-grad-fill)) padding-box,
		linear-gradient(120deg, var(--btn-grad-a), var(--btn-grad-b)) border-box;
}
.btn-gradient-outline:is(:hover, :focus-visible) {
	--btn-grad-fill: color-mix(in srgb, var(--basalt-hue) 8%, var(--basalt-plane));
}
.btn-gradient-outline:is(:active, .active) {
	--btn-grad-fill: color-mix(in srgb, var(--basalt-hue) 14%, var(--basalt-plane));
}
.btn-gradient-outline {
	/* Gradients off collapses the border sweep to its first color. */
}
:root[data-basalt-gradients="off"] .btn-gradient-outline {
	--btn-grad-b: var(--btn-grad-a);
}

/* A disabled sweep of either kind gives up its gradient and takes the
   same quiet disabled look as every other button. */
:is(.btn-gradient, .btn-gradient-warm, .btn-gradient-cool, .btn-gradient-outline):is(:disabled, .disabled) {
	border-color: var(--bs-btn-disabled-border-color);
	background: var(--bs-btn-disabled-bg);
	box-shadow: none;
}

/* A few Bootstrap pieces keep light-theme colors of their own after the dark
   tokens land: inputs sit on the wash with dark-theme copy, and table text
   and trail separators pick up the dark copy tones. */
[data-bs-theme="dark"] .form-control {
	border-color: var(--basalt-edge);
	color: var(--basalt-copy);
	background-color: var(--basalt-wash);
}
[data-bs-theme="dark"] .form-control::placeholder {
	color: var(--basalt-copy-muted);
}

[data-bs-theme="dark"] .table {
	color: var(--basalt-copy);
}

[data-bs-theme="dark"] .breadcrumb-item + .breadcrumb-item::before {
	color: var(--basalt-copy-muted);
}

/* The appearance panel that assets/basalt/js/theme-picker.js drops into the page:
   palette chips in a grid, then segmented switches. It is fixed to the
   viewport instead of the header, which lets it clear the sticky chrome on
   every page without any page having to provide a positioning context. */
.basalt-appearance {
	position: fixed;
	top: calc(var(--basalt-header-h) + 8px);
	right: 16px;
	z-index: 1055;
	width: 320px;
	max-width: calc(100vw - 32px);
	max-height: calc(100vh - var(--basalt-header-h) - 24px);
	padding: 14px;
	border-radius: 16px;
	border: 1px solid var(--basalt-edge);
	overflow-y: auto;
	background: var(--basalt-plane);
	box-shadow: var(--basalt-card-shadow);
}
.basalt-appearance[hidden] {
	display: none;
}
.basalt-appearance {
	/* On a phone the panel spans the screen, inset a little from both edges. */
}
@media (max-width: 480px) {
	.basalt-appearance {
		right: 8px;
		left: 8px;
		width: auto;
	}
}

/* Title on the left, close button on the right. */
.basalt-appearance-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 12px;
}

.basalt-appearance-title {
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-appearance-close {
	padding: 2px;
	border: 0;
	border-radius: 6px;
	line-height: 1;
	color: var(--basalt-copy-muted);
	background: transparent;
	cursor: pointer;
}
.basalt-appearance-close:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}

/* Each section opens with a small uppercase caption. */
.basalt-appearance-section + .basalt-appearance-section {
	margin-top: 14px;
}

.basalt-appearance-label {
	display: block;
	margin-bottom: 7px;
	font-size: 0.7rem;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--basalt-copy-faint);
}

/* Palette chips sit three to a row, two on a phone. */
.basalt-appearance-grid {
	display: grid;
	gap: 10px 6px;
	grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* A chip is the palette's color dot over its name. The dot is the whole
   mark: no frame around it, and the choice gets a ring with a gap. */
.basalt-appearance-chip {
	display: flex;
	gap: 6px;
	flex-direction: column;
	align-items: center;
	min-width: 0;
	padding: 4px;
	border: 0;
	border-radius: 10px;
	text-align: center;
	color: var(--basalt-copy-muted);
	background: transparent;
	cursor: pointer;
}
.basalt-appearance-chip:hover {
	color: var(--basalt-copy);
}
.basalt-appearance-chip:focus-visible {
	outline: 0;
}
.basalt-appearance-chip:focus-visible .basalt-appearance-sw {
	outline-color: var(--basalt-hue);
	outline-style: dashed;
}
.basalt-appearance-chip[aria-checked="true"] {
	color: var(--basalt-copy);
}
.basalt-appearance-chip[aria-checked="true"] .basalt-appearance-sw {
	outline-color: var(--basalt-hue);
}

.basalt-appearance-sw {
	display: flex;
	flex: none;
	width: 2rem;
	aspect-ratio: 1;
	border-radius: 50%;
	overflow: hidden;
	outline: 2px solid transparent;
	outline-offset: 2px;
	box-shadow: inset 0 0 0 1px var(--basalt-edge);
	transition: outline-color 0.15s ease;
}
.basalt-appearance-sw i {
	flex: 1;
}

.basalt-appearance-name {
	font-size: 0.75rem;
	font-weight: 600;
	line-height: 1.2;
	overflow-wrap: anywhere;
}

.basalt-appearance-note {
	font-weight: 500;
	color: var(--basalt-copy-muted);
}

@media (prefers-reduced-motion: reduce) {
	.basalt-appearance-sw {
		transition: none;
	}
}
/* Segmented switches: a soft track as wide as its options, each option as
   wide as its words; the chosen option sits on it as a raised pill. */
.basalt-appearance-seg {
	display: inline-flex;
	max-width: 100%;
	gap: 2px;
	padding: 3px;
	border-radius: 12px;
	background: var(--basalt-wash);
	box-shadow: inset 0 0 0 1px var(--basalt-edge);
}
.basalt-appearance-seg button {
	display: inline-flex;
	gap: 5px;
	flex: none;
	align-items: center;
	justify-content: center;
	padding: 6px 12px;
	border: 0;
	border-radius: 9px;
	font-size: 0.8rem;
	font-weight: 500;
	white-space: nowrap;
	color: var(--basalt-copy-muted);
	background: transparent;
	cursor: pointer;
	transition:
		color 150ms ease,
		background-color 150ms ease,
		box-shadow 150ms ease;
}
.basalt-appearance-seg button:hover {
	color: var(--basalt-copy);
}
.basalt-appearance-seg button:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}
.basalt-appearance-seg button[aria-pressed="true"] {
	font-weight: 700;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--basalt-copy) 12%, transparent),
		0 0 0 1px var(--basalt-edge);
}
[data-bs-theme="dark"] .basalt-appearance-seg button[aria-pressed="true"] {
	background: color-mix(in srgb, var(--basalt-copy) 12%, var(--basalt-plane));
	box-shadow: 0 1px 3px color-mix(in srgb, var(--basalt-canvas) 70%, transparent);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-appearance-seg button {
		transition: none;
	}
}

/* Reusable interface pieces that are not a Bootstrap component of their own:
   the dialog layout (header with icon, body, footer, and a variant with a
   live preview beside the form), the press-and-hold button, the circular
   progress meter and the record status pill. They are shown on
   modals.html, progress.html and badges.html; the press-and-hold
   timing is driven from basalt.js through [data-basalt-hold]. */
/* Motion-sensitive visitors get the end state without the tween. */
/* Dialog layout. The header pairs a tinted icon tile with a title and one
   sentence on what the dialog is for, and stands in for .modal-header in any
   .modal-content. Rows of fields in the body are spaced well apart, and
   the footer right-aligns its buttons and wraps them when space runs out. */
.basalt-dialog-head {
	display: flex;
	gap: 0.875rem;
	align-items: flex-start;
	padding: 1.35rem 1.5rem 0.75rem;
}
.basalt-dialog-head .btn-close {
	flex-shrink: 0;
	margin-left: auto;
}
.basalt-dialog-head-icon {
	--basalt-dialog-tone: var(--basalt-hue);
	display: inline-flex;
	flex-shrink: 0;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: 14px;
	font-size: 1.2rem;
	color: var(--basalt-dialog-tone);
	background: color-mix(in srgb, var(--basalt-dialog-tone) 12%, transparent);
}
.basalt-dialog-head-icon-danger {
	--basalt-dialog-tone: var(--basalt-danger);
}
.basalt-dialog-head-icon-success {
	--basalt-dialog-tone: var(--basalt-success);
}
.basalt-dialog-head-title {
	margin: 0 0 0.1rem;
	font-size: 1.1rem;
	font-weight: 800;
	letter-spacing: -0.01em;
}
.basalt-dialog-head-sub {
	margin: 0;
	font-size: 0.875rem;
	text-wrap: pretty;
	color: var(--basalt-copy-muted);
}

.basalt-dialog-body {
	padding: 0.5rem 1.5rem 1.5rem;
}
.basalt-dialog-body > .row {
	--bs-gutter-y: 1.25rem;
}

/* When the dialog scrolls, only its body moves; the header and the footer
   buttons hold their place, which keeps them reachable on short screens. */
.modal-dialog-scrollable .basalt-dialog-body {
	min-height: 0;
	overflow-y: auto;
}
.modal-dialog-scrollable .basalt-dialog-head,
.modal-dialog-scrollable .basalt-dialog-foot {
	flex-shrink: 0;
}

.basalt-dialog-foot {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	justify-content: flex-end;
	padding: 1.1rem 1.5rem 1.35rem;
	border-top: 1px solid var(--basalt-edge);
}

/* The preview variant sets the form and a preview panel side by side. It
   measures the dialog rather than the screen, so it drops to one column
   whenever the dialog itself gets narrow, tablets and phones included. */
.basalt-dialog-split {
	container: basalt-dialog/inline-size;
}
.basalt-dialog-split-body {
	display: grid;
	gap: 1.5rem;
	grid-template-columns: minmax(0, 1fr) 260px;
}
@container basalt-dialog (max-width: 640px) {
	.basalt-dialog-split-body {
		grid-template-columns: minmax(0, 1fr);
	}
}

.basalt-preview-panel {
	align-self: start;
	padding: 1rem;
	border-radius: 16px;
	background: var(--basalt-canvas);
}
.basalt-preview-panel-label {
	display: block;
	margin-bottom: 0.6rem;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* Press and hold guards a destructive action: it fires only after the button
   has been held down, by pointer or with Enter or Space, for data-hold-ms
   milliseconds (1500 when the attribute is absent). A fill sweeps across
   the button while it is held. */
.basalt-hold {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	user-select: none;
	-webkit-user-select: none;
	touch-action: none;
}
.basalt-hold::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	transform: scaleX(var(--basalt-hold, 0));
	transform-origin: left center;
	/* A solid button gets darker under the fill rather than paler, so its
       label never loses contrast mid-press. Outline and quiet buttons take a
       faint wash of their own label color. */
	background: color-mix(in srgb, var(--basalt-copy) 26%, transparent);
}
.basalt-hold:is([class*="btn-outline-"], .btn-secondary, .btn-light)::before {
	background: color-mix(in srgb, currentColor 12%, transparent);
}
.basalt-hold.is-done::before {
	transform: scaleX(1);
}
.basalt-hold {
	/* An outline button keeps its label color while it is held and after. */
}
.basalt-hold[class*="btn-outline-"]:is(.is-holding, .is-done) {
	border-color: var(--bs-btn-border-color);
	color: var(--bs-btn-color);
	background-color: var(--basalt-plane);
}
.basalt-hold {
	/* When the button carries per-moment labels, they overlap in a single grid
      cell, so its width is set once by the longest of them. */
}
.basalt-hold:has(.basalt-hold-state) {
	display: inline-grid;
}
.basalt-hold {
	/* With reduced motion the hold still lasts as long; the fill just shows
      at half strength instead of sweeping. */
}
@media (prefers-reduced-motion: reduce) {
	.basalt-hold.is-holding::before {
		transform: scaleX(1);
		opacity: 0.5;
	}
}

.basalt-hold-state {
	display: inline-flex;
	gap: 0.5rem;
	grid-area: 1/1;
	align-items: center;
	justify-content: center;
	white-space: nowrap;
	transition:
		opacity 170ms ease,
		visibility 170ms;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-hold-state {
		transition: none;
	}
}

/* The idle label shows at rest, the busy one while the press lasts, the done
   one once the action has fired. */
.basalt-hold.is-done .basalt-hold-idle,
.basalt-hold.is-done .basalt-hold-busy,
.basalt-hold.is-holding .basalt-hold-idle,
.basalt-hold-busy,
.basalt-hold-done {
	visibility: hidden;
	opacity: 0;
}

.basalt-hold.is-done .basalt-hold-done,
.basalt-hold.is-holding:not(.is-done) .basalt-hold-busy {
	visibility: visible;
	opacity: 1;
}

/* The progress ring reads --value from 0 to 100 and draws that share of the
   circle, starting at twelve o'clock. Its center is ordinary text, free to
   say whatever the ring stands for. --size and --thickness scale it, and
   the small size leaves the caption out. */
.basalt-ring {
	--value: 0;
	--size: 120px;
	--thickness: 10px;
	--tone: var(--basalt-hue);
	position: relative;
	display: inline-grid;
	place-items: center;
	width: var(--size);
	height: var(--size);
}
.basalt-ring svg {
	position: absolute;
	inset: 0;
	transform: rotate(-90deg);
	width: 100%;
	height: 100%;
}
.basalt-ring-track,
.basalt-ring-bar {
	fill: none;
	stroke-width: var(--thickness);
}
.basalt-ring-track {
	stroke: color-mix(in srgb, var(--basalt-copy) 10%, transparent);
}
.basalt-ring-bar {
	stroke: var(--tone);
	stroke-linecap: round;
	stroke-dasharray: 100 100;
	stroke-dashoffset: calc(100 - var(--value));
	transition: stroke-dashoffset 500ms cubic-bezier(0.2, 0.8, 0.2, 1);
	animation: basalt-ring-draw 900ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-ring-bar {
		transition: none;
		animation: none;
	}
}
.basalt-ring-label {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	line-height: 1.1;
	text-align: center;
}
.basalt-ring-value {
	font-size: calc(var(--size) * 0.24);
	font-weight: 800;
	letter-spacing: -0.02em;
	color: var(--basalt-copy);
}
.basalt-ring-caption {
	font-size: 0.71rem;
	color: var(--basalt-copy-muted);
}
.basalt-ring-success {
	--tone: var(--basalt-success);
}
.basalt-ring-warning {
	--tone: var(--basalt-warning);
}
.basalt-ring-danger {
	--tone: var(--basalt-danger);
}
.basalt-ring-sm {
	--size: 72px;
	--thickness: 8px;
}
.basalt-ring-sm .basalt-ring-caption {
	display: none;
}

@keyframes basalt-ring-draw {
	from {
		stroke-dashoffset: 100;
	}
}
/* A status pill marks where a record stands (paid, waiting on you, answered,
   overdue). It is a soft tint of one tone, optionally led by an icon or a
   dot, and a live dot breathes. The text is pulled hard toward the copy
   color, because success and warning are pale and the type is small. */
.basalt-status {
	--stp-tone: var(--basalt-copy-muted);
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	padding: 0.2rem 0.6rem;
	border-radius: 999px;
	font-size: 0.75rem;
	font-weight: 700;
	line-height: 1.4;
	white-space: nowrap;
	color: color-mix(in srgb, var(--stp-tone) 48%, var(--basalt-copy));
	background: color-mix(in srgb, var(--stp-tone) 14%, transparent);
}
.basalt-status .bi {
	font-size: 0.85em;
}
.basalt-status-dot::before {
	content: "";
	width: 0.4rem;
	height: 0.4rem;
	border-radius: 50%;
	background: var(--stp-tone);
}
.basalt-status-live::before {
	animation: basalt-status-pulse 1.8s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-status-live::before {
		animation: none;
	}
}
.basalt-status-info {
	--stp-tone: var(--basalt-info);
}
.basalt-status-success {
	--stp-tone: var(--basalt-success);
}
.basalt-status-warning {
	--stp-tone: var(--basalt-warning);
}
.basalt-status-danger {
	--stp-tone: var(--basalt-danger);
}
.basalt-status-primary {
	--stp-tone: var(--basalt-hue);
}

@keyframes basalt-status-pulse {
	50% {
		opacity: 0.35;
	}
}
/**
 * The page header card, .basalt-hero, and its quieter sibling .basalt-pagehead.
 *
 * A hero opens a page with up to four optional pieces: an icon, the page
 * name with a sentence about it, the page's buttons, and a short run of
 * headline numbers. One modifier class chooses the look:
 *
 *   .basalt-hero-ink     deep primary panel with light text
 *   .basalt-hero-glow    surface card lit by a palette glow along the top
 *   .basalt-hero-aurora  text on the left, a drifting palette panel on the right
 *   .basalt-hero-tint    washed in the palette, numbers on a small white card
 *   .basalt-hero-spot    plain card with a light that trails the pointer
 *   .basalt-hero-detail  no card at all: back link, record name, one line
 *
 * .basalt-hero-compact can join any card look on list, table and log pages
 * so the data starts higher. headers.html shows every combination;
 * basalt.js drives the spotlight through [data-basalt-hero-spot].
 *
 *   <header class="basalt-hero basalt-hero-tint">
 *     <div class="basalt-hero-body">
 *       <span class="basalt-hero-icon" aria-hidden="true"><i class="bi bi-wallet2"></i></span>
 *       <h1 class="basalt-hero-title">Payouts</h1>
 *       <p class="basalt-hero-desc">...</p>
 *     </div>
 *     <div class="basalt-hero-actions">...</div>
 *     <dl class="basalt-hero-figures">
 *       <div class="basalt-hero-figure">
 *         <dt class="basalt-hero-label">settled</dt>
 *         <dd class="basalt-hero-value">$12.6k</dd>
 *       </div>
 *     </dl>
 *   </header>
 *
 * The aurora look puts its figures inside <div class="basalt-hero-aside">;
 * the detail look starts its body with <a class="basalt-hero-back">.
 * Turning gradients off flattens every look, and reduced motion stills it.
 */
/* Applies the nested rules at and below the given width. */
/* Applies the nested rules when the appearance panel has gradients off. */
/* Applies the nested rules for visitors who ask for less motion. */
/* Three blend colors feed the aurora panel, the glow and the tint wash.
   Every palette starts from its first chart color; the second and third
   default to series 3 and 5, and the palettes listed in the map pick a
   pair that sits better beside the first. Mono has no third hue of its
   own, so its third color is a mix of the first two. */
:root {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-3);
	--basalt-hero-g3: var(--basalt-series-5);
}

:root[data-basalt-palette="tide"] {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-7);
	--basalt-hero-g3: var(--basalt-series-4);
}

:root[data-basalt-palette="verdant"] {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-2);
	--basalt-hero-g3: var(--basalt-series-8);
}

:root[data-basalt-palette="mono"] {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-7);
	--basalt-hero-g3: color-mix(in srgb, var(--basalt-series-1) 45%, var(--basalt-series-7));
}

:root[data-basalt-palette="electric"],
:root[data-basalt-palette="pastelpop"] {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-7);
	--basalt-hero-g3: var(--basalt-series-2);
}

:root[data-basalt-palette="jewel"] {
	--basalt-hero-g1: var(--basalt-series-1);
	--basalt-hero-g2: var(--basalt-series-2);
	--basalt-hero-g3: var(--basalt-series-7);
}

/* The shared shell: a two-column grid with the text and buttons on top
   and the figures across the bottom. */
.basalt-hero {
	--basalt-hero-fg: var(--basalt-copy);
	--basalt-hero-muted: color-mix(in srgb, var(--basalt-copy-muted) 78%, var(--basalt-copy));
	--basalt-hero-py: 1.75rem;
	--basalt-hero-px: 2rem;
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	grid-template-areas: "body actions" "figures figures";
	isolation: isolate;
	padding: var(--basalt-hero-py) var(--basalt-hero-px);
	border: 1px solid var(--basalt-edge);
	border-radius: 20px;
	overflow: hidden;
	color: var(--basalt-hero-fg);
	background-color: var(--basalt-plane);
	/* An open menu inside the header has to overlap the cards below it. */
}
.basalt-hero:has(.dropdown-menu.show) {
	z-index: 1000;
}

.basalt-hero-body {
	grid-area: body;
	min-width: 0;
}

.basalt-hero-actions {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	grid-area: actions;
	align-self: start;
	align-items: center;
	margin-left: 1.5rem;
}

.basalt-hero-icon {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	margin-bottom: 0.75rem;
	border-radius: 12px;
	font-size: 1.2rem;
}

.basalt-hero-title {
	margin: 0;
	font-size: clamp(1.45rem, 1.05rem + 1.1vw, 1.85rem);
	font-weight: 800;
	line-height: 1.1;
	letter-spacing: -0.025em;
	color: inherit;
}

.basalt-hero-desc {
	max-width: 58ch;
	margin: 0.4rem 0 0;
	font-size: 0.95rem;
	line-height: 1.5;
	color: var(--basalt-hero-muted);
}

.basalt-hero-figures {
	display: flex;
	gap: 0.75rem 2.25rem;
	flex-wrap: wrap;
	grid-area: figures;
	margin: 1.25rem 0 0;
}

/* Screen readers meet the label first; on screen it sits under the number. */
.basalt-hero-figure {
	display: flex;
	flex-direction: column-reverse;
}

.basalt-hero-value {
	margin: 0;
	font-size: 1.3rem;
	font-weight: 750;
	line-height: 1;
	letter-spacing: -0.01em;
	color: inherit;
}

/* The markup keeps labels lower case; capitalizing them is a display choice. */
.basalt-hero-label {
	margin-top: 0.3rem;
	font-size: 0.75rem;
	font-weight: 400;
	text-transform: capitalize;
	white-space: nowrap;
	color: var(--basalt-hero-muted);
}

/* Ink fills the card with a deep primary. Its panel color lives in
   --basalt-hero-ink so the light button can borrow it for its label, and
   the figures are split by thin vertical rules. */
.basalt-hero-ink {
	--basalt-hero-ink: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	--basalt-hero-fg: var(--basalt-plane);
	--basalt-hero-muted: color-mix(in srgb, var(--basalt-hero-fg) 86%, transparent);
	--basalt-hero-line: color-mix(in srgb, var(--basalt-hero-fg) 18%, transparent);
	border-color: transparent;
	background-color: var(--basalt-hero-ink);
}
[data-bs-theme="dark"] .basalt-hero-ink {
	--basalt-hero-ink: color-mix(in srgb, var(--basalt-hue) 32%, var(--basalt-plane));
	--basalt-hero-fg: var(--basalt-copy);
}
.basalt-hero-ink::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: repeating-linear-gradient(
		135deg,
		color-mix(in srgb, var(--basalt-hero-fg) 5%, transparent) 0 1px,
		transparent 1px 14px
	);
	-webkit-mask-image: linear-gradient(90deg, transparent 40%, currentColor);
	mask-image: linear-gradient(90deg, transparent 40%, currentColor);
}
:root[data-basalt-gradients="off"] .basalt-hero-ink::before {
	content: none;
}
.basalt-hero-ink .basalt-hero-icon {
	width: 2.75rem;
	height: 2.75rem;
	border: 1px solid color-mix(in srgb, var(--basalt-hero-fg) 22%, transparent);
	border-radius: 14px;
	background: color-mix(in srgb, var(--basalt-hero-fg) 12%, transparent);
}
.basalt-hero-ink .basalt-hero-figures {
	gap: 0.75rem 0;
	padding-top: 0.9rem;
	border-top: 1px solid var(--basalt-hero-line);
}
.basalt-hero-ink .basalt-hero-figure {
	margin-right: 2rem;
	padding-right: 2rem;
	border-right: 1px solid var(--basalt-hero-line);
}
.basalt-hero-ink .basalt-hero-figure:last-child {
	margin-right: 0;
	padding-right: 0;
	border-right: 0;
}
.basalt-hero-ink .btn-light {
	--bs-btn-color: var(--basalt-hero-ink);
	--bs-btn-bg: var(--basalt-hero-fg);
	--bs-btn-border-color: var(--basalt-hero-fg);
	--bs-btn-hover-color: var(--basalt-hero-ink);
	--bs-btn-hover-bg: color-mix(in srgb, var(--basalt-hero-fg) 88%, var(--basalt-hero-ink));
	--bs-btn-hover-border-color: transparent;
	--bs-btn-active-color: var(--basalt-hero-ink);
	--bs-btn-active-bg: color-mix(in srgb, var(--basalt-hero-fg) 80%, var(--basalt-hero-ink));
	--bs-btn-active-border-color: transparent;
}
.basalt-hero-ink .btn-outline-light {
	--bs-btn-color: var(--basalt-hero-fg);
	--bs-btn-border-color: color-mix(in srgb, var(--basalt-hero-fg) 40%, transparent);
	--bs-btn-hover-color: var(--basalt-hero-fg);
	--bs-btn-hover-bg: color-mix(in srgb, var(--basalt-hero-fg) 10%, transparent);
	--bs-btn-hover-border-color: color-mix(in srgb, var(--basalt-hero-fg) 60%, transparent);
	--bs-btn-active-color: var(--basalt-hero-fg);
	--bs-btn-active-bg: color-mix(in srgb, var(--basalt-hero-fg) 16%, transparent);
	--bs-btn-active-border-color: color-mix(in srgb, var(--basalt-hero-fg) 60%, transparent);
}
@media (max-width: 767.98px) {
	.basalt-hero-ink .basalt-hero-figure {
		margin-right: 1.25rem;
		padding-right: 1.25rem;
	}
}

/* Glow keeps the ordinary card and lets a blurred palette light spill in
   over the top edge. The icon shares a row with the title, and a dashed
   rule separates the figures and buttons underneath. */
.basalt-hero-glow {
	--basalt-hero-py: 1.6rem;
	grid-template-areas: "body body" "figures actions";
	background-color: var(--basalt-plane);
}
.basalt-hero-glow::before {
	content: "";
	position: absolute;
	top: -120px;
	right: 10%;
	left: 10%;
	z-index: -1;
	height: 200px;
	background: radial-gradient(closest-side, color-mix(in srgb, var(--basalt-hero-g1) 22%, transparent), transparent);
	filter: blur(10px);
}
:root[data-basalt-gradients="off"] .basalt-hero-glow::before {
	content: none;
}
:root[data-basalt-gradients="off"] .basalt-hero-glow .basalt-hero-icon {
	background: var(--basalt-hue);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-hero-glow {
		animation: none;
	}
}
.basalt-hero-glow .basalt-hero-body {
	display: grid;
	column-gap: 1.1rem;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: center;
}
.basalt-hero-glow .basalt-hero-title,
.basalt-hero-glow .basalt-hero-desc {
	grid-column: 1/-1;
}
.basalt-hero-glow .basalt-hero-icon + .basalt-hero-title {
	grid-column: 2;
}
.basalt-hero-glow .basalt-hero-icon {
	width: 2.85rem;
	height: 2.85rem;
	margin: 0;
	border-radius: 14px;
	color: var(--basalt-on-hue);
	background: linear-gradient(135deg, var(--basalt-hero-g1), var(--basalt-hero-g2));
}
.basalt-hero-glow .basalt-hero-desc {
	margin-top: 0.6rem;
}
.basalt-hero-glow .basalt-hero-figures,
.basalt-hero-glow .basalt-hero-actions {
	margin-top: 1.2rem;
	padding-top: 0.9rem;
	border-top: 1px dashed var(--basalt-edge-strong);
}
.basalt-hero-glow .basalt-hero-figures {
	gap: 1rem 2.25rem;
}
.basalt-hero-glow .basalt-hero-actions {
	align-self: stretch;
	align-items: center;
	justify-content: flex-end;
	margin-left: 0;
	padding-left: 1rem;
}
.basalt-hero-glow {
	/* With no figures beside them, the buttons take the full row from the left. */
}
.basalt-hero-glow:not(:has(> .basalt-hero-figures)) .basalt-hero-actions {
	grid-column: 1/-1;
	justify-content: flex-start;
	padding-left: 0;
}
@media (max-width: 767.98px) {
	.basalt-hero-glow .basalt-hero-actions,
	.basalt-hero-glow:not(:has(> .basalt-hero-figures)) .basalt-hero-actions {
		justify-content: flex-start;
		margin-top: 1.1rem;
		padding: 0;
		border-top: 0;
	}
	.basalt-hero-glow:not(:has(> .basalt-hero-figures)) .basalt-hero-actions {
		margin-top: 1.4rem;
	}
}

/* Aurora splits the card: the text on the left, and on the right a
   colored aside that runs to the card's edges, with two blurred palette
   blobs drifting behind the figures on their frosted tiles. */
.basalt-hero-aurora {
	--basalt-hero-py: 1.6rem;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas: "body" "actions";
}
.basalt-hero-aurora:has(> .basalt-hero-aside) {
	grid-template-columns: minmax(0, 1fr) minmax(260px, 38%);
	grid-template-rows: auto auto 1fr;
	grid-template-areas: "body aside" "actions aside" ". aside";
}
.basalt-hero-aurora .basalt-hero-icon {
	color: var(--basalt-hue);
	background: var(--basalt-hue-soft);
}
[data-bs-theme="dark"] .basalt-hero-aurora .basalt-hero-icon {
	color: color-mix(in srgb, var(--basalt-hue) 70%, var(--basalt-copy));
}
.basalt-hero-aurora .basalt-hero-actions {
	justify-self: start;
	margin: 1.1rem 0 0;
}
.basalt-hero-aurora .basalt-hero-figures {
	gap: 0.5rem;
	flex-direction: column;
	width: 100%;
	margin: 0;
}
.basalt-hero-aurora .basalt-hero-figure {
	gap: 1rem;
	flex-direction: row;
	align-items: baseline;
	justify-content: space-between;
	padding: 0.5rem 0.8rem;
	border-radius: 12px;
	background: color-mix(in srgb, var(--basalt-plane) 88%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
}
.basalt-hero-aurora .basalt-hero-value {
	font-size: 1.1rem;
	color: var(--basalt-copy);
}
.basalt-hero-aurora .basalt-hero-label {
	margin: 0;
	color: color-mix(in srgb, var(--basalt-copy-muted) 60%, var(--basalt-copy));
}

.basalt-hero-aside {
	position: relative;
	z-index: 0;
	display: flex;
	grid-area: aside;
	align-items: flex-end;
	margin: calc(var(--basalt-hero-py) * -1) calc(var(--basalt-hero-px) * -1) calc(var(--basalt-hero-py) * -1) 2rem;
	padding: 1.25rem;
	overflow: hidden;
	background-color: var(--basalt-hero-g1);
}
.basalt-hero-aside::before,
.basalt-hero-aside::after {
	content: "";
	position: absolute;
	z-index: -1;
	width: 140%;
	aspect-ratio: 1;
	border-radius: 50%;
	filter: blur(40px);
}
.basalt-hero-aside::before {
	top: -70%;
	left: -60%;
	background: var(--basalt-hero-g2);
	animation: basalt-hero-drift 14s ease-in-out infinite alternate;
}
.basalt-hero-aside::after {
	right: -70%;
	bottom: -80%;
	background: var(--basalt-hero-g3);
	opacity: 0.85;
	animation: basalt-hero-drift 18s ease-in-out infinite alternate-reverse;
}
.basalt-hero-aside {
	/* Flat mode shows the panel in the primary color with no blobs; reduced
      motion keeps the blobs but stops their drift. */
}
:root[data-basalt-gradients="off"] .basalt-hero-aside {
	background-color: var(--basalt-hue);
}
:root[data-basalt-gradients="off"] .basalt-hero-aside::before,
:root[data-basalt-gradients="off"] .basalt-hero-aside::after {
	content: none;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-hero-aside::before,
	.basalt-hero-aside::after {
		animation: none;
	}
}

@keyframes basalt-hero-drift {
	to {
		transform: translate(18%, 14%) scale(1.1);
	}
}
/* Below tablet width the aside drops under the text and bleeds to the
   card's sides and bottom instead. */
@media (max-width: 991.98px) {
	.basalt-hero-aurora:has(> .basalt-hero-aside) {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
		grid-template-areas: "body" "actions" "aside";
	}
	.basalt-hero-aside {
		margin: 1.4rem calc(var(--basalt-hero-px) * -1) calc(var(--basalt-hero-py) * -1);
	}
}
/* Tint washes the card in the three blend colors and stands the figures
   in a white ledger card on the right, which moves under the text once
   the screen narrows. */
.basalt-hero-tint {
	--basalt-hero-py: 1.6rem;
	grid-template-rows: auto 1fr;
	grid-template-areas: "body figures" "actions figures";
	background-color: color-mix(in srgb, var(--basalt-hero-g1) 11%, var(--basalt-plane));
	background-image: linear-gradient(
		120deg,
		color-mix(in srgb, var(--basalt-hero-g1) 13%, var(--basalt-plane)),
		color-mix(in srgb, var(--basalt-hero-g2) 9%, var(--basalt-plane)) 60%,
		color-mix(in srgb, var(--basalt-hero-g3) 10%, var(--basalt-plane))
	);
}
:root[data-basalt-gradients="off"] .basalt-hero-tint {
	background-color: var(--basalt-plane);
	background-image: none;
}
.basalt-hero-tint .basalt-hero-icon {
	border-radius: 50%;
	background: var(--basalt-plane);
	box-shadow: 0 6px 16px -8px color-mix(in srgb, var(--basalt-copy) 40%, transparent);
}
.basalt-hero-tint .basalt-hero-actions {
	align-self: start;
	justify-self: start;
	margin: 1rem 0 0;
}
.basalt-hero-tint .basalt-hero-figures {
	gap: 0;
	flex-wrap: nowrap;
	align-self: end;
	margin: 0 0 0 2.5rem;
	border-radius: 14px;
	background: var(--basalt-plane);
	box-shadow: 0 10px 28px -18px color-mix(in srgb, var(--basalt-copy) 45%, transparent);
}
.basalt-hero-tint .basalt-hero-figure {
	padding: 0.7rem 1.1rem;
}
.basalt-hero-tint .basalt-hero-figure + .basalt-hero-figure {
	border-left: 1px solid var(--basalt-edge);
}
@media (max-width: 1199.98px) {
	.basalt-hero-tint {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
		grid-template-areas: "body" "actions" "figures";
	}
	.basalt-hero-tint .basalt-hero-figures {
		justify-self: start;
		margin: 1.25rem 0 0;
	}
}
@media (max-width: 767.98px) {
	.basalt-hero-tint .basalt-hero-figures {
		flex-wrap: wrap;
	}
	.basalt-hero-tint .basalt-hero-figure {
		padding: 0.75rem 0.9rem;
	}
	.basalt-hero-tint .basalt-hero-value {
		font-size: 1.1rem;
	}
}

/* Spot keeps a plain card and paints a soft light where basalt.js puts
   --basalt-hero-x and --basalt-hero-y; with no pointer it rests near the
   top right corner. */
.basalt-hero-spot::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: radial-gradient(
		420px circle at var(--basalt-hero-x, 80%) var(--basalt-hero-y, 20%),
		color-mix(in srgb, var(--basalt-hero-g1) 16%, transparent),
		transparent 65%
	);
	pointer-events: none;
}
:root[data-basalt-gradients="off"] .basalt-hero-spot::before {
	content: none;
}
.basalt-hero-spot .basalt-hero-icon {
	border: 1px solid var(--basalt-edge-strong);
	background: var(--basalt-plane);
}
.basalt-hero-spot .basalt-hero-value {
	font-size: 1.4rem;
}
@media (max-width: 767.98px) {
	.basalt-hero-spot .basalt-hero-value {
		font-size: 1.1rem;
	}
}

/* Detail heads a page about a single record such as an order or a
   customer. It sits straight on the page with no card, its back link
   stands in for a breadcrumb, and a long record ID wraps instead of
   pushing past a phone's edge. */
.basalt-hero-detail {
	display: block;
	padding: 0;
	border: 0;
	border-radius: 0;
	overflow: visible;
	background: none;
}
.basalt-hero-detail .basalt-hero-title {
	font-size: clamp(1.4rem, 1.2rem + 0.5vw, 1.6rem);
	letter-spacing: -0.02em;
	overflow-wrap: anywhere;
}
.basalt-hero-detail .basalt-hero-desc {
	margin-top: 0.3rem;
	font-size: 0.9rem;
	line-height: 1.5;
}

/* The back link is a small pill in the accent's ink. The arrow shares
   the text's color, and hovering only deepens the tint and nudges the
   arrow toward where it goes. On the ink look it turns light. */
.basalt-hero-back {
	--basalt-back-ink: color-mix(in srgb, var(--basalt-hue) 70%, var(--basalt-copy));
	--basalt-back-tint: color-mix(in srgb, var(--basalt-hue) 10%, transparent);
	--basalt-back-tint-hover: color-mix(in srgb, var(--basalt-hue) 17%, transparent);
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	justify-self: start;
	align-self: flex-start;
	margin-bottom: 1.1rem;
	padding: 0.3rem 0.8rem 0.3rem 0.6rem;
	border-radius: 999px;
	font-size: 0.8rem;
	font-weight: 700;
	line-height: 1.4;
	text-decoration: none;
	color: var(--basalt-back-ink);
	background: var(--basalt-back-tint);
	transition: background-color 170ms ease;
}
.basalt-hero-back .bi {
	display: inline-block;
	transition: transform 170ms ease;
}
.basalt-hero-back:hover {
	color: var(--basalt-back-ink);
	background: var(--basalt-back-tint-hover);
}
.basalt-hero-back:hover .bi {
	transform: translateX(-3px);
}
.basalt-hero-back:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	box-shadow: none;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-hero-back {
		transition: none;
	}
	.basalt-hero-back .bi {
		transition: none;
	}
}

/* A detail header for a person or account: the avatar beside a block
   whose name and pills share the first row and whose line sits under
   them, so the avatar centers on the two. The block's last child holds
   the pills. On a phone the pills drop under the line again. */
.basalt-hero-who-text {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	column-gap: 0.85rem;
	align-items: center;
}
.basalt-hero-who-text > .basalt-hero-title {
	grid-row: 1;
	grid-column: 1;
}
.basalt-hero-who-text > .basalt-hero-desc {
	grid-row: 2;
	grid-column: 1/-1;
}
.basalt-hero-who-text > :last-child:not(.basalt-hero-desc) {
	grid-row: 1;
	grid-column: 2;
	margin-top: 0;
}
@media (max-width: 767.98px) {
	.basalt-hero-who-text {
		display: block;
	}
	.basalt-hero-who-text > :last-child:not(.basalt-hero-desc) {
		margin-top: 0.65rem;
	}
}

[data-bs-theme="dark"] .basalt-hero-back {
	--basalt-back-ink: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	--basalt-back-tint: color-mix(in srgb, var(--basalt-hue) 18%, transparent);
	--basalt-back-tint-hover: color-mix(in srgb, var(--basalt-hue) 26%, transparent);
}

.basalt-hero-ink .basalt-hero-back,
[data-bs-theme="dark"] .basalt-hero-ink .basalt-hero-back {
	--basalt-back-ink: var(--basalt-hero-fg);
	--basalt-back-tint: color-mix(in srgb, var(--basalt-hero-fg) 14%, transparent);
	--basalt-back-tint-hover: color-mix(in srgb, var(--basalt-hero-fg) 22%, transparent);
}

/* On a phone the shell stacks into one column. This has to follow every
   look above so it overrides their grids and padding, and glow then
   restacks itself so its figures come before the buttons. */
@media (max-width: 767.98px) {
	.basalt-hero {
		--basalt-hero-py: 1.25rem;
		--basalt-hero-px: 1.25rem;
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "body" "actions" "figures";
	}
	.basalt-hero-actions {
		margin: 1rem 0 0;
	}
	.basalt-hero-glow {
		grid-template-areas: "body" "figures" "actions";
	}
}
/* Compact trims the height and nothing else: the side padding and the
   icon stay full size. Everything shares one row, with the icon beside
   a one-line description, the figures as a slim strip and the buttons
   level with them. Under 1200px the figures wrap into chips below the
   text, and a phone stacks it all. It is written after the phone rules
   above so it overrides them. */
.basalt-hero-compact {
	--basalt-hero-py: 1.4rem;
	/* How far the title sits from the left edge: icon width plus the gap.
      Wrapped figures and phone buttons indent by the same amount. */
	--basalt-hero-indent: calc(2.5rem + 1.1rem);
	grid-template-columns: minmax(0, 1fr) auto auto;
	grid-template-rows: none;
	grid-template-areas: "body figures actions";
	align-items: center;
	border-radius: 16px;
}
.basalt-hero-compact:not(:has(> .basalt-hero-body > .basalt-hero-icon)) {
	--basalt-hero-indent: 0rem;
}
@media (max-width: 1199.98px) {
	.basalt-hero-compact {
		grid-template-columns: minmax(0, 1fr) auto;
		grid-template-areas: "body actions" "figures figures";
	}
}
@media (max-width: 767.98px) {
	.basalt-hero-compact {
		--basalt-hero-py: 1.5rem;
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "body" "actions" "figures";
	}
}
.basalt-hero-compact .basalt-hero-body {
	display: grid;
	column-gap: 1.1rem;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: center;
}
.basalt-hero-compact .basalt-hero-back,
.basalt-hero-compact .basalt-hero-title,
.basalt-hero-compact .basalt-hero-desc {
	grid-column: 1/-1;
}
.basalt-hero-compact .basalt-hero-icon ~ .basalt-hero-title,
.basalt-hero-compact .basalt-hero-icon ~ .basalt-hero-desc {
	grid-column: 2;
}
.basalt-hero-compact .basalt-hero-icon {
	grid-row: span 2;
	margin: 0;
	/* A wrapping description must not pull the icon away from the title. */
}
@media (max-width: 767.98px) {
	.basalt-hero-compact .basalt-hero-icon {
		align-self: start;
	}
}
.basalt-hero-compact .basalt-hero-title {
	font-size: clamp(1.3rem, 1.05rem + 0.6vw, 1.55rem);
}
.basalt-hero-compact .basalt-hero-desc {
	max-width: 64ch;
	margin-top: 0.3rem;
	font-size: 0.9rem;
	line-height: 1.45;
}
.basalt-hero-compact .basalt-hero-actions {
	align-self: center;
	justify-self: end;
	margin: 0 0 0 1.5rem;
}
@media (max-width: 767.98px) {
	.basalt-hero-compact .basalt-hero-actions {
		justify-self: start;
		justify-content: flex-start;
		margin: 1.1rem 0 0 var(--basalt-hero-indent);
	}
}
.basalt-hero-compact .basalt-hero-figures {
	gap: 0;
	flex-wrap: nowrap;
	align-self: center;
	margin: 0 0 0 1.5rem;
	padding: 0;
	border: 0;
}
@media (max-width: 1199.98px) {
	.basalt-hero-compact .basalt-hero-figures {
		gap: 0.4rem;
		flex-wrap: wrap;
		justify-self: start;
		margin: 0.8rem 0 0 var(--basalt-hero-indent);
		border-radius: 0;
		background: none;
		box-shadow: none;
	}
}
@media (max-width: 767.98px) {
	.basalt-hero-compact .basalt-hero-figures {
		margin-top: 1rem;
	}
}
.basalt-hero-compact .basalt-hero-figure {
	margin: 0;
	padding: 0 1.1rem;
	border: 0;
}
.basalt-hero-compact .basalt-hero-figure:first-child {
	padding-left: 0;
}
.basalt-hero-compact .basalt-hero-figure:last-child {
	padding-right: 0;
}
.basalt-hero-compact .basalt-hero-figure + .basalt-hero-figure {
	border-left: 1px solid var(--basalt-hero-line, var(--basalt-edge));
}
.basalt-hero-compact .basalt-hero-value {
	font-size: 1.1rem;
}
@media (max-width: 1199.98px) {
	.basalt-hero-compact .basalt-hero-value {
		font-size: 0.95rem;
	}
}
@media (max-width: 1199.98px) {
	.basalt-hero-compact .basalt-hero-label {
		margin: 0;
		font-size: 0.8rem;
	}
}
.basalt-hero-compact {
	/* The aside still bleeds off the top, right and bottom edges; once the
      row wraps it becomes a full-width band under the text. */
}
.basalt-hero-compact .basalt-hero-aside {
	align-self: stretch;
	align-items: center;
	margin: calc(var(--basalt-hero-py) * -1) calc(var(--basalt-hero-px) * -1) calc(var(--basalt-hero-py) * -1) 1.5rem;
	padding: 0.75rem 1.1rem;
}
@media (max-width: 1199.98px) {
	.basalt-hero-compact .basalt-hero-aside {
		margin: 0.8rem calc(var(--basalt-hero-px) * -1) calc(var(--basalt-hero-py) * -1);
		padding: 0.6rem var(--basalt-hero-px) 0.6rem calc(var(--basalt-hero-px) + var(--basalt-hero-indent));
	}
}
@media (max-width: 767.98px) {
	.basalt-hero-compact .basalt-hero-aside {
		margin-top: 1.1rem;
	}
}

/* The ink and glow icons are larger, so their indent is too. */
.basalt-hero-ink.basalt-hero-compact {
	--basalt-hero-indent: calc(2.75rem + 1.1rem);
}

/* Compact glow drops the dashed rule and keeps its buttons on the title
   row until a phone stacks them. */
.basalt-hero-glow.basalt-hero-compact {
	--basalt-hero-indent: calc(2.85rem + 1.1rem);
}
.basalt-hero-glow.basalt-hero-compact .basalt-hero-actions,
.basalt-hero-glow.basalt-hero-compact:not(:has(> .basalt-hero-figures)) .basalt-hero-actions {
	grid-column: actions;
	justify-content: flex-end;
	margin: 0 0 0 1.5rem;
	padding: 0;
	border-top: 0;
}
@media (max-width: 767.98px) {
	.basalt-hero-glow.basalt-hero-compact .basalt-hero-actions,
	.basalt-hero-glow.basalt-hero-compact:not(:has(> .basalt-hero-figures)) .basalt-hero-actions {
		justify-self: start;
		justify-content: flex-start;
		margin: 1.1rem 0 0 var(--basalt-hero-indent);
	}
}

/* Compact aurora keeps the colored panel bleeding off the right edge, with
   the figures standing side by side inside it. */
.basalt-hero-aurora.basalt-hero-compact:has(> .basalt-hero-aside) {
	grid-template-columns: minmax(0, 1fr) auto auto;
	grid-template-rows: none;
	grid-template-areas: "body actions aside";
}
@media (max-width: 1199.98px) {
	.basalt-hero-aurora.basalt-hero-compact:has(> .basalt-hero-aside) {
		grid-template-columns: minmax(0, 1fr) auto;
		grid-template-areas: "body actions" "aside aside";
	}
}
@media (max-width: 767.98px) {
	.basalt-hero-aurora.basalt-hero-compact:has(> .basalt-hero-aside) {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "body" "actions" "aside";
	}
}
.basalt-hero-aurora.basalt-hero-compact .basalt-hero-figures {
	gap: 0.5rem;
	flex-direction: row;
	margin: 0;
}
.basalt-hero-aurora.basalt-hero-compact .basalt-hero-figure {
	gap: 0;
	flex-direction: column-reverse;
	align-items: flex-start;
	justify-content: flex-start;
	padding: 0.5rem 0.8rem;
	border: 0;
	border-radius: 10px;
}
.basalt-hero-aurora.basalt-hero-compact .basalt-hero-label {
	margin-top: 0.25rem;
}

/* Compact tint keeps the figures on their small white card. */
.basalt-hero-tint.basalt-hero-compact .basalt-hero-figure {
	padding: 0.6rem 1.1rem;
}
.basalt-hero-tint.basalt-hero-compact .basalt-hero-figures {
	border-radius: 12px;
}

/* Once the row wraps, each figure becomes a pill with the number and label
   on one line. It comes after the per-look rules above so it beats them;
   on the tinted and colored looks the pills get a solid face. */
@media (max-width: 1199.98px) {
	.basalt-hero-compact .basalt-hero-figures > .basalt-hero-figure {
		gap: 0.4rem;
		flex-direction: row-reverse;
		align-items: baseline;
		justify-content: flex-end;
		padding: 0.3rem 0.75rem;
		border: 0;
		border-radius: 999px;
		background: color-mix(in srgb, var(--basalt-hero-fg) 7%, transparent);
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
	}
	.basalt-hero-tint.basalt-hero-compact .basalt-hero-figures > .basalt-hero-figure,
	.basalt-hero-aurora.basalt-hero-compact .basalt-hero-figures > .basalt-hero-figure {
		background: color-mix(in srgb, var(--basalt-plane) 88%, transparent);
	}
}
/* .basalt-pagehead is the plain alternative to the hero for pages that
   are busy enough already: the page name, one line under it, and the main
   buttons on the right.

   <header class="basalt-pagehead">
     <div class="basalt-pagehead-text">
       <h1 class="basalt-pagehead-title">Reports</h1>
       <p class="basalt-pagehead-desc">What this page is for.</p>
     </div>
     <div class="basalt-pagehead-actions">...</div>
   </header> */
.basalt-pagehead {
	display: flex;
	gap: 0.75rem 1.5rem;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	margin-bottom: 1.5rem;
}
.basalt-pagehead-text {
	min-width: 0;
}
.basalt-pagehead-title {
	margin: 0;
	font-size: 1.6rem;
	font-weight: 750;
	letter-spacing: -0.01em;
	color: var(--basalt-copy);
}
.basalt-pagehead-desc {
	margin: 0.25rem 0 0;
	font-size: 0.9rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-pagehead {
	/* Centered, so a button beside a taller control (a segmented switch)
     keeps its own height instead of stretching with its label at the top. */
}
.basalt-pagehead-actions {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	align-items: center;
}
.basalt-pagehead-actions .btn {
	white-space: nowrap;
}

/**
 * Selects and type-ahead suggestions share a single dropdown look. basalt.js
 * hides each select.form-select behind a button that opens a custom list, and
 * fields marked [data-basalt-combobox] drop their suggestions into that same
 * list. field-types.html walks through the markup and every option.
 */
/* Children laid out in a centered row with a fixed gap between them. */
/* A small square badge whose glyph sits dead center. */
/* The real select stays in the form so its value, required flag and reset
   keep working, but it takes no room and no clicks. The doubled selector
   beats the input-group and floating-label rules that would position it. */
select.basalt-select-native.form-select,
select.basalt-select-native {
	position: absolute;
	width: 1px;
	height: 1px;
	min-height: 0;
	margin: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
	opacity: 0;
	pointer-events: none;
	clip-path: inset(50%);
}

.basalt-select {
	/* The button wears the select's own classes, so Bootstrap's sizes,
      validation colors, floating labels and input groups treat it exactly as
      they treated the select. */
}
.basalt-select-trigger {
	text-align: start;
	white-space: nowrap;
	cursor: pointer;
}
.basalt-select-trigger:disabled {
	cursor: not-allowed;
}
.basalt-select-trigger.form-select.is-open {
	border-color: var(--basalt-hue);
	box-shadow: 0 0 0 0.25rem var(--basalt-hue-border);
}
.basalt-select-trigger.form-select.is-open.is-invalid {
	border-color: var(--basalt-danger);
}
.basalt-select {
	/* A single grid cell stacks the shown choice over hidden copies of every
      other one, which sizes the button to its longest label. */
}
.basalt-select-value {
	display: grid;
	min-width: 0;
}
.basalt-select-current,
.basalt-select-ghost {
	grid-row: 1;
	grid-column: 1;
	min-width: 0;
	display: flex;
	gap: 0.5rem;
	align-items: center;
}
.basalt-select-ghost {
	visibility: hidden;
}
.basalt-select-text {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.basalt-select-placeholder {
	color: var(--basalt-copy-muted);
}
.basalt-select {
	/* Icons and color dots look the same on the button as in the list. */
}
.basalt-select-icon {
	flex-shrink: 0;
	width: 1.1em;
	line-height: 1;
	text-align: center;
	color: var(--basalt-copy-muted);
}
.basalt-select-dot {
	flex-shrink: 0;
	width: 0.5rem;
	height: 0.5rem;
	margin: 0 0.1rem;
	border-radius: 50%;
	background: var(--basalt-dot, var(--basalt-hue));
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--basalt-dot, var(--basalt-hue)) 20%, transparent);
}

/* Validation is read off the hidden select, which sits right after the
   button or right before it depending on the markup. */
.was-validated .basalt-select-native:invalid + .basalt-select-trigger,
.was-validated .basalt-select-trigger:has(+ .basalt-select-native:invalid) {
	border-color: var(--basalt-danger);
}
.was-validated .basalt-select-native:valid + .basalt-select-trigger.form-select,
.was-validated .basalt-select-trigger.form-select:has(+ .basalt-select-native:valid) {
	border-color: var(--basalt-success);
}

/* A multiple select wraps its picks as chips, each with a cross to drop it. */
.basalt-select-trigger-multi {
	flex-wrap: wrap;
	white-space: normal;
	display: flex;
	gap: 0.3rem;
	align-items: center;
}
.basalt-select-trigger-multi.form-select {
	padding-top: 0.3rem;
	padding-bottom: 0.3rem;
}
.basalt-select-trigger-multi.form-select:not(.form-select-sm):not(.form-select-lg) {
	min-height: calc(2.25rem + var(--bs-border-width) * 2);
}

.basalt-select-chip {
	max-width: 100%;
	padding: 0.12rem 0.2rem 0.12rem 0.5rem;
	border-radius: 999px;
	font-size: 0.81rem;
	font-weight: 600;
	line-height: 1.35;
	color: var(--basalt-copy);
	background: var(--basalt-hue-soft);
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
}
.basalt-select-chip .basalt-select-icon {
	color: var(--basalt-copy-body);
}
.basalt-select-chip-x {
	width: 1.1rem;
	height: 1.1rem;
	border-radius: 50%;
	font-size: 0.95rem;
	color: var(--basalt-copy-body);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	transition:
		background-color 110ms ease,
		color 110ms ease;
}
.basalt-select-chip-x:hover {
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-copy) 14%, transparent);
}
.basalt-select-trigger:disabled .basalt-select-chip-x {
	display: none;
}

/* The floating list is pinned to the viewport and placed by script; it
   grows out of whichever edge of the button it opens from. */
.basalt-select-popup {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 1090;
	transform-origin: top center;
	display: flex;
	flex-direction: column;
	width: max-content;
	max-width: min(24rem, 100vw - 16px);
	padding: 0.375rem;
	border: 1px solid var(--basalt-edge-strong);
	border-radius: 14px;
	font-size: 0.875rem;
	font-weight: 400;
	line-height: 1.35;
	text-align: start;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	box-shadow:
		var(--basalt-card-shadow),
		0 20px 44px -18px var(--basalt-scrim);
}
.basalt-select-popup[hidden] {
	display: none;
}
.basalt-select-popup.is-above {
	transform-origin: bottom center;
}
.basalt-select-popup.is-open {
	animation: basalt-select-in 170ms cubic-bezier(0.2, 0.9, 0.3, 1);
}
.basalt-select-popup.is-open.is-above {
	animation-name: basalt-select-in-above;
}
.basalt-select-popup {
	/* Long lists open with a filter field across the top. */
}
.basalt-select-popup-search {
	position: relative;
	flex-shrink: 0;
	margin: 0 0 0.375rem;
}
.basalt-select-popup-search .bi {
	position: absolute;
	top: 50%;
	left: 0.7rem;
	transform: translateY(-50%);
	font-size: 0.8rem;
	color: var(--basalt-copy-muted);
	pointer-events: none;
}
.basalt-select-popup-input {
	width: 100%;
	padding: 0.4rem 0.75rem 0.4rem 2rem;
	border: 1px solid var(--basalt-edge-strong);
	border-radius: 9px;
	outline: 0;
	font: inherit;
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-copy) 4%, var(--basalt-plane));
}
.basalt-select-popup-input::placeholder {
	color: var(--basalt-copy-muted);
}
.basalt-select-popup-input:focus {
	border-color: var(--basalt-hue);
}
.basalt-select-popup-list {
	max-height: 18rem;
	outline: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	scrollbar-color: color-mix(in srgb, var(--basalt-copy) 22%, transparent) transparent;
}
.basalt-select-popup {
	/* A rule separates each group from whatever came before it. */
}
.basalt-select-popup-group + .basalt-select-popup-group,
.basalt-select-popup-option + .basalt-select-popup-group {
	margin-top: 0.25rem;
	padding-top: 0.25rem;
	border-top: 1px solid var(--basalt-edge);
}
.basalt-select-popup-heading {
	padding: 0.4rem 0.625rem 0.3rem;
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--basalt-copy-muted);
}
.basalt-select-popup-option {
	min-height: 2.25rem;
	padding: 0.4rem 0.625rem;
	border-radius: 9px;
	color: var(--basalt-copy);
	display: flex;
	gap: 0.625rem;
	align-items: center;
	cursor: pointer;
	transition: background-color 90ms ease;
	/* Highlight and choice also recolor the parts inside the option. */
}
.basalt-select-popup-option.is-active {
	background: color-mix(in srgb, var(--basalt-hue) 11%, var(--basalt-plane));
}
.basalt-select-popup-option.is-active .basalt-select-popup-hint {
	color: var(--basalt-copy-body);
}
.basalt-select-popup-option[aria-selected="true"] {
	font-weight: 600;
}
.basalt-select-popup-option[aria-selected="true"] .basalt-select-icon {
	color: var(--basalt-hue);
}
.basalt-select-popup-option[aria-selected="true"] .basalt-select-popup-check {
	visibility: visible;
}
.basalt-select-popup-option[aria-selected="true"] .basalt-select-popup-box {
	border-color: var(--basalt-hue);
	color: var(--basalt-on-hue);
	background: var(--basalt-hue);
}
.basalt-select-popup-option[aria-disabled="true"] {
	color: var(--basalt-copy-muted);
	cursor: not-allowed;
}
.basalt-select-popup-option[aria-disabled="true"] .basalt-select-icon,
.basalt-select-popup-option[aria-disabled="true"] .basalt-select-dot {
	opacity: 0.5;
}
.basalt-select-popup-body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	min-width: 0;
}
.basalt-select-popup-label {
	overflow-wrap: anywhere;
}
.basalt-select-popup-hint {
	margin-top: 0.1rem;
	font-size: 0.75rem;
	font-weight: 400;
	color: var(--basalt-copy-muted);
}
.basalt-select-popup {
	/* The tick at the far end only shows on the chosen option. */
}
.basalt-select-popup-check {
	visibility: hidden;
	flex-shrink: 0;
	margin-left: auto;
	padding-left: 0.5rem;
	font-size: 1.05rem;
	line-height: 1;
	color: var(--basalt-hue);
}
.basalt-select-popup {
	/* Multiple selects trade the tick for a checkbox in front. */
}
.basalt-select-popup-box {
	flex-shrink: 0;
	width: 1.1rem;
	height: 1.1rem;
	border: 1.5px solid color-mix(in srgb, var(--basalt-copy) 34%, transparent);
	border-radius: 5px;
	font-size: 0.85rem;
	color: transparent;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	transition:
		background-color 110ms ease,
		border-color 110ms ease;
}
.basalt-select-popup {
	/* Typed letters are marked inside each label they match. */
}
.basalt-select-popup mark {
	padding: 0 0.05em;
	border-radius: 3px;
	font-weight: 700;
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-hue) 20%, transparent);
}
.basalt-select-popup {
	/* When the filter leaves nothing, one quiet line says so. */
}
.basalt-select-popup-empty {
	display: flex;
	gap: 0.5rem;
	align-items: baseline;
	margin: 0;
	padding: 0.6rem 0.625rem;
	font-size: 0.81rem;
	color: var(--basalt-copy-body);
}
.basalt-select-popup-empty[hidden] {
	display: none;
}
.basalt-select-popup-empty .bi {
	color: var(--basalt-copy-muted);
}

@keyframes basalt-select-in {
	from {
		transform: translateY(-6px) scale(0.98);
		opacity: 0;
	}
}
@keyframes basalt-select-in-above {
	from {
		transform: translateY(6px) scale(0.98);
		opacity: 0;
	}
}
/* Reduced motion: the list just appears and hover tints change at once. */
@media (prefers-reduced-motion: reduce) {
	.basalt-select-popup.is-open {
		animation: none;
	}
	.basalt-select-popup-option,
	.basalt-select-popup-box,
	.basalt-select-chip-x {
		transition: none;
	}
}
/**
 * Spot illustrations, .basalt-illo: inline SVGs whose shapes are colored
 * by class, so a drawing repaints itself with the palette and the theme.
 * Any ancestor can set --basalt-tone to swap the lead color. The empty
 * states and the card types draw with these classes.
 */
/* The lead color, and the lighter and darker shades taken from it. Each
   one comes as a fill class and as a matching stroke-* class. */
.basalt-illo {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

.basalt-illo-tone {
	fill: var(--basalt-tone, var(--basalt-hue));
}

.basalt-illo-deep {
	fill: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 62%, var(--basalt-copy));
}

.basalt-illo-soft {
	fill: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 30%, var(--basalt-plane));
}

.basalt-illo-paper {
	fill: var(--basalt-plane);
}

.basalt-illo-ink {
	fill: var(--basalt-copy);
}

.basalt-illo-mute {
	fill: var(--basalt-edge-strong);
}

.basalt-illo-shadow {
	fill: color-mix(in srgb, var(--basalt-copy) 10%, transparent);
}

/* Outlined shapes: a sheet of paper, a magnifier lens, a sparkle, chart
   axes, a dashed placeholder and a dashed trail. */
.basalt-illo-card {
	fill: var(--basalt-plane);
	stroke: var(--basalt-edge-strong);
	stroke-width: 1.5;
}

.basalt-illo-glass {
	fill: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 14%, var(--basalt-plane));
	stroke: var(--basalt-tone, var(--basalt-hue));
	stroke-width: 6;
}

.basalt-illo-spark {
	fill: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 45%, var(--basalt-plane));
}

.basalt-illo-axis {
	fill: none;
	stroke: var(--basalt-edge-strong);
	stroke-width: 2;
	stroke-linecap: round;
}

.basalt-illo-ghost {
	fill: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 6%, transparent);
	stroke: var(--basalt-edge-strong);
	stroke-width: 1.5;
	stroke-dasharray: 4 3;
}

.basalt-illo-dash {
	opacity: 0.55;
	fill: none;
	stroke: var(--basalt-tone, var(--basalt-hue));
	stroke-width: 2.5;
	stroke-dasharray: 5 5;
	stroke-linecap: round;
}

/* Line work: every stroke-* class draws an unfilled, round-ended line,
   colored by shade and weighted by the width classes after it. */
[class*="basalt-illo-stroke-"] {
	fill: none;
	stroke-width: 7;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.basalt-illo-stroke-tone {
	stroke: var(--basalt-tone, var(--basalt-hue));
}

.basalt-illo-stroke-deep {
	stroke: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 62%, var(--basalt-copy));
}

.basalt-illo-stroke-soft {
	stroke: color-mix(in srgb, var(--basalt-tone, var(--basalt-hue)) 30%, var(--basalt-plane));
}

.basalt-illo-stroke-paper {
	stroke: var(--basalt-plane);
}

.basalt-illo-stroke-wide {
	stroke-width: 15;
}

.basalt-illo-stroke-thick {
	stroke-width: 9;
}

.basalt-illo-stroke-thin {
	stroke-width: 3;
}

/* Supporting colors c1 to c4 borrow chart series 2 to 5. */
.basalt-illo-c1 {
	fill: var(--basalt-series-2);
}

.basalt-illo-c2 {
	fill: var(--basalt-series-3);
}

.basalt-illo-c3 {
	fill: var(--basalt-series-4);
}

.basalt-illo-c4 {
	fill: var(--basalt-series-5);
}

/* Hovering an empty state makes its floating piece bob gently. */
.basalt-empty:hover .basalt-illo-float {
	animation: basalt-float 2.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-empty:hover .basalt-illo-float {
		animation: none;
	}
}

@keyframes basalt-float {
	50% {
		transform: translateY(-4px);
	}
}
/* A check mark that draws itself and a burst of confetti around it. Both
   show finished by default; once a script adds .is-armed they wait hidden
   until .is-in arrives, then play with staggered delays. */
.basalt-illo-draw {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
}

.basalt-illo-burst > * {
	transform-box: fill-box;
	transform-origin: center;
}

.is-armed:not(.is-in) .basalt-illo-draw {
	stroke-dashoffset: 1;
}
.is-armed:not(.is-in) .basalt-illo-burst > * {
	transform: scale(0.2) translateY(10px);
	opacity: 0;
}

.is-armed .basalt-illo-draw {
	transition: stroke-dashoffset 500ms cubic-bezier(0.6, 0, 0.3, 1) 250ms;
}
.is-armed .basalt-illo-burst > * {
	transition:
		opacity 400ms ease 700ms,
		transform 600ms cubic-bezier(0.3, 1.6, 0.5, 1) 700ms;
}
.is-armed .basalt-illo-burst > :nth-child(2n) {
	transition-delay: 780ms;
}
.is-armed .basalt-illo-burst > :nth-child(3n) {
	transition-delay: 860ms;
}
@media (prefers-reduced-motion: reduce) {
	.is-armed .basalt-illo-draw,
	.is-armed .basalt-illo-burst > * {
		transition: none;
	}
}

/**
 * Buttons that do more than Bootstrap's: tinted soft fills, square icon
 * buttons, numbers and corner dots, shortcut keys, pressed toggles, copy,
 * self-reporting loaders, a segmented switch, a floating speed dial and a
 * two-step confirm, plus the small refresh and icon buttons card headers
 * use. They appear in that order on buttons.html (loaders also on
 * loaders.html). Their behavior comes from basalt.js: basaltButtonState
 * and the data-basalt-confirm, -segmented, -speed-dial, -copy and -shortcut
 * hooks.
 */
/* Bootstrap's button height for a given vertical padding, used to make an
   icon-only button exactly as wide as it is tall. */
/* Icon and label laid out on one line, optionally centered as a unit. */
/* A single glyph or number centered in a fixed box. */
/* What changes for visitors who asked their system for less motion. */
/* Soft tones: the token the tint is mixed from, the share it leans toward
   the copy for the label, and, where the default 14% / 22% wash is too pale
   or too loud, its own resting and hover strength. */
/* A soft button is a wash of its tone with a darker label. It has no edge
   until pressed, when a faint one appears. */
[class*="btn-soft-"] {
	--bs-btn-color: var(--btn-soft-text);
	--bs-btn-hover-color: var(--btn-soft-text);
	--bs-btn-active-color: var(--btn-soft-text);
	--bs-btn-bg: color-mix(in srgb, var(--btn-soft-tone) var(--btn-soft-rest, 14%), transparent);
	--bs-btn-hover-bg: color-mix(in srgb, var(--btn-soft-tone) var(--btn-soft-hover, 22%), transparent);
	--bs-btn-active-bg: color-mix(in srgb, var(--btn-soft-tone) var(--btn-soft-hover, 22%), transparent);
	--bs-btn-border-color: transparent;
	--bs-btn-hover-border-color: transparent;
	--bs-btn-active-border-color: color-mix(in srgb, var(--btn-soft-tone) 40%, transparent);
	font-weight: 600;
}

.btn-soft-primary {
	--btn-soft-tone: var(--basalt-hue);
	--btn-soft-text: color-mix(in srgb, var(--basalt-hue) 56%, var(--basalt-copy));
}

.btn-soft-secondary {
	--btn-soft-tone: var(--basalt-copy);
	--btn-soft-text: var(--basalt-copy-body);
	--btn-soft-rest: 7%;
	--btn-soft-hover: 12%;
}

.btn-soft-success {
	--btn-soft-tone: var(--basalt-success);
	--btn-soft-text: color-mix(in srgb, var(--basalt-success) 46%, var(--basalt-copy));
	--btn-soft-rest: 16%;
	--btn-soft-hover: 24%;
}

.btn-soft-danger {
	--btn-soft-tone: var(--basalt-danger);
	--btn-soft-text: color-mix(in srgb, var(--basalt-danger) 56%, var(--basalt-copy));
}

.btn-soft-warning {
	--btn-soft-tone: var(--basalt-warning);
	--btn-soft-text: color-mix(in srgb, var(--basalt-warning) 42%, var(--basalt-copy));
	--btn-soft-rest: 18%;
	--btn-soft-hover: 26%;
}

.btn-soft-info {
	--btn-soft-tone: var(--basalt-flare);
	--btn-soft-text: color-mix(in srgb, var(--basalt-flare) 42%, var(--basalt-copy));
	--btn-soft-rest: 18%;
	--btn-soft-hover: 26%;
}

/* Square buttons hold one icon and keep equal sides at every size. */
.btn-square {
	width: calc(1.5em + 0.75rem + 2px);
	height: calc(1.5em + 0.75rem + 2px);
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

.btn-sm.btn-square {
	width: calc(1.5em + 0.5rem + 2px);
	height: calc(1.5em + 0.5rem + 2px);
}

.btn-lg.btn-square {
	width: calc(1.5em + 1rem + 2px);
	height: calc(1.5em + 1rem + 2px);
}

/* A count rides in its own segment behind a divider. */
.btn-count {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}
.btn-count .bi + span {
	margin-right: 0.4rem;
}

.btn-count-num {
	margin-left: 0.2rem;
	padding-left: 0.6rem;
	border-left: 1px solid color-mix(in srgb, currentColor 35%, transparent);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

/* A badge sits on the top corner of an icon button, ringed in the surface
   color so it lifts off whatever is under it. */
.btn-badge {
	position: relative;
	overflow: visible;
}

.btn-badge-num,
.btn-badge-dot {
	position: absolute;
	top: 0;
	right: 0;
	translate: 40% -40%;
	border-radius: 999px;
	border: 2px solid var(--basalt-plane);
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-danger) 76%, var(--basalt-copy));
}

.btn-badge-num {
	min-width: 1.25rem;
	height: 1.25rem;
	padding: 0 0.3rem;
	font-size: 0.67rem;
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	display: inline-grid;
	place-items: center;
}

.btn-badge-dot {
	translate: 25% -25%;
	width: 0.75rem;
	height: 0.75rem;
}

/* A shortcut button prints its key in a small outlined cap and gives a
   quick press when the key is used. */
.btn-kbd {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}
.btn-kbd.is-fired {
	animation: btn-press 260ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.btn-kbd.is-fired {
		animation: none;
	}
}

.btn-kbd-key {
	min-width: 1.35rem;
	height: 1.35rem;
	margin-left: 0.2rem;
	padding: 0 0.3rem;
	border-radius: 5px;
	border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
	font:
		600 0.71rem/1 "Chivo Mono",
		monospace;
	color: inherit;
	background: transparent;
	box-shadow: none;
	display: inline-grid;
	place-items: center;
}

@keyframes btn-press {
	40% {
		scale: 0.94;
	}
	100% {
		scale: 1;
	}
}
/* Toggles pair with Bootstrap's data-bs-toggle="button" and swap in a
   second label and icon while pressed. */
.btn-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
}

.btn-toggle-off,
.btn-toggle-on {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.btn-toggle-on,
.btn-toggle.active .btn-toggle-off {
	display: none;
}

.btn-toggle.active .btn-toggle-on {
	display: inline-flex;
}
.btn-toggle.active .btn-toggle-on .bi {
	animation: btn-pop 320ms cubic-bezier(0.2, 0.9, 0.3, 1.5);
}
@media (prefers-reduced-motion: reduce) {
	.btn-toggle.active .btn-toggle-on .bi {
		animation: none;
	}
}

/* An icon-only toggle stays understated when pressed; its icon tells the state. */
.btn-toggle.btn-outline-secondary.active {
	border-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
	color: var(--basalt-copy);
	background-color: color-mix(in srgb, var(--basalt-hue) 12%, var(--basalt-plane));
}

.btn-toggle.active .bi-star-fill {
	color: var(--basalt-warning);
}

.btn-toggle.active .bi-heart-fill {
	color: var(--basalt-danger);
}

@keyframes btn-pop {
	0% {
		transform: scale(0.4);
	}
	100% {
		transform: scale(1);
	}
}
/* Copy buttons stack both faces in one cell, so the check and "Copied"
   take over without the button changing width. */
.btn-copy {
	display: inline-grid;
}

.btn-copy-idle,
.btn-copy-done {
	grid-area: 1/1;
	white-space: nowrap;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	transition:
		opacity 170ms ease,
		transform 200ms cubic-bezier(0.2, 0.9, 0.3, 1.3),
		visibility 170ms;
}
@media (prefers-reduced-motion: reduce) {
	.btn-copy-idle,
	.btn-copy-done {
		transition: none;
	}
}

.btn-copy-done,
.btn-copy.is-copied .btn-copy-idle {
	transform: scale(0.7);
	visibility: hidden;
	opacity: 0;
}

.btn-copy.is-copied .btn-copy-done {
	transform: none;
	visibility: visible;
	opacity: 1;
}

.btn-copy-icon {
	width: calc(1.5em + 0.5rem + 2px);
	padding-left: 0;
	padding-right: 0;
}

/* Loading buttons report their own progress, set by
   basaltButtonState(btn, state, label) as is-loading, is-success or
   is-error. The stacked form keeps one span per state (idle, busy, done,
   fail) in a single grid cell so the width holds steady; the swap form
   has one icon slot and one label whose contents the script replaces. */
.btn-loading {
	position: relative;
	display: inline-grid;
	isolation: isolate;
	overflow: hidden;
}
.btn-loading.is-loading {
	cursor: progress;
}
.btn-loading .spinner-border-sm {
	--bs-spinner-border-width: 0.15em;
	width: 0.95rem;
	height: 0.95rem;
	color: inherit;
}

.btn-loading-state {
	grid-area: 1/1;
	white-space: nowrap;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	transition:
		opacity 200ms ease,
		transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1),
		visibility 200ms;
}
@media (prefers-reduced-motion: reduce) {
	.btn-loading-state {
		transition: none;
	}
}

/* Spans that are not showing wait below; the idle one leaves upward. */
.btn-loading-state:not(.btn-loading-idle),
.btn-loading:is(.is-loading, .is-success, .is-error) .btn-loading-idle {
	transform: translateY(0.7em);
	visibility: hidden;
	opacity: 0;
}

.btn-loading:is(.is-loading, .is-success, .is-error) .btn-loading-idle {
	transform: translateY(-0.7em);
}

.btn-loading.is-loading .btn-loading-busy,
.btn-loading.is-success .btn-loading-done,
.btn-loading.is-error .btn-loading-fail {
	transform: none;
	visibility: visible;
	opacity: 1;
}

.btn-loading-num {
	min-width: 3.6ch;
	text-align: left;
	font-variant-numeric: tabular-nums;
}

.btn-loading.is-success .btn-loading-done .bi {
	animation: btn-pop 360ms cubic-bezier(0.2, 0.9, 0.3, 1.4);
}
@media (prefers-reduced-motion: reduce) {
	.btn-loading.is-success .btn-loading-done .bi {
		animation: none;
	}
}

.btn-loading.is-error {
	animation: btn-shake 380ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.btn-loading.is-error {
		animation: none;
	}
}

.btn-loading-swap {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
}

.btn-loading-icon {
	width: 1rem;
	height: 1rem;
	display: inline-grid;
	place-items: center;
	flex-shrink: 0;
}
.btn-loading-icon .spinner-border {
	--bs-spinner-width: 1rem;
	--bs-spinner-height: 1rem;
	--bs-spinner-border-width: 0.15em;
	color: currentColor;
}

.btn-loading-swap.is-success .btn-loading-icon {
	animation: btn-pop-in 320ms cubic-bezier(0.3, 1.5, 0.5, 1);
}
@media (prefers-reduced-motion: reduce) {
	.btn-loading-swap.is-success .btn-loading-icon {
		animation: none;
	}
}

/* A failed swap button turns the danger tone and stays that way on hover. */
.btn-loading-swap.is-error {
	--bs-btn-color: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
	--bs-btn-border-color: var(--basalt-danger);
	--bs-btn-hover-color: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
	--bs-btn-hover-border-color: var(--basalt-danger);
	--bs-btn-hover-bg: var(--basalt-danger-soft);
	background-color: var(--basalt-danger-soft);
}
.btn-loading-swap.is-error:focus-visible,
.btn-loading-swap.is-error:hover {
	color: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
}

/* The progress form fills in behind its label as the work advances. */
.btn-loading-progress::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	transform: scaleX(var(--btn-progress, calc(var(--value, 0) / 100)));
	transform-origin: left center;
	background: color-mix(in srgb, var(--basalt-hue) 14%, transparent);
	transition: transform 180ms linear;
}
@media (prefers-reduced-motion: reduce) {
	.btn-loading-progress::before {
		transition: none;
	}
}
.btn-loading-progress:not(.is-loading)::before {
	transform: scaleX(0);
}

@keyframes btn-pop-in {
	from {
		transform: scale(0.4);
		opacity: 0;
	}
}
@keyframes btn-shake {
	0%,
	100% {
		translate: 0;
	}
	20% {
		translate: -4px;
	}
	40% {
		translate: 4px;
	}
	60% {
		translate: -3px;
	}
	80% {
		translate: 2px;
	}
}
/* The segmented switch draws a row of btn-check radios as one control.
   Once the script marks it is-ready it slides a thumb under the choice;
   until then the checked option fills by itself. */
.basalt-segmented {
	--seg-x: 0px;
	--seg-w: 0px;
	position: relative;
	display: inline-flex;
	gap: 2px;
	align-items: stretch;
	isolation: isolate;
	max-width: 100%;
	padding: 3px;
	border-radius: 12px;
	border: 1px solid var(--basalt-edge);
	background: color-mix(in srgb, var(--basalt-copy) 7%, var(--basalt-plane));
}

.basalt-segmented-option {
	min-height: 2.25rem;
	/* The sides narrow on a phone so four or five choices still fit. */
	padding: 0.3rem clamp(0.6rem, 3.4vw, 1rem);
	border-radius: 9px;
	font-size: 0.875rem;
	font-weight: 600;
	line-height: 1.2;
	white-space: nowrap;
	color: var(--basalt-copy-body);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	position: relative;
	z-index: 1;
	cursor: pointer;
	user-select: none;
	transition:
		color 180ms ease,
		background-color 180ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-segmented-option {
		transition: none;
	}
}
.basalt-segmented-option:hover {
	color: var(--basalt-copy);
}

.btn-check:checked + .basalt-segmented-option {
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	box-shadow: 0 1px 2px color-mix(in srgb, var(--basalt-copy) 14%, transparent);
}
.btn-check:focus-visible:not(:checked) + .basalt-segmented-option {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

.basalt-segmented-thumb {
	position: absolute;
	top: 3px;
	bottom: 3px;
	left: 0;
	z-index: 0;
	translate: var(--seg-x) 0;
	width: var(--seg-w);
	border-radius: 9px;
	background: var(--basalt-plane);
	opacity: 0;
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--basalt-copy) 14%, transparent),
		0 2px 8px color-mix(in srgb, var(--basalt-copy) 8%, transparent);
	pointer-events: none;
}

.basalt-segmented.is-ready .basalt-segmented-thumb {
	opacity: 1;
}
.basalt-segmented.is-ready.is-moving .basalt-segmented-thumb {
	transition:
		translate 280ms cubic-bezier(0.3, 0.9, 0.3, 1),
		width 280ms cubic-bezier(0.3, 0.9, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-segmented.is-ready.is-moving .basalt-segmented-thumb {
		transition: none;
	}
}
.basalt-segmented.is-ready .btn-check:checked + .basalt-segmented-option {
	background: transparent;
	box-shadow: none;
}

.basalt-segmented-sm .basalt-segmented-option {
	min-height: 1.9rem;
	padding: 0.25rem clamp(0.5rem, 2.6vw, 0.75rem);
	font-size: 0.8rem;
}

/* The block form fills a narrow space but stops short of stretching its
   options across a wide one. */
.basalt-segmented-block {
	display: flex;
	max-width: 28rem;
}
.basalt-segmented-block .basalt-segmented-option {
	flex: 1 1 0;
	min-width: 0;
}

/* The speed dial is a round toggle with a column of labeled actions that
   rise above it, one after another, when it opens. */
.basalt-speed-dial {
	z-index: 5;
	display: inline-flex;
	gap: 0.75rem;
	flex-direction: column;
	align-items: flex-end;
}

.basalt-speed-dial-fixed {
	position: fixed;
	right: 1.5rem;
	bottom: 1.5rem;
	z-index: 1030;
}

.basalt-speed-dial-toggle {
	width: 3.25rem;
	height: 3.25rem;
	padding: 0;
	border-radius: 50%;
	font-size: 1.35rem;
	box-shadow: 0 6px 18px color-mix(in srgb, var(--basalt-hue) 32%, transparent);
	display: inline-grid;
	place-items: center;
}
.basalt-speed-dial-toggle .bi {
	transition: transform 240ms cubic-bezier(0.3, 0.9, 0.3, 1.2);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-speed-dial-toggle .bi {
		transition: none;
	}
}
.basalt-speed-dial-toggle[aria-expanded="true"] .bi {
	transform: rotate(45deg);
}

.basalt-speed-dial-actions {
	display: flex;
	visibility: hidden;
	gap: 0.5rem;
	flex-direction: column;
	align-items: flex-end;
}

.basalt-speed-dial-action {
	padding: 0;
	border: 0;
	font: inherit;
	color: var(--basalt-copy);
	background: none;
	opacity: 0;
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	translate: 0 0.6rem;
	cursor: pointer;
	transition:
		opacity 180ms ease,
		translate 210ms cubic-bezier(0.3, 0.9, 0.3, 1.2);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-speed-dial-action {
		transition: none;
	}
}

.basalt-speed-dial.is-open .basalt-speed-dial-actions {
	visibility: visible;
}
.basalt-speed-dial.is-open .basalt-speed-dial-action {
	translate: 0 0;
	opacity: 1;
}
.basalt-speed-dial.is-open {
	/* The action nearest the toggle moves first and each one above waits 40ms longer. */
}
.basalt-speed-dial.is-open .basalt-speed-dial-action:nth-last-child(2) {
	transition-delay: 40ms;
}
.basalt-speed-dial.is-open .basalt-speed-dial-action:nth-last-child(3) {
	transition-delay: 80ms;
}
.basalt-speed-dial.is-open .basalt-speed-dial-action:nth-last-child(4) {
	transition-delay: 120ms;
}

.basalt-speed-dial-label {
	padding: 0.3rem 0.7rem;
	border-radius: 8px;
	border: 1px solid var(--basalt-edge);
	font-size: 0.8rem;
	font-weight: 600;
	white-space: nowrap;
	background: var(--basalt-plane);
	box-shadow: var(--basalt-card-shadow);
}

.basalt-speed-dial-icon {
	width: 2.5rem;
	height: 2.5rem;
	margin-right: 0.375rem;
	border-radius: 50%;
	border: 1px solid var(--basalt-edge-strong);
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	box-shadow: var(--basalt-card-shadow);
	display: inline-grid;
	place-items: center;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}

/* Hover or keyboard focus tints the icon; the keyboard ring goes around
   the label instead of the whole row. */
.basalt-speed-dial-action:hover .basalt-speed-dial-icon,
.basalt-speed-dial-action:focus-visible .basalt-speed-dial-icon {
	color: var(--basalt-copy);
	background: var(--basalt-hue-soft);
}

.basalt-speed-dial-action:focus-visible {
	outline: none;
}
.basalt-speed-dial-action:focus-visible .basalt-speed-dial-label {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

/* Two-step confirm: the first click asks, and a second one within
   data-confirm-ms (3000 by default) fires 'basalt:confirm'. A bar along
   the bottom runs down the time left. */
.btn-confirm {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	position: relative;
	overflow: hidden;
}
.btn-confirm::after {
	content: "";
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	transform: scaleX(0);
	transform-origin: left center;
	height: 3px;
	background: currentColor;
	opacity: 0.55;
}

.btn-confirm-idle,
.btn-confirm-ask {
	white-space: nowrap;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.btn-confirm-ask,
.btn-confirm.is-asking .btn-confirm-idle {
	display: none;
}

.btn-confirm.is-asking .btn-confirm-ask {
	display: inline-flex;
	animation: btn-pop 240ms cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
@media (prefers-reduced-motion: reduce) {
	.btn-confirm.is-asking .btn-confirm-ask {
		animation: none;
	}
}
.btn-confirm.is-asking.btn {
	border-color: color-mix(in srgb, var(--basalt-danger) 76%, var(--basalt-copy));
	color: var(--basalt-plane);
	background-color: color-mix(in srgb, var(--basalt-danger) 76%, var(--basalt-copy));
}
.btn-confirm.is-asking::after {
	animation: btn-confirm-timer var(--btn-confirm-ms, 3000ms) linear forwards;
	/* The timeout still counts down; only the bar holds still. */
}
@media (prefers-reduced-motion: reduce) {
	.btn-confirm.is-asking::after {
		transform: scaleX(1);
		animation: none;
	}
}

@keyframes btn-confirm-timer {
	from {
		transform: scaleX(1);
	}
	to {
		transform: scaleX(0);
	}
}
.btn-confirm-icon:not(.is-asking) {
	width: calc(1.5em + 0.5rem + 2px);
	padding-left: 0;
	padding-right: 0;
}

/* A refresh button turns its arrow while the panel beside it reloads; the
   caller sets is-spinning and aria-busy for as long as that takes. */
.basalt-refresh .bi {
	display: inline-block;
}
.basalt-refresh.is-spinning {
	cursor: progress;
}
.basalt-refresh.is-spinning .bi {
	animation: basalt-turn 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-refresh.is-spinning .bi {
		animation-duration: 1.6s;
	}
}

@keyframes basalt-turn {
	to {
		transform: rotate(360deg);
	}
}
/* The bordered icon button card headers use for refresh and similar tools. */
.basalt-icon-btn {
	width: 2.25rem;
	height: 2.25rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 10px;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	display: inline-grid;
	place-items: center;
	flex-shrink: 0;
	transition:
		background-color 150ms ease,
		color 150ms ease,
		border-color 150ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-icon-btn {
		transition: none;
	}
}
.basalt-icon-btn:hover {
	border-color: var(--basalt-edge-strong);
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-icon-btn:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

/*
 * Dropdown menus that live inside the page content, plus every menu variant
 * that builds on them: the filter-as-you-type list, the multi-pick with chips,
 * the small form panel, rich two-line rows, the wide mega menu, nested
 * flyouts, the right-click menu and the two-step delete row. The
 * header menus are styled elsewhere. dropdowns.html shows them all;
 * basalt.js supplies the behavior behind the data-basalt-* hooks.
 */
/*
 * Bootstrap reads its menu from these --bs-dropdown-* knobs, so the look is
 * set by feeding it Basalt tokens rather than by overriding its rules.
 */
/*
 * The menu surface is padded and rounded, lifted on a two-step shadow, and
 * drops in by animating `translate` because Popper only ever writes
 * `transform`. Selected rows get a tint instead of a solid fill so their
 * label keeps its contrast under every palette.
 */
.basalt-stage .dropdown-menu {
	--bs-dropdown-font-size: 0.875rem;
	--bs-dropdown-color: var(--basalt-copy-body);
	--bs-dropdown-bg: var(--basalt-plane);
	--bs-dropdown-border-color: var(--basalt-edge-strong);
	--bs-dropdown-border-radius: 12px;
	--bs-dropdown-inner-border-radius: 11px;
	--bs-dropdown-padding-x: 0.3rem;
	--bs-dropdown-padding-y: 0.3rem;
	--bs-dropdown-divider-bg: var(--basalt-edge);
	--bs-dropdown-divider-margin-y: 0.3rem;
	--bs-dropdown-header-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-dropdown-header-padding-x: 0.7rem;
	--bs-dropdown-header-padding-y: 0.4rem;
	--bs-dropdown-item-padding-x: 0.7rem;
	--bs-dropdown-item-padding-y: 0.4rem;
	--bs-dropdown-link-color: var(--basalt-copy-body);
	--bs-dropdown-link-hover-color: var(--basalt-copy);
	--bs-dropdown-link-hover-bg: var(--basalt-wash);
	--bs-dropdown-link-active-color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
	--bs-dropdown-link-active-bg: var(--basalt-hue-soft);
	--bs-dropdown-link-disabled-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	min-width: 12rem;
	border-color: var(--bs-dropdown-border-color);
	color: var(--bs-dropdown-color);
	background-color: var(--bs-dropdown-bg);
	box-shadow:
		0 2px 6px color-mix(in srgb, var(--basalt-copy) 6%, transparent),
		0 14px 34px color-mix(in srgb, var(--basalt-copy) 12%, transparent);
}
.basalt-stage .dropdown-menu.show {
	animation: basalt-dd-in 170ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* A menu that opens upward rises into place instead of falling. */
.basalt-stage .dropup .dropdown-menu.show {
	animation-name: basalt-dd-in-up;
}

@keyframes basalt-dd-in {
	from {
		translate: 0 -6px;
		opacity: 0;
	}
}
@keyframes basalt-dd-in-up {
	from {
		translate: 0 6px;
		opacity: 0;
	}
}
/* Rows lay their icon and label out on one line with rounded hover pills. */
.basalt-stage .dropdown-item {
	display: flex;
	gap: 0.6rem;
	align-items: center;
	border-radius: 8px;
	font-weight: 500;
	color: var(--bs-dropdown-link-color);
}
.basalt-stage .dropdown-item:hover,
.basalt-stage .dropdown-item:focus {
	color: var(--bs-dropdown-link-hover-color);
	background-color: var(--bs-dropdown-link-hover-bg);
}
.basalt-stage .dropdown-item:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
}
.basalt-stage .dropdown-item:active,
.basalt-stage .dropdown-item.active {
	color: var(--bs-dropdown-link-active-color);
	background-color: var(--bs-dropdown-link-active-bg);
}
.basalt-stage .dropdown-item:disabled,
.basalt-stage .dropdown-item.disabled {
	color: var(--bs-dropdown-link-disabled-color);
	background: none;
}
.basalt-stage .dropdown-item > .bi:first-child {
	width: 1rem;
	text-align: center;
	opacity: 0.85;
}

/* Group headings are small caps labels; plain text rows keep the body ink. */
.basalt-stage .dropdown-header {
	margin: 0;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.055em;
	text-transform: uppercase;
}
.basalt-stage .dropdown-item-text {
	color: var(--basalt-copy-body);
}

/*
 * Destructive rows, including the two-step delete row, read red enough to
 * warn while staying dark enough to pass contrast.
 */
.basalt-stage .basalt-dd-danger,
.basalt-stage .dropdown-item-confirm {
	color: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
}
.basalt-stage .basalt-dd-danger:hover,
.basalt-stage .basalt-dd-danger:focus,
.basalt-stage .dropdown-item-confirm:hover,
.basalt-stage .dropdown-item-confirm:focus {
	color: color-mix(in srgb, var(--basalt-danger) 56%, var(--basalt-copy));
	background-color: color-mix(in srgb, var(--basalt-danger) 12%, var(--basalt-plane));
}

/* A toggle spaces its leading icon from the label and its caret from both. */
.basalt-stage .dropdown-toggle {
	display: inline-flex;
	align-items: center;
}
.basalt-stage .dropdown-toggle::after {
	margin-left: 0.5rem;
}
.basalt-stage .dropdown-toggle > .bi:first-child,
.basalt-stage .dropdown-toggle .bi + span {
	margin-right: 0.4rem;
}

.basalt-stage .dropdown-toggle-split::after {
	margin-left: 0;
}

/*
 * The two-step delete row swaps its idle label for a question on the first
 * press, turns solid and shakes once so the second press is deliberate.
 */
.dropdown-item-confirm-idle,
.dropdown-item-confirm.is-asking .dropdown-item-confirm-ask {
	display: inline-flex;
	gap: 0.6rem;
	align-items: center;
}

.dropdown-item-confirm-ask,
.dropdown-item-confirm.is-asking .dropdown-item-confirm-idle {
	display: none;
}

.basalt-stage .dropdown-item-confirm.is-asking,
.basalt-stage .dropdown-item-confirm.is-asking:hover,
.basalt-stage .dropdown-item-confirm.is-asking:focus {
	color: var(--basalt-plane);
	background-color: color-mix(in srgb, var(--basalt-danger) 76%, var(--basalt-copy));
	animation: basalt-dd-nudge 280ms ease;
}

@keyframes basalt-dd-nudge {
	30% {
		translate: -3px 0;
	}
	60% {
		translate: 3px 0;
	}
	100% {
		translate: 0 0;
	}
}
/* The searchable menu pins its field above a scrolling list. */
.basalt-stage .basalt-dd-search-menu {
	width: 17rem;
	padding: 0;
	overflow: hidden;
}

.basalt-dd-search-field {
	position: relative;
	padding: 0.5rem;
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-dd-search-field .bi {
	position: absolute;
	top: 50%;
	left: 1.1rem;
	translate: 0 -50%;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	pointer-events: none;
}

.basalt-dd-search-input.form-control {
	padding-left: 2rem;
}

.basalt-dd-search-list {
	max-height: 15rem;
	margin: 0;
	padding: 0.3rem;
	overflow-y: auto;
	list-style: none;
}

.basalt-dd-search-empty {
	margin: 0;
	padding: 1rem;
	font-size: 0.8rem;
	text-align: center;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/*
 * People rows carry an initials disc tinted from the chart series, a
 * presence dot on its corner and a check that shows on the current pick.
 */
.basalt-dd-avatar {
	--av-tone: var(--basalt-series-1);
	flex-shrink: 0;
	width: 1.9rem;
	height: 1.9rem;
	border-radius: 50%;
	font-size: 0.67rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: color-mix(in srgb, var(--av-tone) 45%, var(--basalt-copy));
	background: color-mix(in srgb, var(--av-tone) 18%, var(--basalt-plane));
	display: inline-grid;
	place-items: center;
	position: relative;
}

.basalt-dd-avatar-1 {
	--av-tone: var(--basalt-series-1);
}

.basalt-dd-avatar-2 {
	--av-tone: var(--basalt-series-2);
}

.basalt-dd-avatar-3 {
	--av-tone: var(--basalt-series-3);
}

.basalt-dd-avatar-4 {
	--av-tone: var(--basalt-series-4);
}

.basalt-dd-avatar-5 {
	--av-tone: var(--basalt-series-5);
}

.basalt-dd-avatar-6 {
	--av-tone: var(--basalt-series-6);
}

.basalt-dd-avatar-empty {
	--av-tone: var(--basalt-copy-muted);
	font-size: 0.85rem;
}

.basalt-dd-avatar-status {
	position: absolute;
	right: -1px;
	bottom: -1px;
	width: 0.6rem;
	height: 0.6rem;
	border-radius: 50%;
	border: 2px solid var(--basalt-plane);
	background: var(--basalt-copy-faint);
}

.basalt-dd-avatar-status-on {
	background: var(--basalt-success);
}

.basalt-dd-avatar-status-away {
	background: var(--basalt-warning);
}

.basalt-dd-person-text {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-width: 0;
	line-height: 1.25;
}

.basalt-dd-person-name {
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-dd-person-role {
	font-size: 0.75rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-dd-person-check {
	visibility: hidden;
	color: color-mix(in srgb, var(--basalt-hue) 62%, var(--basalt-copy));
}

.basalt-dd-person[aria-current="true"] .basalt-dd-person-check {
	visibility: visible;
}

.basalt-stage .basalt-dd-person[aria-current="true"] {
	background: var(--basalt-hue-soft);
}

/*
 * The multi-pick menu lists checkbox rows under a select-all row and ends in
 * a tinted footer; picks show as removable chips beside the trigger.
 */
.basalt-stage .basalt-dd-multi-menu {
	width: 15rem;
}
.basalt-stage .basalt-dd-multi-all,
.basalt-stage .basalt-dd-multi-option {
	margin: 0;
	cursor: pointer;
}
.basalt-stage .basalt-dd-multi-all {
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-dd-multi-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.basalt-dd-multi-all .form-check-input,
.basalt-dd-multi-option .form-check-input {
	flex-shrink: 0;
	margin: 0;
}

.basalt-dd-multi-foot {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	justify-content: space-between;
	margin: 0.3rem -0.35rem -0.35rem;
	padding: 0.5rem 0.6rem;
	border-top: 1px solid var(--basalt-edge);
	border-radius: 0 0 11px 11px;
	background: var(--basalt-canvas);
}

.basalt-dd-multi-count {
	min-width: 1.35rem;
	height: 1.35rem;
	margin-left: 0.5rem;
	padding: 0 0.3rem;
	border-radius: 999px;
	font-size: 0.71rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-on-hue);
	background: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	display: inline-grid;
	place-items: center;
}
.basalt-dd-multi-count[hidden] {
	display: none;
}

.basalt-dd-multi-chips {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	gap: 0.4rem;
	flex-wrap: wrap;
	min-height: 1.9rem;
}

.basalt-dd-multi-chip {
	display: inline-flex;
	gap: 0.1rem;
	align-items: center;
	padding: 0.1rem 0.2rem 0.1rem 0.65rem;
	border-radius: 999px;
	font-size: 0.8rem;
	font-weight: 600;
	color: color-mix(in srgb, var(--basalt-hue) 56%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
	animation: basalt-dd-in 170ms ease;
}
.basalt-dd-multi-chip button {
	width: 1.4rem;
	height: 1.4rem;
	border: 0;
	border-radius: 50%;
	font-size: 0.7rem;
	color: inherit;
	background: transparent;
	display: inline-grid;
	place-items: center;
}
.basalt-dd-multi-chip button:hover {
	background: color-mix(in srgb, var(--basalt-hue) 18%, transparent);
}
.basalt-dd-multi-chip button:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

.basalt-dd-multi-none {
	align-self: center;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* The form panel stacks a title bar, fieldsets and a right-aligned action footer. */
.basalt-stage .dropdown-menu.basalt-dd-panel {
	width: min(20rem, 100vw - 2rem);
	padding: 0;
}

.basalt-dd-panel-head {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	justify-content: space-between;
	padding: 0.75rem 0.75rem 0.5rem 1rem;
}

.basalt-dd-panel-title {
	margin: 0;
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-dd-panel-body {
	display: flex;
	gap: 1rem;
	flex-direction: column;
	padding: 0.25rem 1rem 1rem;
}

.basalt-dd-panel-group {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

.basalt-dd-panel-label {
	float: none;
	margin: 0 0 0.4rem;
	padding: 0;
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-dd-panel .form-check-label {
	color: var(--basalt-copy-body);
}

.basalt-dd-panel-foot {
	display: flex;
	gap: 0.5rem;
	justify-content: flex-end;
	padding: 0.7rem 1rem;
	border-top: 1px solid var(--basalt-edge);
	border-radius: 0 0 11px 11px;
	background: var(--basalt-canvas);
}

/*
 * Rich rows pair a tinted icon tile with a title, a hint line and an
 * optional shortcut key.
 */
.basalt-stage .basalt-dd-item {
	gap: 0.75rem;
	align-items: center;
	padding: 0.5rem 0.6rem;
}

.basalt-dd-item-icon {
	--item-tone: var(--basalt-hue);
	flex-shrink: 0;
	width: 2.1rem;
	height: 2.1rem;
	border-radius: 9px;
	color: color-mix(in srgb, var(--item-tone) 70%, var(--basalt-copy));
	background: color-mix(in srgb, var(--item-tone) 14%, var(--basalt-plane));
	display: inline-grid;
	place-items: center;
}

.basalt-dd-item-icon-1 {
	--item-tone: var(--basalt-series-1);
}

.basalt-dd-item-icon-2 {
	--item-tone: var(--basalt-series-2);
}

.basalt-dd-item-icon-3 {
	--item-tone: var(--basalt-series-3);
}

.basalt-dd-item-icon-4 {
	--item-tone: var(--basalt-series-4);
}

.basalt-dd-item-text {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-width: 0;
	line-height: 1.3;
	white-space: normal;
}

.basalt-dd-item-title {
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-dd-item-sub {
	font-size: 0.76rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-dd-item-kbd {
	flex-shrink: 0;
	padding: 0.12rem 0.4rem;
	border-radius: 5px;
	border: 1px solid var(--basalt-edge-strong);
	font:
		600 0.67rem/1.2 "Chivo Mono",
		monospace;
	color: var(--basalt-copy-body);
	background: var(--basalt-canvas);
	box-shadow: none;
}

.basalt-stage .basalt-dd-rich {
	width: min(20rem, 100vw - 2rem);
}

/* The mega menu opens as three columns, the last a featured card, and stacks on phones. */
.basalt-stage .dropdown-menu.basalt-dd-mega {
	width: min(44rem, 100vw - 2rem);
	padding: 0.6rem;
}

.basalt-dd-mega.show {
	display: grid;
	gap: 0.3rem;
	grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 767.98px) {
	.basalt-dd-mega.show {
		grid-template-columns: 1fr;
	}
}

.basalt-dd-mega-col ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.basalt-dd-mega-feature {
	display: flex;
	gap: 0.3rem;
	flex-direction: column;
	padding: 1rem;
	border-radius: 10px;
	border: 1px solid var(--basalt-edge);
	font-size: 0.8rem;
	line-height: 1.45;
	text-decoration: none;
	color: var(--basalt-copy-body);
	background: var(--basalt-grad-soft);
}
.basalt-dd-mega-feature:hover {
	border-color: color-mix(in srgb, var(--basalt-hue) 45%, transparent);
	color: var(--basalt-copy-body);
}
.basalt-dd-mega-feature:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

.basalt-dd-mega-eyebrow {
	font-size: 0.67rem;
	font-weight: 700;
	letter-spacing: 0.055em;
	text-transform: uppercase;
	color: var(--basalt-copy-body);
}

.basalt-dd-mega-title {
	font-size: 1rem;
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-dd-mega-more {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	margin-top: auto;
	padding-top: 0.5rem;
	font-weight: 600;
	color: color-mix(in srgb, var(--basalt-hue) 58%, var(--basalt-copy));
}

/*
 * A nested flyout opens beside its parent row, lines its first row up with
 * that row, and moves to the left side when basalt.js marks it flipped.
 */
.basalt-stage .dropdown-submenu-toggle::after {
	content: "\f285";
	margin-left: auto;
	padding-left: 1rem;
	border: 0;
	font-family: "bootstrap-icons";
	font-size: 0.7rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-stage .dropdown-submenu-toggle[aria-expanded="true"] {
	color: var(--bs-dropdown-link-hover-color);
	background-color: var(--bs-dropdown-link-hover-bg);
}

.dropdown-submenu {
	position: relative;
}
.dropdown-submenu > .dropdown-menu {
	position: absolute;
	top: calc(var(--bs-dropdown-padding-y, 0.3rem) * -1 - 1px);
	left: calc(100% + 0.3rem);
	margin: 0;
}
.dropdown-submenu.is-flipped > .dropdown-menu {
	right: calc(100% + 0.3rem);
	left: auto;
}
.dropdown-submenu > .dropdown-menu.show {
	display: block;
}

/* The right-click menu is placed at the pointer, above sticky page chrome. */
.basalt-stage .dropdown-menu.basalt-context-menu {
	position: fixed;
	z-index: 1060;
}

/* Without motion, menus, chips and the delete row simply appear. */
@media (prefers-reduced-motion: reduce) {
	.basalt-stage .dropdown-menu.show,
	.basalt-dd-multi-chip,
	.basalt-stage .dropdown-item-confirm.is-asking {
		animation: none;
	}
}
/* .basalt-command is a search field over grouped results that answers to the
   arrow keys and Enter and marks the matching letters. The same block stands
   alone on a page, sits inside a dropdown (.dropdown-menu.basalt-command-menu
   around .basalt-command-as-menu) or fills a dialog (.modal.basalt-modal-command).
   A result either stacks a title over a second line (-text holding -title and
   -sub, followed by a -kbd) or shows one label with a hint at the end (-label
   and -hint). [data-basalt-command] in basalt.js runs it; dropdowns.html
   and modals.html show it. */
/* Secondary text everywhere in the menu mixes the muted token toward the body
   color so it stays readable on every palette. */
.basalt-command {
	display: flex;
	flex-direction: column;
	min-width: 0;
	border-radius: 14px;
	border: 1px solid var(--basalt-edge-strong);
	overflow: hidden;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	box-shadow:
		0 2px 6px color-mix(in srgb, var(--basalt-copy) 5%, transparent),
		0 18px 40px color-mix(in srgb, var(--basalt-copy) 10%, transparent);
}
.basalt-command:focus-within {
	border-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
}
.basalt-command {
	/* Matched letters get a soft highlighter stroke. */
}
.basalt-command mark {
	padding: 0 0.05em;
	border-radius: 3px;
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-warning) 30%, transparent);
}

/* The search row carries the focus cue as an underline, so the field inside
   it drops its own ring. */
.basalt-command-search {
	display: flex;
	gap: 0.7rem;
	align-items: center;
	padding: 0.85rem 1.1rem;
	border-bottom: 1px solid var(--basalt-edge);
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	transition: box-shadow 170ms ease;
}
.basalt-command-search > .bi {
	font-size: 1.05rem;
}
.basalt-command-search:focus-within {
	box-shadow: inset 0 -2px 0 var(--basalt-hue);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-command-search {
		transition: none;
	}
}

.basalt-command-input {
	flex: 1 1 auto;
	min-width: 0;
	padding: 0.2rem 0;
	border: 0;
	outline: 0;
	font-size: 1rem;
	color: var(--basalt-copy);
	background: transparent;
}
.basalt-command-input::placeholder {
	color: color-mix(in srgb, var(--basalt-copy-muted) 80%, var(--basalt-copy));
	opacity: 1;
}
.basalt-command-input:focus-visible {
	outline: 0;
	box-shadow: none;
}

/* Results scroll inside the box and never hand the scroll to the page. */
.basalt-command-list {
	scroll-padding: 0.4rem;
	max-height: var(--basalt-command-height, 22rem);
	padding: 0.4rem;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.basalt-command-group + .basalt-command-group {
	margin-top: 0.3rem;
}

.basalt-command-group[hidden],
.basalt-command-item[hidden] {
	display: none;
}

.basalt-command-heading {
	padding: 0.5rem 0.7rem 0.3rem;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.055em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* The active result is tinted and gets a short bar on its leading edge. */
.basalt-command-item {
	position: relative;
	display: flex;
	gap: 0.75rem;
	align-items: center;
	padding: 0.5rem 0.7rem;
	border-radius: 10px;
	color: var(--basalt-copy-body);
	cursor: pointer;
}
.basalt-command-item[aria-selected="true"] {
	color: var(--basalt-copy);
	background: var(--basalt-hue-soft);
}
.basalt-command-item[aria-selected="true"]::before {
	content: "";
	position: absolute;
	top: 22%;
	bottom: 22%;
	left: 0;
	width: 3px;
	border-radius: 3px;
	background: var(--basalt-hue);
}

/* Icon tiles take their tint from --cmd-tone; the modifiers only repoint it. */
.basalt-command-icon {
	--cmd-tone: var(--basalt-copy-muted);
	display: inline-grid;
	flex-shrink: 0;
	place-items: center;
	width: 2rem;
	height: 2rem;
	border-radius: 9px;
	font-size: 0.95rem;
	color: color-mix(in srgb, var(--cmd-tone) 70%, var(--basalt-copy));
	background: color-mix(in srgb, var(--cmd-tone) 14%, var(--basalt-plane));
}

.basalt-command-icon-primary {
	--cmd-tone: var(--basalt-hue);
}

.basalt-command-icon-warm {
	--cmd-tone: var(--basalt-series-5);
}

.basalt-command-icon-fresh {
	--cmd-tone: var(--basalt-series-3);
}

/* Two-line results: a title over a line that truncates. */
.basalt-command-text {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-width: 0;
	line-height: 1.3;
}

.basalt-command-title {
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-command-sub {
	overflow: hidden;
	font-size: 0.77rem;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* One-line results: a label that truncates and a hint pinned to the end,
   which phones leave out. */
.basalt-command-label {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	font-size: 0.9rem;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--basalt-copy);
}

.basalt-command-hint {
	flex-shrink: 0;
	font-size: 0.75rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-command-item[aria-selected="true"] .basalt-command-hint {
	color: var(--basalt-copy-body);
}
@media (max-width: 575.98px) {
	.basalt-command-hint {
		display: none;
	}
}

/* Every key cap in the menu, from a result's shortcut to the footer legend,
   shares one look. */
.basalt-command-kbd,
.basalt-command-esc,
.basalt-command-foot kbd {
	flex-shrink: 0;
	padding: 0.1rem 0.4rem;
	border-radius: 5px;
	border: 1px solid var(--basalt-edge-strong);
	font:
		600 0.67rem/1.2 "Chivo Mono",
		monospace;
	color: var(--basalt-copy-body);
	background: var(--basalt-canvas);
	box-shadow: none;
}

.basalt-command-empty {
	padding: 2rem 1rem;
	font-size: 0.875rem;
	text-align: center;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-command-empty[hidden] {
	display: none;
}
.basalt-command-empty .bi {
	display: block;
	margin-bottom: 0.4rem;
	font-size: 1.4rem;
}
.basalt-command-empty p {
	margin: 0;
}

/* The footer legend keeps only the result count on a phone. */
.basalt-command-foot {
	display: flex;
	gap: 0.4rem 1.1rem;
	flex-wrap: wrap;
	align-items: center;
	padding: 0.6rem 1.1rem;
	border-top: 1px solid var(--basalt-edge);
	font-size: 0.75rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: var(--basalt-canvas);
}
.basalt-command-foot span {
	display: inline-flex;
	gap: 0.25rem;
	align-items: center;
}
@media (max-width: 575.98px) {
	.basalt-command-foot span:not(.basalt-command-count) {
		display: none;
	}
}

.basalt-command-count {
	margin-left: auto;
	font-variant-numeric: tabular-nums;
}

/* A fixed-height box holds still while results come and go, which suits a
   dialog; --basalt-command-height sets the size. */
.basalt-command-fixed .basalt-command-list,
.basalt-modal-command .basalt-command-list {
	height: var(--basalt-command-height, 360px);
	max-height: none;
}

.basalt-command-fixed .basalt-command-empty,
.basalt-modal-command .basalt-command-empty {
	display: flex;
	gap: 0.5rem;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	height: var(--basalt-command-height, 360px);
}
.basalt-command-fixed .basalt-command-empty[hidden],
.basalt-modal-command .basalt-command-empty[hidden] {
	display: none;
}

/* In a dropdown the menu itself is the frame, so the box sheds its own. */
.basalt-stage .dropdown-menu.basalt-command-menu {
	width: min(24rem, 100vw - 2rem);
	padding: 0;
	overflow: hidden;
}

.basalt-command-as-menu {
	border: 0;
	border-radius: 0;
	box-shadow: none;
}
.basalt-command-as-menu .basalt-command-list {
	max-height: 16rem;
}

/* In a dialog the box sits high on the screen and the modal supplies the
   chrome; phones pull it up further and cap its height. */
.basalt-modal-command .modal-dialog {
	max-width: 620px;
	margin-top: min(12vh, 7rem);
}
.basalt-modal-command .modal-content {
	overflow: hidden;
}
.basalt-modal-command .basalt-command {
	border: 0;
	border-radius: inherit;
	box-shadow: none;
}
@media (max-width: 575.98px) {
	.basalt-modal-command .modal-dialog {
		margin-top: 0.75rem;
	}
	.basalt-modal-command .basalt-command {
		--basalt-command-height: min(360px, 55vh);
	}
}

/* Bootstrap's toned .alert, restyled for every page. The richer
   .basalt-alert layouts, banners and alert groups are in _alert-types.scss
   and load only where a page uses them. */
/* Bootstrap's own .alert, rebuilt on a single tone per color. Its text is the
   tone met halfway by the body copy, which keeps 4.5:1 on the tinted fill in
   every palette where the bare status color would not. */
.alert {
	--basalt-alert-tone: var(--basalt-hue);
	--basalt-alert-ink: color-mix(in srgb, var(--basalt-alert-tone) 50%, var(--basalt-copy));
	--basalt-alert-tint: color-mix(in srgb, var(--basalt-alert-tone) 9%, var(--basalt-plane));
	--bs-alert-bg: var(--basalt-alert-tint);
	--bs-alert-color: var(--basalt-alert-ink);
	--bs-alert-border-color: color-mix(in srgb, var(--basalt-alert-tone) 30%, var(--basalt-plane));
	--bs-alert-link-color: var(--basalt-alert-ink);
	--bs-alert-border-radius: 12px;
	font-size: 0.9rem;
	line-height: 1.5;
}
.alert .alert-heading {
	margin-bottom: 0.4rem;
	font-size: 1rem;
	font-weight: 650;
}
.alert hr {
	margin: 0.85rem 0;
	border-color: currentColor;
	opacity: 0.2;
}
.alert .alert-link {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}
.alert > ul {
	padding-left: 1.2rem;
}

/* The color classes only pick the tone; secondary borrows muted copy. */
.alert.alert-primary {
	--basalt-alert-tone: var(--basalt-hue);
}

.alert.alert-success {
	--basalt-alert-tone: var(--basalt-success);
}

.alert.alert-danger {
	--basalt-alert-tone: var(--basalt-danger);
}

.alert.alert-warning {
	--basalt-alert-tone: var(--basalt-warning);
}

.alert.alert-info {
	--basalt-alert-tone: var(--basalt-flare);
}

.alert.alert-secondary {
	--basalt-alert-tone: var(--basalt-copy-muted);
}

/* Light trades the tint for the quiet alternate surface. */
.alert.alert-light {
	--basalt-alert-tone: var(--basalt-copy-muted);
	--bs-alert-bg: var(--basalt-plane-alt);
	--bs-alert-color: var(--basalt-copy-body);
	--bs-alert-border-color: var(--basalt-edge);
	--bs-alert-link-color: var(--basalt-copy);
}

/* Dark flips the page around: dark on a light theme, light on a dark one. */
.alert.alert-dark {
	--basalt-alert-tone: var(--basalt-copy);
	--basalt-alert-ink: var(--basalt-plane);
	--bs-alert-bg: var(--basalt-copy);
	--bs-alert-color: var(--basalt-plane);
	--bs-alert-border-color: var(--basalt-copy);
	--bs-alert-link-color: var(--basalt-plane);
}

/* Pop-up notifications: Bootstrap's plain .toast on the palette, the richer
   .basalt-notice card, and the floating pile that stacks them. toasts.html
   shows each one; Basalt.toasts in basalt.js builds and runs the pile. */
/* Secondary text in a toast is muted copy pulled toward full copy. */
/* A solid keyboard outline in the given color, set off the element. */
/* Out of the box a Bootstrap toast is translucent white with gray text. Each
   of its variables is pointed at a palette token here, so untouched Bootstrap
   markup follows the theme in light and dark alike. */
.toast {
	--bs-toast-bg: var(--basalt-plane);
	--bs-toast-color: var(--basalt-copy-body);
	--bs-toast-border-color: var(--basalt-edge);
	--bs-toast-border-radius: 12px;
	--bs-toast-box-shadow:
		var(--basalt-card-shadow), 0 14px 34px -18px color-mix(in srgb, var(--basalt-copy) 45%, transparent);
	--bs-toast-header-bg: color-mix(in srgb, var(--basalt-plane-alt) 55%, var(--basalt-plane));
	--bs-toast-header-color: var(--basalt-copy);
	--bs-toast-header-border-color: var(--basalt-edge);
	--bs-toast-font-size: 0.86rem;
	--bs-toast-max-width: 360px;
	--bs-toast-padding-x: 0.85rem;
	--bs-toast-padding-y: 0.6rem;
	/* Dark copy is light, so in dark mode the drop shadow is cast from the
      page color instead. */
}
[data-bs-theme="dark"] .toast {
	--bs-toast-box-shadow:
		var(--basalt-card-shadow), 0 16px 36px -14px color-mix(in srgb, var(--basalt-canvas) 92%, transparent);
}

.toast-header strong {
	font-weight: 650;
}
.toast-header small {
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.toast-body {
	line-height: 1.5;
}

.toast .border-top {
	border-color: var(--basalt-edge);
}

/* .basalt-notice is a toast laid out as an icon or avatar tile beside a
   title, timestamp, message and action row, with an optional close button
   in the corner and a countdown bar the pile adds along the bottom. It works
   alone (with Bootstrap's .toast and .show) or inside the pile. One tone
   variable colors it; the -message and -bar forms change its shape. */
.toast.basalt-notice {
	--basalt-toast-tone: var(--basalt-hue);
	--basalt-toast-ink: color-mix(in srgb, var(--basalt-toast-tone) 50%, var(--basalt-copy));
	--bs-toast-max-width: 24rem;
	position: relative;
	width: 100%;
	border-radius: 14px;
	overflow: hidden;
	color: var(--basalt-copy-body);
}

/* Each tone class swaps the tone token, and every status tone also draws a
   thin stripe of its color down the leading edge. */
.basalt-notice-info::before,
.basalt-notice-danger::before,
.basalt-notice-warning::before,
.basalt-notice-success::before {
	content: "";
	position: absolute;
	inset: 0 auto 0 0;
	width: 3px;
	background: var(--basalt-toast-tone);
}

.toast.basalt-notice-success {
	--basalt-toast-tone: var(--basalt-success);
}

.toast.basalt-notice-warning {
	--basalt-toast-tone: var(--basalt-warning);
}

.toast.basalt-notice-danger {
	--basalt-toast-tone: var(--basalt-danger);
}

.toast.basalt-notice-info {
	--basalt-toast-tone: var(--basalt-flare);
}

.toast.basalt-notice-busy {
	--basalt-toast-tone: var(--basalt-hue);
}

/* Tile on the left, text on the right; a close button reserves its corner. */
.basalt-notice:not(.basalt-notice-piled),
.basalt-notice-wrap {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: start;
	padding: 0.85rem 1rem;
}

.basalt-notice:has(.basalt-notice-dismiss):not(.basalt-notice-piled),
.basalt-notice-wrap:has(.basalt-notice-dismiss) {
	padding-right: 2.75rem;
}

/* The tile is a tinted rounded square holding an icon; a person's initials
   sit in a slightly larger circle instead. */
.basalt-notice-mark,
.basalt-notice-face {
	display: inline-grid;
	place-items: center;
	width: 2rem;
	height: 2rem;
	border-radius: 9px;
	font-size: 0.95rem;
	color: var(--basalt-toast-ink);
	background: color-mix(in srgb, var(--basalt-toast-tone) 16%, var(--basalt-plane));
}

.basalt-notice-face {
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 50%;
	font-size: 0.74rem;
	font-weight: 700;
	letter-spacing: 0.03em;
}

/* While work is under way the icon gives place to a spinning ring, which
   slows right down for visitors who ask for less motion. */
.basalt-notice-busy .basalt-notice-mark .bi {
	display: none;
}
.basalt-notice-busy .basalt-notice-mark::before {
	content: "";
	width: 1rem;
	height: 1rem;
	border-radius: 50%;
	border: 2px solid currentColor;
	border-right-color: transparent;
	animation: basalt-toast-spin 700ms linear infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-notice-busy .basalt-notice-mark::before {
		animation-duration: 2s;
	}
}

@keyframes basalt-toast-spin {
	to {
		transform: rotate(360deg);
	}
}
/* The text column: a bold title with its time beside it, then the message. */
.basalt-notice-content {
	align-self: center;
	min-width: 0;
}

.basalt-notice-head {
	margin: 0;
	font-size: 0.88rem;
	font-weight: 650;
	line-height: 1.35;
	color: var(--basalt-copy);
}

.basalt-notice-when {
	margin-left: 0.3rem;
	font-size: 0.75rem;
	font-weight: 400;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-notice-msg {
	margin: 0;
	font-size: 0.84rem;
	line-height: 1.45;
}
.basalt-notice-head + .basalt-notice-msg {
	margin-top: 0.1rem;
}

/* Actions wrap in a row under the text. The main one is a solid ink button,
   and the quiet one is outlined on a clear ground. */
.basalt-notice-acts {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	margin-top: 0.7rem;
}

.basalt-notice-action {
	--bs-btn-color: var(--basalt-plane);
	--bs-btn-bg: var(--basalt-copy);
	--bs-btn-border-color: var(--basalt-copy);
	--bs-btn-hover-color: var(--basalt-plane);
	--bs-btn-hover-bg: color-mix(in srgb, var(--basalt-copy) 84%, var(--basalt-plane));
	--bs-btn-hover-border-color: color-mix(in srgb, var(--basalt-copy) 84%, var(--basalt-plane));
	--bs-btn-active-color: var(--basalt-plane);
	--bs-btn-active-bg: color-mix(in srgb, var(--basalt-copy) 76%, var(--basalt-plane));
	--bs-btn-active-border-color: color-mix(in srgb, var(--basalt-copy) 76%, var(--basalt-plane));
	--bs-btn-font-weight: 600;
	--bs-btn-padding-y: 0.2rem;
	--bs-btn-padding-x: 0.65rem;
	white-space: nowrap;
}
.basalt-notice-action:focus-visible {
	box-shadow: none;
	outline: 2px solid var(--basalt-copy);
	outline-offset: 2px;
}

.basalt-notice-action-quiet {
	--bs-btn-color: var(--basalt-copy-body);
	--bs-btn-bg: transparent;
	--bs-btn-border-color: var(--basalt-edge-strong);
	--bs-btn-hover-color: var(--basalt-copy);
	--bs-btn-hover-bg: var(--basalt-wash);
	--bs-btn-hover-border-color: var(--basalt-edge-strong);
	--bs-btn-active-color: var(--basalt-copy);
	--bs-btn-active-bg: var(--basalt-wash);
	--bs-btn-active-border-color: var(--basalt-copy-muted);
}

/* The close button floats in the top right corner above the content. */
.basalt-notice-dismiss {
	position: absolute;
	top: 0.5rem;
	right: 0.5rem;
	z-index: 1;
	display: inline-grid;
	place-items: center;
	width: 1.9rem;
	height: 1.9rem;
	padding: 0;
	border: 0;
	border-radius: 8px;
	font-size: 0.77rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: transparent;
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
.basalt-notice-dismiss:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-notice-dismiss:focus-visible {
	outline: 2px solid var(--basalt-copy);
	outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-notice-dismiss {
		transition: none;
	}
}

/* The countdown bar shrinks from the right as time runs out, and fades
   back while the visitor holds the toast open. */
.basalt-notice-timer {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	transform-origin: left center;
	transform: scaleX(var(--basalt-toast-left, 1));
	height: 3px;
	background: var(--basalt-toast-ink);
	opacity: 0.75;
}
.basalt-notice.is-paused .basalt-notice-timer {
	opacity: 0.35;
}

/* The message form adds a reply field below the text, and can list line
   items with a ruled total at the bottom. */
.basalt-notice-answer {
	display: flex;
	gap: 0.4rem;
	margin-top: 0.65rem;
}
.basalt-notice-answer .form-control {
	min-width: 0;
}

.basalt-notice-copy {
	margin: 0.5rem 0 0;
	padding: 0;
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	list-style: none;
}
.basalt-notice-copy li {
	display: flex;
	gap: 1rem;
	justify-content: space-between;
	padding: 0.1rem 0;
}
.basalt-notice-copy .basalt-notice-sum {
	margin-top: 0.3rem;
	padding-top: 0.4rem;
	border-top: 1px solid var(--basalt-edge);
	font-weight: 600;
	color: var(--basalt-copy);
}

/* The snackbar flips to the inverse of the page and holds a single line
   with one uppercase text action. */
.toast.basalt-notice-bar {
	--bs-toast-bg: var(--basalt-copy);
	--bs-toast-border-color: var(--basalt-copy);
	display: flex;
	gap: 0.75rem;
	align-items: center;
	padding: 0.7rem 0.8rem 0.7rem 1rem;
	color: var(--basalt-plane);
}

.basalt-notice-bar .basalt-notice-msg {
	flex: 1 1 auto;
	color: var(--basalt-plane);
}
.basalt-notice-bar .basalt-notice-mark {
	width: auto;
	height: auto;
	color: var(--basalt-plane);
	background: none;
}

.basalt-notice-anchor {
	flex-shrink: 0;
	padding: 0.25rem 0.5rem;
	border: 0;
	border-radius: 6px;
	font-size: 0.8rem;
	font-weight: 700;
	letter-spacing: 0.035em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-hue) 30%, var(--basalt-plane));
	background: transparent;
	cursor: pointer;
}
.basalt-notice-anchor:hover {
	background: color-mix(in srgb, var(--basalt-plane) 12%, transparent);
}
.basalt-notice-anchor:focus-visible {
	outline: 2px solid var(--basalt-plane);
	outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-notice-anchor {
		transition: none;
	}
}

/* The pile is the fixed corner region the script builds. Toasts lie on top
   of one another: while it is closed the older ones tuck in behind the
   newest (the script sets --y and --s on each), and hovering or focusing it
   adds .is-open, which spreads them out. It sits bottom-end unless a
   -bottom-center, -top-end or -top-center class moves it. */
.basalt-notice-pile {
	position: fixed;
	/* The script steers the pile around an open drawer or dialog. Its
      --basalt-toast-avoid shifts it left of the panel, --basalt-toast-w
      narrows it to the space beside one, and --basalt-toast-lift raises it
      over the panel's footer buttons. */
	right: calc(1.25rem + var(--basalt-toast-avoid, 0px));
	bottom: calc(1.25rem + var(--basalt-toast-lift, 0px));
	z-index: 1090;
	width: var(--basalt-toast-w, min(24rem, 100vw - 2.5rem));
	pointer-events: none;
	/* Floating over anything, a toast needs the stronger edge to stand out. */
}
.basalt-notice-pile .toast {
	--bs-toast-border-color: var(--basalt-edge-strong);
}

.basalt-notice-pile-bottom-center,
.basalt-notice-pile-top-center {
	right: auto;
	left: 50%;
	transform: translateX(-50%);
}

.basalt-notice-pile-top-end,
.basalt-notice-pile-top-center {
	top: 1.25rem;
	bottom: auto;
}

.basalt-notice-pile-items {
	position: relative;
	height: var(--basalt-stack-h, 0);
	transition: height 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-notice-pile-items:not(:empty) {
	pointer-events: auto;
}

/* Inside the pile each toast is pinned to the bottom (or the top, for the
   top positions) and slides and scales to the place the script gives it. */
.basalt-notice-pile .basalt-notice {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	transform: translateY(var(--y, 0)) scale(var(--s, 1));
	transform-origin: center bottom;
	height: var(--basalt-toast-h, auto);
	transition:
		transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
		opacity 320ms ease,
		height 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.basalt-notice-pile-top-end .basalt-notice,
.basalt-notice-pile-top-center .basalt-notice {
	top: 0;
	bottom: auto;
	transform-origin: center top;
}

.basalt-notice-pile .basalt-notice-wrap {
	transition: opacity 200ms ease;
}
.basalt-notice-pile .basalt-notice.is-behind .basalt-notice-wrap {
	opacity: 0;
}
.basalt-notice-pile .basalt-notice.is-gone {
	opacity: 0;
	pointer-events: none;
}

/* A new toast rises in from below (drops in from above at the top), and a
   closing one slides out to the side, or shrinks away when centered. */
.basalt-notice-pile .basalt-notice.is-entering {
	transform: translateY(calc(var(--y, 0px) + 1.5rem)) scale(0.96);
	opacity: 0;
}

.basalt-notice-pile-top-end .basalt-notice.is-entering,
.basalt-notice-pile-top-center .basalt-notice.is-entering {
	transform: translateY(calc(var(--y, 0px) - 1.5rem)) scale(0.96);
}

.basalt-notice-pile .basalt-notice.is-leaving {
	transform: translateX(110%);
	opacity: 0;
}

.basalt-notice-pile-bottom-center .basalt-notice.is-leaving,
.basalt-notice-pile-top-center .basalt-notice.is-leaving {
	transform: translateY(var(--y, 0)) scale(0.9);
}

.basalt-notice-pile .basalt-notice:focus-visible {
	outline: 2px solid var(--basalt-copy);
	outline-offset: 2px;
}

/* Under reduced motion the pile jumps straight to each new layout. */
@media (prefers-reduced-motion: reduce) {
	.basalt-notice-pile-items,
	.basalt-notice-pile .basalt-notice,
	.basalt-notice-pile .basalt-notice-wrap {
		transition: none;
	}
}
/* Phones pull the pile closer to the screen edges and let it run nearly
   full width. */
@media (max-width: 575.98px) {
	.basalt-notice-pile {
		right: calc(0.75rem + var(--basalt-toast-avoid, 0px));
		bottom: calc(0.75rem + var(--basalt-toast-lift, 0px));
		width: var(--basalt-toast-w, calc(100vw - 1.5rem));
	}
	.basalt-notice-pile-top-end,
	.basalt-notice-pile-top-center {
		top: 0.75rem;
	}
}
/* Notifications have no place on paper. */
@media print {
	.basalt-notice-pile {
		display: none;
	}
}
/*
 * Corrections to Bootstrap's stock badges, followed by the badge family the
 * template adds: dot labels, trends, corner counters, toggles, a status pill
 * with its own menu, removable filters and soft count pills. badges.html
 * shows them in that order. basalt.js powers [data-basalt-removables],
 * [data-basalt-status-menu] and Basalt.count; --basalt-shade, the dark
 * end that solid fills mix toward, comes from the palette bridge.
 */
/* Secondary text leans toward the body color so it keeps 4.5:1. */
/* Pills that change tone on hover or press fade fill, text and edge together. */
/* The semantic tones a --tone driven badge can take; with none it stays neutral. */
/* Every pressable badge part answers focus with the same hue outline. */
/* Visitors who asked for less motion get the end state straight away. */
/* Bootstrap's .text-bg-* fix the text at white, so the fill is darkened
   instead: toward the text color in light mode, the page color in dark. */
.text-bg-primary {
	--basalt-hue: color-mix(in srgb, var(--bs-primary) 80%, var(--basalt-copy));
}
[data-bs-theme="dark"] .text-bg-primary {
	--basalt-hue: var(--bs-primary);
}

.text-bg-success {
	--basalt-success: color-mix(in srgb, var(--bs-success) 58%, var(--basalt-shade));
}
[data-bs-theme="dark"] .text-bg-success {
	--basalt-success: color-mix(in srgb, var(--bs-success) 50%, var(--basalt-shade));
}

.text-bg-danger {
	--basalt-danger: color-mix(in srgb, var(--bs-danger) 70%, var(--basalt-shade));
}

.text-bg-warning {
	--basalt-warning: color-mix(in srgb, var(--bs-warning) 88%, var(--basalt-plane));
}

.text-bg-info {
	--basalt-flare: color-mix(in srgb, var(--bs-info) 88%, var(--basalt-plane));
}

/* Inside a heading a badge or count pill grows with the text, as Bootstrap
   means it to, even though .badge is pinned small for tables. Middle
   alignment lands it on the x-height and the em-based lift moves it up to
   the middle of the capitals, so every heading level lines up the same. */
:is(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6, .basalt-hero-title, .card-title)
	> :is(.badge, .basalt-count-pill) {
	translate: 0 -0.14em;
	font-size: 0.62em;
	vertical-align: middle;
}

.btn > .badge {
	margin-left: 0.3rem;
	font-size: 0.72em;
	vertical-align: 0.08em;
}

/* A dot label is an outlined neutral badge whose colored dot is only a hint
   of category; the numbered tones follow the chart series. */
.badge.basalt-badge-as-dot {
	--dot: var(--basalt-copy-muted);
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	padding: 0.3em 0.65em;
	border: 1px solid var(--basalt-edge-strong);
	font-weight: 600;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
}
.badge.basalt-badge-as-dot::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--dot);
}

.basalt-badge-tone-1 {
	--dot: var(--basalt-series-1);
}

.basalt-badge-tone-2 {
	--dot: var(--basalt-series-2);
}

.basalt-badge-tone-3 {
	--dot: var(--basalt-series-3);
}

.basalt-badge-tone-4 {
	--dot: var(--basalt-series-4);
}

.basalt-badge-tone-5 {
	--dot: var(--basalt-series-5);
}

.basalt-badge-tone-6 {
	--dot: var(--basalt-series-6);
}

.basalt-badge-tone-7 {
	--dot: var(--basalt-series-7);
}

.basalt-badge-tone-8 {
	--dot: var(--basalt-series-8);
}

.badge.basalt-badge-as-dot.basalt-badge-lg {
	font-size: 0.8rem;
}

/* A trend reports change since the last period. The direction picks the
   arrow tone, and --invert flips it for figures where lower is better. */
.basalt-trend {
	--tone: var(--basalt-copy-muted);
	display: inline-flex;
	gap: 0.2rem;
	align-items: center;
	padding: 0.1rem 0.4rem;
	border-radius: 6px;
	font-weight: 700;
	font-size: 0.74rem;
	line-height: 1.35;
	white-space: nowrap;
	color: color-mix(in srgb, var(--tone) 50%, var(--basalt-copy));
	background: color-mix(in srgb, var(--tone) 13%, transparent);
}
.basalt-trend .bi {
	font-size: 0.9em;
}

.basalt-trend-up,
.basalt-trend-down.basalt-trend-invert {
	--tone: var(--basalt-success);
}

.basalt-trend-down,
.basalt-trend-up.basalt-trend-invert {
	--tone: var(--basalt-danger);
}

.basalt-trend-flat {
	--tone: var(--basalt-copy-muted);
}

[data-bs-theme="dark"] .basalt-trend {
	color: color-mix(in srgb, var(--tone) 60%, var(--basalt-copy));
}

/* A counter pins to the corner of whatever .basalt-count-host wraps. It
   tops out at 99+, shrinks to a bare dot for "something new", and
   Basalt.count(el, n) updates it with a short bump. */
.basalt-count-host {
	position: relative;
	display: inline-flex;
}

.basalt-count {
	--tone: var(--basalt-danger);
	position: absolute;
	top: 0;
	right: 0;
	transform: translate(40%, -40%);
	display: inline-grid;
	place-items: center;
	min-width: 1.25rem;
	height: 1.25rem;
	padding: 0 0.3rem;
	border-radius: 999px;
	font-weight: 700;
	font-size: 0.67rem;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--tone) 72%, var(--basalt-shade));
	box-shadow: 0 0 0 2px var(--basalt-plane);
	pointer-events: none;
}
[data-bs-theme="dark"] .basalt-count {
	color: var(--basalt-canvas);
	background: var(--tone);
}
.basalt-count[hidden] {
	display: none;
}

.basalt-count-dot {
	transform: translate(25%, -25%);
	width: 0.7rem;
	min-width: 0;
	height: 0.7rem;
	padding: 0;
}

.basalt-count-primary {
	--tone: var(--basalt-hue);
}

.basalt-count.is-bumping {
	animation: basalt-count-bump 420ms cubic-bezier(0.3, 1.6, 0.5, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-count.is-bumping {
		animation: none;
	}
}

@keyframes basalt-count-bump {
	0% {
		transform: translate(40%, -40%) scale(1);
	}
	35% {
		transform: translate(40%, -40%) scale(1.35);
	}
	100% {
		transform: translate(40%, -40%) scale(1);
	}
}
/* A toggle badge is a pressable filter that carries its own count; pressed,
   it takes the hue and shows a check. */
.basalt-badge-toggle {
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	padding: 0.3rem 0.3rem 0.3rem 0.75rem;
	border: 1px solid var(--basalt-edge-strong);
	border-radius: 999px;
	font-weight: 650;
	font-size: 0.8rem;
	line-height: 1.3;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease,
		border-color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-badge-toggle {
		transition: none;
	}
}
.basalt-badge-toggle:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-badge-toggle:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

.basalt-badge-toggle-count {
	min-width: 1.4rem;
	padding: 0.05rem 0.4rem;
	border-radius: 999px;
	font-size: 0.71rem;
	text-align: center;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}

.basalt-badge-toggle[aria-pressed="true"] {
	border-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
}
.basalt-badge-toggle[aria-pressed="true"] .basalt-badge-toggle-count {
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-hue) 78%, var(--basalt-shade));
}
[data-bs-theme="dark"] .basalt-badge-toggle[aria-pressed="true"] .basalt-badge-toggle-count {
	color: var(--basalt-canvas);
	background: var(--basalt-hue);
}

.basalt-badge-toggle-check {
	display: none;
	margin-left: -0.2rem;
	font-size: 0.85em;
}

.basalt-badge-toggle[aria-pressed="true"] .basalt-badge-toggle-check {
	display: inline;
}

/* The status menu turns a .basalt-status pill into a dropdown trigger
   (script: [data-basalt-status-menu]); the pill pops when its value changes. */
.basalt-status-menu .basalt-status {
	border: 1px solid transparent;
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease,
		border-color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-status-menu .basalt-status {
		transition: none;
	}
}
.basalt-status-menu .basalt-status:hover,
.basalt-status-menu .basalt-status[aria-expanded="true"] {
	border-color: color-mix(in srgb, var(--stp-tone) 45%, transparent);
}
.basalt-status-menu .basalt-status:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

.basalt-status-menu-caret {
	font-size: 0.7em;
	transition: transform 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-status-menu-caret {
		transition: none;
	}
}
.basalt-status-menu .basalt-status[aria-expanded="true"] .basalt-status-menu-caret {
	transform: rotate(180deg);
}

.basalt-status-menu .dropdown-menu {
	--bs-dropdown-padding-y: 0.3rem;
	--bs-dropdown-min-width: 12rem;
	--bs-dropdown-header-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-dropdown-link-color: var(--basalt-copy);
	--bs-dropdown-link-hover-bg: var(--basalt-wash);
	--bs-dropdown-link-hover-color: var(--basalt-copy);
	--bs-dropdown-link-active-bg: var(--basalt-wash);
	--bs-dropdown-link-active-color: var(--basalt-copy);
	font-size: 0.84rem;
	box-shadow: 0 12px 32px -12px color-mix(in srgb, var(--basalt-copy) 30%, transparent);
}

.basalt-status-menu .dropdown-item {
	display: flex;
	gap: 0.5rem;
	align-items: center;
}
.basalt-status-menu .dropdown-item:focus-visible {
	background: var(--basalt-wash);
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
}

.basalt-status-menu-dot {
	flex-shrink: 0;
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--stp-tone, var(--basalt-copy-muted));
}

.basalt-status-menu-check {
	visibility: hidden;
	margin-left: auto;
}

.basalt-status-menu .dropdown-item.active {
	font-weight: 650;
}
.basalt-status-menu .dropdown-item.active .basalt-status-menu-check {
	visibility: visible;
}

.basalt-status.is-changed {
	animation: basalt-status-pop 420ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-status.is-changed {
		animation: none;
	}
}

@keyframes basalt-status-pop {
	40% {
		transform: scale(1.08);
	}
}
/* Removable badges sit in a .basalt-removables row, each with its own close
   button; the optional key part reads like "Fabric: Linen". The row hides
   itself once empty (script: [data-basalt-removables]). */
.basalt-removables {
	display: flex;
	gap: 0.4rem;
	flex-wrap: wrap;
	align-items: center;
	margin: 0;
	padding: 0;
	list-style: none;
}
.basalt-removables > li {
	display: inline-flex;
}
.basalt-removables:empty {
	display: none;
}

.basalt-removables-empty {
	margin: 0;
	font-size: 0.84rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-removable {
	--tone: var(--basalt-copy-muted);
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	padding: 0.22rem 0.25rem 0.22rem 0.65rem;
	border: 1px solid color-mix(in srgb, var(--tone) 28%, transparent);
	border-radius: 999px;
	font-weight: 650;
	font-size: 0.8rem;
	line-height: 1.3;
	white-space: nowrap;
	color: color-mix(in srgb, var(--tone) 45%, var(--basalt-copy));
	background: color-mix(in srgb, var(--tone) 12%, var(--basalt-plane));
}

.basalt-removable-key {
	font-weight: 500;
	color: var(--basalt-copy-body);
}
.basalt-removable-key::after {
	content: ":";
}

.basalt-removable.is-entering {
	animation: basalt-removable-in 210ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-removable.is-entering {
		animation: none;
	}
}

.basalt-removable.is-leaving {
	animation: basalt-removable-out 170ms ease-in forwards;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-removable.is-leaving {
		animation: none;
	}
}

.basalt-removable-remove {
	display: inline-grid;
	place-items: center;
	width: 1.25rem;
	height: 1.25rem;
	padding: 0;
	border-radius: 50%;
	border: 0;
	font-size: 0.95rem;
	line-height: 1;
	color: inherit;
	background: transparent;
	cursor: pointer;
	transition: background-color 130ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-removable-remove {
		transition: none;
	}
}
.basalt-removable-remove:hover {
	background: color-mix(in srgb, var(--tone) 22%, transparent);
}
.basalt-removable-remove:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

@keyframes basalt-removable-in {
	from {
		transform: scale(0.7);
		opacity: 0;
	}
}
@keyframes basalt-removable-out {
	to {
		transform: scale(0.7);
		opacity: 0;
	}
}
/* A soft count pill tints its fill and pulls its text toward the body
   color, which keeps 4.5:1 in the lighter palettes where text-primary alone
   falls short. In an active list row it turns into an outline. */
.basalt-count-pill {
	--basalt-count-pill-tone: var(--basalt-hue);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.6rem;
	padding: 0.12rem 0.5rem;
	border-radius: 999px;
	font-weight: 700;
	font-size: 0.71rem;
	font-variant-numeric: tabular-nums;
	color: color-mix(in srgb, var(--basalt-count-pill-tone) 40%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-count-pill-tone) 15%, var(--basalt-plane));
}

.basalt-count-pill-success {
	--basalt-count-pill-tone: var(--basalt-success);
}

.basalt-count-pill-warning {
	--basalt-count-pill-tone: var(--basalt-warning);
}

.basalt-count-pill-danger {
	--basalt-count-pill-tone: var(--basalt-danger);
}

.list-group-item.active .basalt-count-pill {
	color: var(--basalt-on-hue);
	background: transparent;
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--basalt-on-hue) 55%, transparent);
}

/* The shared tones come last so they override each type's neutral --tone. */
.basalt-tone-primary {
	--tone: var(--basalt-hue);
}

.basalt-tone-success {
	--tone: var(--basalt-success);
}

.basalt-tone-warning {
	--tone: var(--basalt-warning);
}

.basalt-tone-danger {
	--tone: var(--basalt-danger);
}

.basalt-tone-info {
	--tone: var(--basalt-info);
}

/*
 * Everything built on top of the plain .basalt-avatar: the larger steps, chart
 * tones, presence and count markers, the progress ring, stacks that fan out
 * or collapse into a "+N" menu, the editable picture and the name, list and
 * tile layouts. avatars.html walks through all of it in this order;
 * basalt.js drives the parts marked [data-basalt-avatar],
 * [data-basalt-avatar-group], [data-basalt-avatar-edit] and
 * [data-basalt-presence].
 */
/* Secondary lines lean toward the body color so they keep 4.5:1. */
/* Every interactive part of an avatar shows the same hue outline on focus. */
/* Calm the motion for visitors who asked the system for less of it. */
/* The two big steps, and what any avatar does with a photo or an icon. */
.basalt-avatar {
	line-height: 1;
	text-decoration: none;
}
.basalt-avatar > img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.basalt-avatar > .bi {
	font-size: 1.1em;
}

.basalt-avatar-xl {
	width: 72px;
	height: 72px;
	font-size: 1.5rem;
}

.basalt-avatar-xxl {
	width: 96px;
	height: 96px;
	font-size: 2rem;
}

/* Each tone borrows one chart series; the text mix keeps 4.5:1 on the tint. */
.basalt-avatar-tone-1 {
	--avatar-tone: var(--basalt-series-1);
}

.basalt-avatar-tone-2 {
	--avatar-tone: var(--basalt-series-2);
}

.basalt-avatar-tone-3 {
	--avatar-tone: var(--basalt-series-3);
}

.basalt-avatar-tone-4 {
	--avatar-tone: var(--basalt-series-4);
}

.basalt-avatar-tone-5 {
	--avatar-tone: var(--basalt-series-5);
}

.basalt-avatar-tone-6 {
	--avatar-tone: var(--basalt-series-6);
}

.basalt-avatar-tone-7 {
	--avatar-tone: var(--basalt-series-7);
}

.basalt-avatar-tone-8 {
	--avatar-tone: var(--basalt-series-8);
}

[class*="basalt-avatar-tone-"] {
	color: color-mix(in srgb, var(--avatar-tone) 40%, var(--basalt-copy));
	background: color-mix(in srgb, var(--avatar-tone) 16%, var(--basalt-plane));
}
[data-bs-theme="dark"] [class*="basalt-avatar-tone-"] {
	color: color-mix(in srgb, var(--avatar-tone) 62%, var(--basalt-copy));
}

/* Solid, dashed and ringed treatments sit on top of any tone. */
.basalt-avatar-solid {
	color: var(--basalt-on-hue);
	background: color-mix(in srgb, var(--basalt-hue) 80%, var(--basalt-shade));
}
[data-bs-theme="dark"] .basalt-avatar-solid {
	background: var(--basalt-hue);
}

.basalt-avatar-outline {
	border: 1.5px dashed var(--basalt-edge-strong);
	color: var(--basalt-copy-body);
	background: transparent;
}

.basalt-avatar-ring {
	box-shadow:
		0 0 0 2px var(--basalt-plane),
		0 0 0 4px var(--basalt-hue);
}

:is(a, button).basalt-avatar:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

/* Softer corners shrink along with the two smallest sizes. */
.basalt-avatar-rounded {
	border-radius: 12px;
}
.basalt-avatar-rounded:is(.basalt-avatar-xs, .basalt-avatar-sm) {
	border-radius: 8px;
}

.basalt-avatar-square {
	border-radius: 4px;
}

/* The presence dot scales with its avatar and hugs the lower corner; on a
   squared avatar it slides out a little so it still clears the edge. */
.basalt-avatar-status {
	position: relative;
	display: inline-flex;
	flex-shrink: 0;
}

.basalt-avatar-status-dot {
	position: absolute;
	right: 0;
	bottom: 0;
	width: 28%;
	min-width: 8px;
	height: 28%;
	min-height: 8px;
	border: 2px solid var(--basalt-plane);
	border-radius: 50%;
	background: var(--basalt-copy-muted);
	transition: background-color 200ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-avatar-status-dot {
		transition: none;
	}
}
:is(.basalt-avatar-rounded, .basalt-avatar-square) + .basalt-avatar-status-dot {
	right: -3px;
	bottom: -3px;
}

.basalt-avatar-status-dot-top {
	top: 0;
	bottom: auto;
}

.basalt-avatar-status-dot-online {
	background: var(--basalt-success);
}

/* Busy and away carry a mark as well as a color, so neither relies on hue. */
.basalt-avatar-status-dot-busy {
	background: var(--basalt-danger);
}
.basalt-avatar-status-dot-busy::after {
	content: "";
	position: absolute;
	inset: 42% 22%;
	border-radius: 2px;
	background: var(--basalt-plane);
}

.basalt-avatar-status-dot-away {
	background: var(--basalt-warning);
}
.basalt-avatar-status-dot-away::after {
	content: "";
	position: absolute;
	inset: 18% 18% 30% 30%;
	border-bottom: 2px solid var(--basalt-plane);
	border-left: 2px solid var(--basalt-plane);
}

/* A count rides the upper corner, cut out from the avatar by a surface ring. */
.basalt-avatar-badge {
	position: absolute;
	top: -4px;
	right: -6px;
	min-width: 20px;
	height: 20px;
	padding: 0 0.3rem;
	border-radius: 999px;
	font-size: 0.6875rem;
	font-weight: 700;
	line-height: 20px;
	text-align: center;
	color: var(--basalt-plane);
	background: color-mix(in srgb, var(--basalt-danger) 72%, var(--basalt-shade));
	box-shadow: 0 0 0 2px var(--basalt-plane);
}
[data-bs-theme="dark"] .basalt-avatar-badge {
	color: var(--basalt-canvas);
	background: var(--basalt-danger);
}

/* The ring fills to --value (0 to 100) around the picture for profile or
   course progress; a plain custom property animates it, no script. */
@property --value {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}
.basalt-avatar-meter {
	--value: 0;
	--meter-width: 3px;
	--meter-tone: var(--basalt-hue);
	position: relative;
	display: inline-grid;
	place-items: center;
	padding: calc(var(--meter-width) + 3px);
	border-radius: 50%;
	background: conic-gradient(
		var(--meter-tone) calc(var(--value) * 1%),
		color-mix(in srgb, var(--basalt-copy) 12%, transparent) 0
	);
	transition: --value 600ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-avatar-meter {
		transition: none;
	}
}
.basalt-avatar-meter::before {
	content: "";
	position: absolute;
	inset: var(--meter-width);
	border-radius: 50%;
	background: var(--basalt-plane);
}
.basalt-avatar-meter > .basalt-avatar {
	position: relative;
}

.basalt-avatar-meter-lg {
	--meter-width: 4px;
}

.basalt-avatar-meter-success {
	--meter-tone: var(--basalt-success);
}

.basalt-avatar-meter-warning {
	--meter-tone: var(--basalt-warning);
}

/* Stacks come in two more overlaps (the base one lives with .basalt-avatar), and a
   hover variant lifts the avatar under the pointer above its neighbors. */
.basalt-avatar-more {
	font-weight: 700;
	color: var(--basalt-copy);
	background: var(--basalt-plane-alt);
}

.basalt-avatar-group-sm .basalt-avatar {
	margin-left: -6px;
}

.basalt-avatar-group-lg .basalt-avatar {
	margin-left: -14px;
	border-width: 3px;
}

:is(.basalt-avatar-group-sm, .basalt-avatar-group-lg) .basalt-avatar:first-child {
	margin-left: 0;
}

.basalt-avatar-group-hover .basalt-avatar {
	transition: transform 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-avatar-group-hover .basalt-avatar {
		transition: none;
	}
}
.basalt-avatar-group-hover .basalt-avatar:hover {
	position: relative;
	z-index: 1;
	transform: translateY(-3px);
}

/* The name sits beside its avatar with one quieter line of detail under it. */
.basalt-person {
	display: inline-flex;
	gap: 0.75rem;
	align-items: center;
	min-width: 0;
}

.basalt-person-name {
	display: block;
	font-weight: 600;
	line-height: 1.25;
	color: var(--basalt-copy);
}

.basalt-person-meta {
	display: block;
	font-size: 0.81rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* A chip is a person you can take back out of a selection. */
.basalt-person-chip {
	display: inline-flex;
	gap: 0.5rem;
	align-items: center;
	padding: 0.25rem 0.3rem 0.25rem 0.25rem;
	border-radius: 999px;
	border: 1px solid var(--basalt-edge-strong);
	font-weight: 550;
	font-size: 0.84rem;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
}

.basalt-person-chip-remove {
	display: inline-grid;
	place-items: center;
	width: 1.4rem;
	height: 1.4rem;
	padding: 0;
	border-radius: 50%;
	border: 0;
	color: var(--basalt-copy-body);
	background: transparent;
}
.basalt-person-chip-remove:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-person-chip-remove:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

/* A people list runs edge to edge, one ruled row per person and their role. */
.basalt-people {
	width: 100%;
	margin: 0;
	padding: 0;
	list-style: none;
}
.basalt-people > li {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	padding: 0.75rem 0;
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-people > li:last-child {
	border-bottom: 0;
}
.basalt-people .basalt-person {
	flex: 1;
}

.basalt-people-role {
	font-size: 0.77rem;
	white-space: nowrap;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* A profile tile centers one person over a short row of actions. */
.basalt-profile-tile {
	display: grid;
	gap: 0.2rem;
	justify-items: center;
	min-width: 0;
	padding: 1.5rem 1rem 1.25rem;
	border-radius: 14px;
	border: 1px solid var(--basalt-edge);
	text-align: center;
	background: var(--basalt-plane);
}
.basalt-profile-tile .basalt-avatar-status {
	margin-bottom: 0.65rem;
}

.basalt-profile-tile-actions {
	display: flex;
	gap: 0.4rem;
	margin-top: 0.75rem;
}

/* An editable avatar takes a picked or dropped image; a ring fills around it
   while the picture loads (script: [data-basalt-avatar-edit]). */
.basalt-avatar-edit {
	position: relative;
	display: inline-flex;
	border-radius: 50%;
}
.basalt-avatar-edit.is-dragging {
	box-shadow:
		0 0 0 3px var(--basalt-plane),
		0 0 0 6px var(--basalt-hue);
}
.basalt-avatar-edit > .basalt-avatar {
	position: relative;
	z-index: 1;
}

.basalt-avatar-edit-btn {
	position: absolute;
	right: -2px;
	bottom: -2px;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	border: 2px solid var(--basalt-plane);
	border-radius: 50%;
	font-size: 0.85rem;
	color: var(--basalt-on-hue);
	background: color-mix(in srgb, var(--basalt-hue) 80%, var(--basalt-shade));
}
[data-bs-theme="dark"] .basalt-avatar-edit-btn {
	background: var(--basalt-hue);
}
.basalt-avatar-edit-btn:hover {
	background: var(--basalt-hue-deep);
}
.basalt-avatar-edit-btn:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

.basalt-avatar-edit-ring {
	position: absolute;
	inset: -6px;
	border-radius: 50%;
	background: conic-gradient(var(--basalt-hue) calc(var(--value, 0) * 1%), transparent 0);
	opacity: 0;
	pointer-events: none;
	transition: opacity 200ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-avatar-edit-ring {
		transition: none;
	}
}
.basalt-avatar-edit-ring::before {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: var(--basalt-plane);
}

.basalt-avatar-edit.is-loading .basalt-avatar-edit-ring {
	opacity: 1;
}
.basalt-avatar-edit.is-loading .basalt-avatar {
	opacity: 0.6;
}

/* A spread stack opens up on hover or focus. With data-max, the script keeps
   that many avatars and folds the rest into a "+N" button whose menu lists
   them; the button's dropdown wrapper overlaps like any other member. */
.basalt-avatar-group-spread .basalt-avatar {
	transition:
		margin 210ms cubic-bezier(0.3, 0.7, 0.3, 1),
		transform 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-avatar-group-spread .basalt-avatar {
		transition: none;
	}
}

.basalt-avatar-group-spread:is(:hover, :focus-within) .basalt-avatar:not(:first-child) {
	margin-left: 4px;
}

.basalt-avatar-group .basalt-avatar[hidden] {
	display: none;
}
.basalt-avatar-group > .dropdown {
	display: inline-flex;
	margin-left: -8px;
}
.basalt-avatar-group > .dropdown .basalt-avatar {
	box-sizing: content-box;
	margin-left: 0;
	border: 2px solid var(--basalt-plane);
}
.basalt-avatar-group > .basalt-avatar:focus-visible,
.basalt-avatar-group > .dropdown > .basalt-avatar:focus-visible {
	position: relative;
	z-index: 2;
}

.basalt-avatar-group-lg > .dropdown {
	margin-left: -14px;
}
.basalt-avatar-group-lg > .dropdown .basalt-avatar {
	border-width: 3px;
}

.basalt-avatar-group-spread:is(:hover, :focus-within) > .dropdown {
	margin-left: 4px;
}

.basalt-avatar-group-more {
	padding: 0;
	cursor: pointer;
}
.basalt-avatar-group-more:hover {
	background: var(--basalt-wash);
}
.basalt-avatar-group-more[aria-expanded="true"] {
	box-shadow: 0 0 0 2px var(--basalt-hue);
}

/* The overflow menu scrolls past a handful of people and reuses the quiet
   detail color for each person's second line. */
.dropdown-menu.basalt-avatar-roster {
	--bs-dropdown-padding-y: 0.4rem;
	--bs-dropdown-min-width: 15rem;
	--bs-dropdown-header-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-dropdown-link-color: var(--basalt-copy);
	--bs-dropdown-link-hover-bg: var(--basalt-wash);
	--bs-dropdown-link-hover-color: var(--basalt-copy);
	--bs-dropdown-link-active-bg: var(--basalt-wash);
	--bs-dropdown-link-active-color: var(--basalt-copy);
	min-width: 15rem;
	max-height: 18rem;
	overflow-y: auto;
	box-shadow: 0 12px 32px -12px color-mix(in srgb, var(--basalt-copy) 30%, transparent);
}

.basalt-avatar-roster .dropdown-item {
	display: flex;
	gap: 0.65rem;
	align-items: center;
	padding-top: 0.4rem;
	padding-bottom: 0.4rem;
}
.basalt-avatar-roster .dropdown-item:focus-visible {
	background: var(--basalt-wash);
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
}

.basalt-avatar-roster-name {
	display: block;
	font-weight: 600;
	font-size: 0.84rem;
	line-height: 1.25;
}

.basalt-avatar-roster-meta {
	display: block;
	font-size: 0.74rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* The tone and title size every empty state shares, including the plain
   "nothing found" panel that basalt.js writes into any filtered list; the
   variants in _empty-types.scss load only where a page uses them. */
/* Each variant reads one tone, set by a modifier class, for its picture and
   badge; the quiet text color is mixed once here for all of them. */
.basalt-empty {
	--basalt-tone: var(--basalt-hue);
	--basalt-empty-quiet: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	/* A title is the same size whichever heading level carries it. */
}
.basalt-empty-title {
	font-size: 1rem;
	line-height: 1.4;
}
.basalt-empty-success {
	--basalt-tone: var(--basalt-success);
}
.basalt-empty-warning {
	--basalt-tone: var(--basalt-warning);
}
.basalt-empty-danger {
	--basalt-tone: var(--basalt-danger);
}
.basalt-empty-muted {
	--basalt-tone: var(--basalt-copy-muted);
}

/* Bootstrap's modal is the base of every dialog here; this partial points it
   at the palette and then adds the dialog patterns in the order modals.html
   demonstrates them. Scripts behind them (Basalt.dialog and the
   [data-basalt-*] hooks) live in basalt.js and modals.js. The command
   palette borrows the modal too, but its look belongs to the command menu. */
/* Visitors who ask for less motion get each effect below switched off where it is declared. */
/* A tone tinted into the copy color reads clearly on light and dark planes alike. */
/* The base dialog: rounder corners, a deep shadow, an opaque tinted scrim, and
   a small scale-in replacing Bootstrap's 50px drop from the top. */
.modal {
	--bs-modal-color: var(--basalt-copy-body);
	--bs-modal-bg: var(--basalt-plane);
	--bs-modal-border-color: var(--basalt-edge);
	--bs-modal-border-radius: 18px;
	--bs-modal-inner-border-radius: 17px;
	--bs-modal-box-shadow: 0 32px 80px -28px var(--basalt-scrim), 0 4px 14px -6px var(--basalt-scrim);
	--bs-modal-header-padding: 1.1rem 1.5rem;
	--bs-modal-header-border-color: var(--basalt-edge);
	--bs-modal-footer-border-color: var(--basalt-edge);
	--bs-modal-padding: 1.5rem;
	--bs-modal-footer-gap: 0.5rem;
}
.modal-content {
	box-shadow: var(--bs-modal-box-shadow);
}
.modal-title {
	font-size: 1.1rem;
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--basalt-copy);
}
.modal-footer {
	padding: 1.1rem 1.5rem 1.35rem;
}
.modal-backdrop {
	--bs-backdrop-bg: var(--basalt-scrim);
	--bs-backdrop-opacity: 1;
}

/* The dialog only appears after the backdrop has faded in, so that fade is cut short. */
.modal-backdrop.fade {
	transition-duration: 80ms;
}

.modal.fade .modal-dialog {
	transform: translateY(6px) scale(0.985);
	transition: transform 170ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.modal.fade .modal-dialog {
		transition: none;
	}
}
.modal.show .modal-dialog {
	transform: none;
}
.modal.modal-static .modal-dialog {
	transform: scale(1.02);
}

/* Typed confirmation: the destructive button waits until the exact phrase is
   typed, and a thin bar fills as the letters match ([data-basalt-type-confirm]). */
.basalt-type-confirm {
	--basalt-match: 0;
}
.basalt-type-confirm-phrase {
	padding: 0.05rem 0.4rem;
	border-radius: 6px;
	border: 1px solid var(--basalt-edge-strong);
	font-family: "Chivo Mono", monospace;
	font-size: 0.85em;
	font-weight: 400;
	white-space: nowrap;
	color: var(--basalt-copy);
	background: var(--basalt-canvas);
	user-select: all;
}
.basalt-type-confirm-meter {
	height: 4px;
	margin-top: 0.6rem;
	border-radius: 99px;
	overflow: hidden;
	background: var(--basalt-edge);
}
.basalt-type-confirm-meter span {
	display: block;
	width: calc(var(--basalt-match, calc(var(--value, 0) / 100)) * 100%);
	height: 100%;
	border-radius: inherit;
	background: var(--basalt-warning);
	transition:
		width 180ms ease,
		background-color 180ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-type-confirm-meter span {
		transition: none;
	}
}
.basalt-type-confirm-state {
	margin: 0.4rem 0 0;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-type-confirm {
	/* A full match turns bar and caption green; a wrong letter turns them red. */
}
.basalt-type-confirm.is-match .basalt-type-confirm-meter span {
	background: var(--basalt-success);
}
.basalt-type-confirm.is-match .basalt-type-confirm-state {
	font-weight: 600;
	color: color-mix(in srgb, var(--basalt-success) 62%, var(--basalt-copy));
}
.basalt-type-confirm.is-wrong .basalt-type-confirm-meter span {
	background: var(--basalt-danger);
}
.basalt-type-confirm.is-wrong .basalt-type-confirm-state {
	font-weight: 600;
	color: color-mix(in srgb, var(--basalt-danger) 62%, var(--basalt-copy));
}
.basalt-type-confirm.is-wrong .form-control {
	border-color: var(--basalt-danger);
}

/* The confirm dialog is built around one question: a toned icon, the question,
   what will happen, then both answers stacked full width. Danger is the
   default tone; the warning and primary modifiers soften it. */
.basalt-modal-confirm .modal-dialog {
	max-width: 420px;
}

.basalt-confirm {
	--basalt-confirm-tone: var(--basalt-danger);
	padding: 2rem 1.75rem 1.5rem;
	text-align: center;
}
.basalt-confirm-warning {
	--basalt-confirm-tone: var(--basalt-warning);
}
.basalt-confirm-primary {
	--basalt-confirm-tone: var(--basalt-hue);
}
.basalt-confirm-icon {
	display: grid;
	place-items: center;
	width: 64px;
	height: 64px;
	margin: 0 auto 1rem;
	border-radius: 50%;
	font-size: 1.6rem;
	color: color-mix(in srgb, var(--basalt-confirm-tone) 82%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-confirm-tone) 13%, var(--basalt-plane));
	box-shadow: 0 0 0 8px color-mix(in srgb, var(--basalt-confirm-tone) 6%, transparent);
}
.basalt-confirm-title {
	margin: 0 0 0.4rem;
	font-size: 1.2rem;
	font-weight: 800;
	letter-spacing: -0.01em;
	color: var(--basalt-copy);
}
.basalt-confirm-text {
	max-width: 34ch;
	margin: 0 auto 1.25rem;
	font-size: 0.9rem;
	text-wrap: pretty;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-confirm-list {
	margin: 0 0 1.5rem;
	padding: 0.6rem 0.9rem;
	border-radius: 12px;
	border: 1px solid var(--basalt-edge);
	font-size: 0.875rem;
	text-align: left;
	color: var(--basalt-copy);
	background: var(--basalt-canvas);
	list-style: none;
}
.basalt-confirm-list li {
	display: flex;
	gap: 0.6rem;
	align-items: center;
	padding: 0.3rem 0;
}
.basalt-confirm-list .bi {
	color: color-mix(in srgb, var(--basalt-confirm-tone) 82%, var(--basalt-copy));
}
.basalt-confirm-actions {
	display: grid;
	gap: 0.5rem;
}
.basalt-confirm-hint {
	margin: 0.85rem 0 0;
	font-size: 0.77rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* With [data-basalt-modal-guard] a form dialog refuses to close over unsaved
   edits: it shakes once and this warning bar rises into its footer. */
@keyframes basalt-guard-in {
	from {
		transform: translateY(6px);
		opacity: 0;
	}
}
@keyframes basalt-guard-shake {
	25% {
		transform: translateX(-5px);
	}
	75% {
		transform: translateX(5px);
	}
}
.basalt-modal-guard {
	display: flex;
	gap: 0.6rem 0.75rem;
	flex-wrap: wrap;
	align-items: center;
	padding: 0.85rem 1.5rem;
	border-top: 1px solid color-mix(in srgb, var(--basalt-warning) 45%, transparent);
	font-size: 0.875rem;
	color: var(--basalt-copy);
	background: var(--basalt-warning-soft);
	animation: basalt-guard-in 210ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-modal-guard[hidden] {
	display: none;
}
.basalt-modal-guard > .bi {
	font-size: 1.05rem;
	color: color-mix(in srgb, var(--basalt-warning) 60%, var(--basalt-copy));
}
.basalt-modal-guard-text {
	flex: 1;
	min-width: 10rem;
	margin: 0;
	font-weight: 650;
}
.basalt-modal-guard .btn-outline-secondary {
	background: var(--basalt-plane);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-modal-guard {
		animation: none;
	}
}

.modal-content.is-guarding {
	animation: basalt-guard-shake 320ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.modal-content.is-guarding {
		animation: none;
	}
}

/* A submit button carrying [data-busy-label] spins and swaps its label while
   saving, and holds on to its own fill instead of fading to disabled gray. */
.btn.is-busy {
	cursor: progress;
}
.btn.is-busy .spinner-border {
	width: 0.9rem;
	height: 0.9rem;
	margin-right: 0.4rem;
	border-width: 0.14em;
	vertical-align: -0.1em;
	color: currentColor;
}

.btn-primary.is-busy:disabled {
	--bs-btn-disabled-bg: var(--btn-fill);
	--bs-btn-disabled-border-color: var(--btn-fill);
	--bs-btn-disabled-color: var(--btn-ink);
}

/* After the work is done a dialog trades its parts for this state: a check
   that draws its ring and tick, a title, a line and one button. It waits
   [hidden] inside .modal-content until the script brings it forward. */
@keyframes basalt-done-ring {
	to {
		stroke-dashoffset: 0;
	}
}
@keyframes basalt-done-tick {
	to {
		stroke-dashoffset: 0;
	}
}
.basalt-done {
	padding: 2.5rem 1.75rem 2rem;
	text-align: center;
}
.basalt-done[hidden] {
	display: none;
}
.basalt-done-mark {
	display: block;
	width: 72px;
	height: 72px;
	margin: 0 auto 1rem;
	color: color-mix(in srgb, var(--basalt-success) 82%, var(--basalt-copy));
}
.basalt-done-mark circle {
	fill: color-mix(in srgb, var(--basalt-success) 12%, transparent);
	stroke: currentColor;
	stroke-width: 2;
	stroke-dasharray: 151;
	stroke-dashoffset: 151;
	animation: basalt-done-ring 520ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.basalt-done-mark path {
	fill: none;
	stroke: currentColor;
	stroke-width: 3.5;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-dasharray: 34;
	stroke-dashoffset: 34;
	animation: basalt-done-tick 360ms 380ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.basalt-done-mark {
	/* Held still, the check appears already drawn. */
}
@media (prefers-reduced-motion: reduce) {
	.basalt-done-mark circle,
	.basalt-done-mark path {
		stroke-dashoffset: 0;
		animation: none;
	}
}
.basalt-done-title {
	margin: 0 0 0.3rem;
	outline: 0;
	font-size: 1.2rem;
	font-weight: 800;
	color: var(--basalt-copy);
}
.basalt-done-text {
	max-width: 36ch;
	margin: 0 auto 1.5rem;
	font-size: 0.9rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.modal-content.is-done > :not(.basalt-done) {
	display: none;
}

/* A stepped dialog numbers its stages across the top. Each stage is done,
   current (aria-current="step") or ahead, and the line leading into a stage
   fills once the one before it is done ([data-basalt-dialog-steps]). */
@keyframes basalt-step-in {
	from {
		transform: translateX(12px);
		opacity: 0;
	}
}
.basalt-dialog-steps {
	display: flex;
	margin: 0.25rem 0 1.5rem;
	padding: 0;
	list-style: none;
}

.basalt-dialog-steps-item {
	position: relative;
	display: flex;
	gap: 0.4rem;
	flex: 1;
	flex-direction: column;
	align-items: center;
	font-size: 0.77rem;
	font-weight: 600;
	text-align: center;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	/* Two stacked rails join neighbors: a gray track and a hue fill that grows over it. */
}
.basalt-dialog-steps-item + .basalt-dialog-steps-item::before,
.basalt-dialog-steps-item + .basalt-dialog-steps-item::after {
	content: "";
	position: absolute;
	top: 15px;
	right: calc(50% + 22px);
	left: calc(-50% + 22px);
	height: 2px;
	border-radius: 2px;
	background: var(--basalt-edge-strong);
}
.basalt-dialog-steps-item + .basalt-dialog-steps-item::after {
	transform: scaleX(0);
	transform-origin: left center;
	background: var(--basalt-hue);
	transition: transform 360ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-dialog-steps-item.is-done + .basalt-dialog-steps-item::after {
	transform: scaleX(1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-dialog-steps-item + .basalt-dialog-steps-item::after {
		transition: none;
	}
}

.basalt-dialog-steps-dot {
	position: relative;
	z-index: 1;
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	border: 2px solid var(--basalt-edge-strong);
	font-family: "Chivo Mono", monospace;
	font-size: 0.8rem;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	transition:
		background-color 200ms ease,
		border-color 200ms ease,
		box-shadow 200ms ease;
}
.basalt-dialog-steps-dot .bi {
	display: none;
	font-size: 0.95rem;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-dialog-steps-dot {
		transition: none;
	}
}

.basalt-dialog-steps-item.is-done .basalt-dialog-steps-dot {
	border-color: transparent;
	color: var(--basalt-on-hue);
	background: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
}
.basalt-dialog-steps-item.is-done .basalt-dialog-steps-num {
	display: none;
}
.basalt-dialog-steps-item.is-done .basalt-dialog-steps-dot .bi {
	display: block;
}

.basalt-dialog-steps-item[aria-current="step"] .basalt-dialog-steps-dot,
.basalt-dialog-steps-item.is-current .basalt-dialog-steps-dot {
	border-color: var(--basalt-hue);
	color: var(--basalt-copy);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--basalt-hue) 18%, transparent);
}

.basalt-dialog-steps-item.is-done,
.basalt-dialog-steps-item[aria-current="step"],
.basalt-dialog-steps-item.is-current {
	color: var(--basalt-copy);
}

.basalt-dialog-steps-panel {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	animation: basalt-step-in 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-dialog-steps-panel[hidden] {
	display: none;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-dialog-steps-panel {
		animation: none;
	}
}

/* The review stage lists every answer as a label and value pair. */
.basalt-dialog-steps-summary {
	margin: 0 0 1rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	overflow: hidden;
}
.basalt-dialog-steps-summary div {
	display: flex;
	gap: 1rem;
	justify-content: space-between;
	padding: 0.7rem 1rem;
}
.basalt-dialog-steps-summary div + div {
	border-top: 1px solid var(--basalt-edge);
}
.basalt-dialog-steps-summary dt {
	font-weight: 500;
	font-size: 0.85rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-dialog-steps-summary dd {
	margin: 0;
	font-weight: 650;
	text-align: right;
	color: var(--basalt-copy);
}

/* The side sheet is a modal docked full height to the right edge, as wide as
   --basalt-sheet-width; adding .basalt-modal-sheet-start docks it left. */
.basalt-modal-sheet {
	--basalt-sheet-width: 520px;
}
.basalt-modal-sheet .modal-dialog {
	width: 100%;
	max-width: var(--basalt-sheet-width);
	height: 100%;
	margin: 0 0 0 auto;
}
.basalt-modal-sheet.fade .modal-dialog {
	transform: translateX(100%);
	transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-modal-sheet.fade .modal-dialog {
		transition: none;
	}
}
.basalt-modal-sheet.show .modal-dialog {
	transform: none;
}
.basalt-modal-sheet.modal-static .modal-dialog {
	transform: translateX(-8px);
}
.basalt-modal-sheet .modal-content {
	height: 100%;
	max-height: 100%;
	border-width: 0 0 0 1px;
	border-radius: 20px 0 0 20px;
}
.basalt-modal-sheet-start .modal-dialog {
	margin: 0 auto 0 0;
}
.basalt-modal-sheet-start.fade .modal-dialog {
	transform: translateX(-100%);
}
.basalt-modal-sheet-start.show .modal-dialog {
	transform: none;
}
.basalt-modal-sheet-start .modal-content {
	border-width: 0 1px 0 0;
	border-radius: 0 20px 20px 0;
}

/* A phone sheet covers the whole screen, so rounded corners would only show gaps. */
@media (max-width: 575.98px) {
	.basalt-modal-sheet .modal-content {
		border-radius: 0;
	}
}
.basalt-sheet-head {
	gap: 0.75rem;
	align-items: flex-start;
}
.basalt-sheet-head .btn-close {
	margin: 0;
}
.basalt-sheet-head .basalt-status {
	margin-top: 0.2rem;
}
.basalt-sheet-head-sub {
	margin: 0.1rem 0 0;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* Used with .modal-fullscreen, the full-screen dialog swaps its header for an
   app bar, and from 992px its body splits into work and settings columns. */
@keyframes basalt-pulse {
	50% {
		opacity: 0.35;
	}
}
.basalt-modal-full .modal-content {
	border: 0;
	border-radius: 0;
	box-shadow: none;
}
.basalt-modal-full .modal-body {
	padding: 2rem 1.25rem;
	background: var(--basalt-canvas);
}

.basalt-appbar {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	padding: 0.7rem 1.25rem;
	border-bottom: 1px solid var(--basalt-edge);
	background: var(--basalt-plane);
}
.basalt-appbar-heading {
	display: flex;
	gap: 0.1rem 0.9rem;
	flex: 1;
	flex-wrap: wrap;
	align-items: baseline;
	min-width: 0;
}
.basalt-appbar-title {
	max-width: 100%;
	margin: 0;
	overflow: hidden;
	font-size: 1.05rem;
	font-weight: 750;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--basalt-copy);
}
.basalt-appbar-status {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	/* The cloud icon breathes while a save is in flight. */
}
.basalt-appbar-status.is-saving .bi {
	animation: basalt-pulse 1s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-appbar-status.is-saving .bi {
		animation: none;
	}
}
.basalt-appbar-actions {
	display: flex;
	gap: 0.5rem;
	flex-shrink: 0;
}
.basalt-appbar-close {
	color: var(--basalt-copy);
}

.basalt-modal-grid {
	display: grid;
	gap: 1.5rem;
	grid-template-columns: minmax(0, 1fr);
	max-width: 1120px;
	margin: 0 auto;
}
@media (min-width: 992px) {
	.basalt-modal-grid {
		gap: 2rem;
		grid-template-columns: minmax(0, 1fr) 320px;
	}
}

.basalt-modal-main {
	padding: 1.5rem;
	border-radius: 16px;
	border: 1px solid var(--basalt-edge);
	background: var(--basalt-plane);
}

/* The lightbox pages through pictures on a wide stage: arrows at its sides, a
   caption bar beneath and a thumbnail strip at the foot
   ([data-basalt-lightbox-set], wired up in modals.js). */
@keyframes basalt-slide-in {
	from {
		transform: translateX(28px) scale(0.98);
		opacity: 0;
	}
}
@keyframes basalt-slide-back {
	from {
		transform: translateX(-28px) scale(0.98);
		opacity: 0;
	}
}
.basalt-lightbox .modal-dialog {
	max-width: min(1040px, 100vw - 2rem);
}
.basalt-lightbox .modal-content {
	overflow: hidden;
}
.basalt-lightbox-stage {
	position: relative;
	width: 100%;
	max-height: 68vh;
	aspect-ratio: 16/9;
	overflow: hidden;
	background: var(--basalt-canvas);
}
.basalt-lightbox-slide {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	animation: basalt-slide-in 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-lightbox-slide.is-back {
	animation-name: basalt-slide-back;
}
.basalt-lightbox-slide > * {
	width: 100%;
	height: 100%;
	object-fit: contain;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-lightbox-slide {
		animation: none;
	}
}
.basalt-lightbox-nav {
	position: absolute;
	top: 50%;
	z-index: 2;
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	margin-top: -23px;
	border-radius: 50%;
	border: 1px solid var(--basalt-edge);
	font-size: 1.1rem;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	box-shadow: 0 10px 24px -12px var(--basalt-scrim);
	transition:
		transform 170ms ease,
		background-color 170ms ease;
}
.basalt-lightbox-nav:hover {
	transform: scale(1.06);
	background: var(--basalt-wash);
}
.basalt-lightbox-nav:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}
.basalt-lightbox-nav-prev {
	left: 1rem;
}
.basalt-lightbox-nav-next {
	right: 1rem;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-lightbox-nav {
		transition: none;
	}
}
.basalt-lightbox-bar {
	display: flex;
	gap: 1rem;
	align-items: center;
	padding: 0.9rem 1.25rem;
	border-top: 1px solid var(--basalt-edge);
}
.basalt-lightbox-caption {
	display: flex;
	gap: 0.1rem;
	flex: 1;
	flex-direction: column;
	min-width: 0;
}
.basalt-lightbox-caption strong {
	font-weight: 700;
	color: var(--basalt-copy);
}
.basalt-lightbox-caption span {
	font-size: 0.85rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-lightbox-count {
	font-family: "Chivo Mono", monospace;
	font-size: 0.8rem;
	white-space: nowrap;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-lightbox-thumbs {
	display: flex;
	gap: 0.5rem;
	padding: 0 1.25rem 1.1rem;
	overflow-x: auto;
	overflow-y: hidden;
}
.basalt-lightbox-thumb {
	flex-shrink: 0;
	width: 68px;
	height: 48px;
	padding: 0;
	border-radius: 9px;
	border: 2px solid transparent;
	overflow: hidden;
	background: none;
	opacity: 0.6;
	transition:
		opacity 170ms ease,
		border-color 170ms ease;
}
.basalt-lightbox-thumb:hover {
	opacity: 1;
}
.basalt-lightbox-thumb[aria-current="true"] {
	border-color: var(--basalt-hue);
	opacity: 1;
}
.basalt-lightbox-thumb:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	opacity: 1;
}

/* Narrow screens get smaller arrows that sit closer to the edges. */
@media (max-width: 575.98px) {
	.basalt-lightbox-nav {
		width: 38px;
		height: 38px;
		margin-top: -19px;
	}
	.basalt-lightbox-nav-prev {
		left: 0.5rem;
	}
	.basalt-lightbox-nav-next {
		right: 0.5rem;
	}
}
/**
 * Everything that slides in from an edge. Bootstrap's offcanvas gets the
 * palette first; the Basalt panels layered on it follow in the order a
 * visitor meets them inside a panel: the drawer frame, record stepping, the
 * drill-in menu, the resize grip, then the bottom sheet and the in-page push
 * drawer. The filter count and applied-filter chips that live beside a
 * panel's trigger close the file. offcanvas.html exercises every piece,
 * the list pages reuse the drawer, and basalt.js answers the data-basalt-*
 * hooks mentioned along the way.
 */
/* All slides, fades and size changes here share one soft deceleration. */
/* Supporting text mixes the muted tone back toward the main ink. */
/* Accent text on a tinted ground leans toward the ink to stay legible. */
/* A square control with one glyph dead center; size and corner vary. */
/* Reduced-motion overrides travel with the rule they quiet. */
/* Bootstrap's panel reads its whole look from these variables; the slide uses
   the shared curve, and the scrim behind it is tinted rather than black. */
.offcanvas,
.offcanvas-lg {
	--bs-offcanvas-bg: var(--basalt-plane);
	--bs-offcanvas-color: var(--basalt-copy-body);
	--bs-offcanvas-border-color: var(--basalt-edge);
	--bs-offcanvas-padding-x: 1.5rem;
	--bs-offcanvas-padding-y: 1.25rem;
	--bs-offcanvas-box-shadow: 0 30px 80px -24px var(--basalt-scrim);
	--bs-offcanvas-transition: transform 210ms cubic-bezier(0.2, 0.8, 0.2, 1);
	--bs-offcanvas-title-line-height: 1.3;
}
@media (prefers-reduced-motion: reduce) {
	.offcanvas,
	.offcanvas-lg {
		--bs-offcanvas-transition: none;
	}
}

/* Only the corners that face the page are rounded. */
.offcanvas {
	box-shadow: var(--bs-offcanvas-box-shadow);
}
.offcanvas.offcanvas-start {
	border-radius: 0 20px 20px 0;
}
.offcanvas.offcanvas-end {
	border-radius: 20px 0 0 20px;
}
.offcanvas.offcanvas-top {
	border-radius: 0 0 20px 20px;
}
.offcanvas.offcanvas-bottom {
	border-radius: 20px 20px 0 0;
}
.offcanvas {
	/* A phone always keeps a strip of the page visible beside a side panel. */
}
@media (max-width: 575.98px) {
	.offcanvas.offcanvas-start,
	.offcanvas.offcanvas-end {
		--bs-offcanvas-width: min(400px, 92vw);
	}
}

.offcanvas-header {
	gap: 0.75rem;
	border-bottom: 1px solid var(--basalt-edge);
}
.offcanvas-header .btn-close {
	flex-shrink: 0;
	margin: 0 0 0 auto;
}

.offcanvas-title {
	font-size: 1.1rem;
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--basalt-copy);
}

.offcanvas-backdrop {
	background-color: var(--basalt-scrim);
}
.offcanvas-backdrop.show {
	opacity: 1;
}

/* .basalt-drawer turns any panel into a titled head, a scrolling body and a
   foot for actions. A form placed in .basalt-drawer-form stretches between
   them so its submit button can sit in the foot. */
.basalt-drawer {
	container: basalt-drawer/inline-size;
}
.basalt-drawer .form-check {
	margin-bottom: 0.6rem;
}
.basalt-drawer .form-check-label {
	color: var(--basalt-copy);
}

.basalt-drawer-heading {
	flex: 1;
	min-width: 0;
}

.basalt-drawer-sub {
	margin: 0.2rem 0 0;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-drawer-form {
	display: flex;
	flex-direction: column;
	flex: 1;
	min-height: 0;
}

/* Sections are bare fieldsets spaced apart, the last one flush with the end. */
.basalt-drawer-section {
	min-width: 0;
	margin: 0 0 1.5rem;
	padding: 0;
	border: 0;
}
.basalt-drawer-section:last-child {
	margin-bottom: 0;
}

.basalt-drawer-legend {
	display: block;
	float: none;
	width: auto;
	margin: 0 0 0.75rem;
	padding: 0;
	font-size: var(--basalt-fs-section);
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-drawer-count {
	margin-left: 0.3rem;
	padding: 0 0.4rem;
	border-radius: 999px;
	border: 1px solid var(--basalt-edge);
	font-size: 0.71rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-copy-body);
	background: var(--basalt-canvas);
}

/* The foot is stacked above the body that scrolls under it and casts a faint
   shadow upward; its buttons gather on the right and never break a label. */
.basalt-drawer-foot {
	position: relative;
	z-index: 1;
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	margin-top: auto;
	padding: 1.1rem var(--bs-offcanvas-padding-x) 1.35rem;
	border-top: 1px solid var(--basalt-edge);
	background: var(--basalt-plane);
	box-shadow: 0 -14px 24px -20px var(--basalt-scrim);
}
.basalt-drawer-foot .btn-primary {
	min-width: 9rem;
}
.basalt-drawer-foot > .btn {
	white-space: nowrap;
}
.basalt-drawer-foot {
	/* Once the panel is narrow, every button widens to fill its row, and one
      that has no room left drops to the next row whole. */
}
@container basalt-drawer (max-width: 420px) {
	.basalt-drawer-foot > .btn {
		flex: 1 1 auto;
	}
}

/* Record stepping puts a position label and two arrow buttons in the head. */
.basalt-drawer-nav {
	display: flex;
	gap: 0.25rem;
	flex-shrink: 0;
	align-items: center;
}
.basalt-drawer-nav .btn-icon {
	padding: 0;
	border: 1px solid var(--basalt-edge-strong);
	background: var(--basalt-plane);
	display: inline-grid;
	place-items: center;
	width: 32px;
	height: 32px;
	border-radius: 8px;
}
.basalt-drawer-nav .btn-icon:hover {
	background: var(--basalt-wash);
}

.basalt-drawer-pos {
	margin-right: 0.25rem;
	font-size: 0.77rem;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* Each step re-runs the body's entrance; .is-back flips it so the next
   record arrives from the side the visitor is heading toward. */
.basalt-drawer-record {
	--bs-offcanvas-width: 460px;
}
.basalt-drawer-record .offcanvas-body > * {
	animation: basalt-record-in 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-drawer-record .offcanvas-body > * {
		animation: none;
	}
}
.basalt-drawer-record.is-back .offcanvas-body > * {
	animation-name: basalt-record-back;
}

/* The drill-in drawer keeps every menu level in one panel and slides from
   one to the next; [data-basalt-drawer-views] runs it (offcanvas.js). */
.basalt-drawer-views {
	position: relative;
	overflow-x: hidden;
}

.basalt-drawer-views-view {
	display: flex;
	gap: 0.2rem;
	flex-direction: column;
	animation: basalt-view-in 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-drawer-views-view {
		animation: none;
	}
}
.basalt-drawer-views-view.is-back {
	animation-name: basalt-view-back;
}
.basalt-drawer-views-view[hidden] {
	display: none;
}

.basalt-drawer-views-back {
	flex-shrink: 0;
	padding: 0;
	border: 1px solid var(--basalt-edge-strong);
	background: var(--basalt-plane);
	display: inline-grid;
	place-items: center;
	width: 34px;
	height: 34px;
	border-radius: 9px;
}
.basalt-drawer-views-back:hover {
	background: var(--basalt-wash);
}
.basalt-drawer-views-back[hidden] {
	display: none;
}

/* A level's entry is a full-width row: icon, label that takes the slack,
   an optional tally, then the chevron. */
.basalt-drawer-views-item {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	width: 100%;
	padding: 0.75rem 0.8rem;
	border: 0;
	border-radius: 10px;
	font-size: 0.95rem;
	font-weight: 600;
	text-align: left;
	color: var(--basalt-copy);
	background: none;
}
.basalt-drawer-views-item:hover {
	background: var(--basalt-wash);
}
.basalt-drawer-views-item:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
}
.basalt-drawer-views-item > span:not([class]) {
	flex: 1;
	min-width: 0;
}

.basalt-drawer-views-icon {
	flex-shrink: 0;
	color: color-mix(in srgb, var(--basalt-hue) 66%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
	display: inline-grid;
	place-items: center;
	width: 34px;
	height: 34px;
	border-radius: 10px;
}

.basalt-drawer-views-hint {
	margin-left: auto;
	font-size: 0.8rem;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-drawer-views-chev {
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* The resize grip is a focusable separator astride the panel's inner edge.
   It answers to dragging and to the arrow keys, and
   [data-basalt-drawer-resize] clamps it to data-min and data-max. */
.basalt-drawer-resize {
	position: absolute;
	top: 0;
	bottom: 0;
	z-index: 2;
	width: 14px;
	cursor: ew-resize;
	touch-action: none;
}
.offcanvas-end > .basalt-drawer-resize {
	left: -7px;
}
.offcanvas-start > .basalt-drawer-resize {
	right: -7px;
}
.basalt-drawer-resize::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 5px;
	width: 4px;
	height: 44px;
	margin-top: -22px;
	border-radius: 4px;
	background: var(--basalt-edge-strong);
	transition:
		background-color 170ms ease,
		height 170ms ease,
		margin-top 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-drawer-resize::after {
		transition: none;
	}
}
.basalt-drawer-resize {
	/* Hover, a drag in progress and keyboard focus all stretch the bar and
      paint it in the accent; focus adds a ring in place of the outline. */
}
.basalt-drawer-resize:hover::after,
.basalt-drawer-resize.is-dragging::after,
.basalt-drawer-resize:focus-visible::after {
	height: 64px;
	margin-top: -32px;
	background: var(--basalt-hue);
}
.basalt-drawer-resize:focus-visible {
	outline: 0;
	box-shadow: none;
}
.basalt-drawer-resize:focus-visible::after {
	box-shadow: 0 0 0 3px var(--basalt-hue-border);
}

/* Mid-resize the panel tracks the pointer exactly and selects no text. */
.offcanvas.is-resizing {
	user-select: none;
	transition: none;
}

/* A bottom sheet is a centered .offcanvas-bottom that snaps between the
   heights in data-snap (percent of the viewport). Its handle drags and also
   works as a button; [data-basalt-sheet] provides both. */
.basalt-sheet {
	--bs-offcanvas-height: 55vh;
	max-width: 720px;
	margin: 0 auto;
	transition:
		var(--bs-offcanvas-transition),
		height 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-sheet {
		transition: none;
	}
}
.basalt-sheet.is-dragging {
	transition: none;
}
.basalt-sheet .offcanvas-header {
	padding-top: 0.25rem;
	padding-bottom: 0.5rem;
	border-bottom: 0;
}
.basalt-sheet .offcanvas-body {
	padding-top: 0.25rem;
}

.basalt-sheet-handle {
	display: grid;
	flex-shrink: 0;
	place-items: center;
	width: 100%;
	height: 26px;
	padding: 0;
	border: 0;
	background: none;
	cursor: grab;
	touch-action: none;
}
.basalt-sheet-handle span {
	width: 44px;
	height: 5px;
	border-radius: 5px;
	background: var(--basalt-edge-strong);
	transition:
		background-color 170ms ease,
		width 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-sheet-handle span {
		transition: none;
	}
}
.basalt-sheet-handle {
	/* The pill widens under the pointer, while dragging and on focus; focus
      paints it in the accent with a ring instead of an outline. */
}
.basalt-sheet-handle:hover span,
.basalt-sheet.is-dragging .basalt-sheet-handle span {
	width: 56px;
	background: var(--basalt-copy-muted);
}
.basalt-sheet-handle:focus-visible {
	outline: 0;
	box-shadow: none;
}
.basalt-sheet-handle:focus-visible span {
	width: 56px;
	background: var(--basalt-hue);
	box-shadow: 0 0 0 3px var(--basalt-hue-border);
}
.basalt-sheet.is-dragging .basalt-sheet-handle {
	cursor: grabbing;
}

/* The push drawer sits inside the page and moves the content over instead
   of covering it; [data-basalt-push-toggle] collapses its first column. */
.basalt-push {
	--basalt-push-width: 230px;
	position: relative;
	display: grid;
	grid-template-columns: var(--basalt-push-width) minmax(0, 1fr);
	min-height: 300px;
	border: 1px solid var(--basalt-edge);
	border-radius: 14px;
	overflow: hidden;
	background: var(--basalt-plane);
	transition: grid-template-columns 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.basalt-push.is-closed {
	grid-template-columns: 0 minmax(0, 1fr);
}

.basalt-push-panel {
	min-width: 0;
	padding: 1rem 0.75rem;
	border-right: 1px solid var(--basalt-edge);
	overflow: hidden;
	background: var(--basalt-canvas);
	transition:
		opacity 240ms ease,
		visibility 240ms;
}
.basalt-push.is-closed .basalt-push-panel {
	visibility: hidden;
	border-right-color: transparent;
	opacity: 0;
}

.basalt-push-title {
	margin: 0 0 0.6rem;
	padding: 0 0.7rem;
	font-size: 0.71rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	white-space: nowrap;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

.basalt-push-main {
	min-width: 0;
}

/* Under tablet width the content keeps the full row, and the panel floats
   over its left edge, sliding away when closed instead of fading. */
@media (max-width: 767.98px) {
	.basalt-push,
	.basalt-push.is-closed {
		grid-template-columns: minmax(0, 1fr);
	}
	.basalt-push-panel {
		position: absolute;
		top: 0;
		bottom: 0;
		left: 0;
		z-index: 2;
		width: min(var(--basalt-push-width), 80%);
		box-shadow: 16px 0 32px -20px var(--basalt-scrim);
		transition:
			transform 210ms cubic-bezier(0.2, 0.8, 0.2, 1),
			visibility 210ms;
	}
	.basalt-push.is-closed .basalt-push-panel {
		transform: translateX(-100%);
		opacity: 1;
	}
}
/* The push drawer opens and closes instantly for reduced-motion visitors;
   this has to follow the narrow layout, which sets its own transition. */
@media (prefers-reduced-motion: reduce) {
	.basalt-push,
	.basalt-push-panel {
		transition: none;
	}
}
/* A filter trigger shows how many filters are on in a small dark pill. */
.basalt-count-badge {
	display: inline-grid;
	place-items: center;
	min-width: 1.35rem;
	height: 1.35rem;
	margin-left: 0.4rem;
	padding: 0 0.3rem;
	border-radius: 999px;
	font-size: 0.71rem;
	font-weight: 700;
	line-height: 1;
	color: var(--basalt-plane);
	background: var(--basalt-copy);
}
.basalt-count-badge[hidden] {
	display: none;
}

/* The filters in force become chips, each removable on its own, with a
   clear-all link trailing them; a row with nothing in it collapses. */
.basalt-applied {
	display: flex;
	gap: 0.4rem;
	flex-wrap: wrap;
	align-items: center;
}
.basalt-applied:empty {
	display: none;
}

.basalt-applied-chip {
	display: inline-flex;
	gap: 0.25rem;
	align-items: center;
	padding: 0.2rem 0.25rem 0.2rem 0.7rem;
	border-radius: 999px;
	border: 1px solid var(--basalt-hue-border);
	font-size: 0.8rem;
	font-weight: 600;
	white-space: nowrap;
	color: var(--basalt-copy);
	background: var(--basalt-hue-soft);
	animation: basalt-chip-in 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-applied-chip {
		animation: none;
	}
}
.basalt-applied-chip button {
	padding: 0;
	border: 0;
	color: var(--basalt-copy-body);
	background: transparent;
	display: inline-grid;
	place-items: center;
	width: 22px;
	height: 22px;
	border-radius: 50%;
}
.basalt-applied-chip button:hover {
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-copy) 10%, transparent);
}
.basalt-applied-chip button:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

.basalt-applied-clear {
	padding: 0.2rem 0.4rem;
	border: 0;
	font-size: 0.8rem;
	font-weight: 600;
	text-decoration: underline;
	text-underline-offset: 3px;
	color: color-mix(in srgb, var(--basalt-hue) 66%, var(--basalt-copy));
	background: none;
}

/* Every entrance above fades up from transparent while it travels the
   listed offset back to rest. */
@keyframes basalt-record-in {
	from {
		transform: translateY(8px);
		opacity: 0;
	}
}
@keyframes basalt-record-back {
	from {
		transform: translateY(-8px);
		opacity: 0;
	}
}
@keyframes basalt-view-in {
	from {
		transform: translateX(32px);
		opacity: 0;
	}
}
@keyframes basalt-view-back {
	from {
		transform: translateX(-32px);
		opacity: 0;
	}
}
@keyframes basalt-chip-in {
	from {
		transform: scale(0.9);
		opacity: 0;
	}
}
/* Tabbed navigation in two layers. Bootstrap's nav, tabs, pills and underline
   are tuned to the palette first; then .basalt-tabs builds on the same markup
   with an indicator that glides to the picked tab, in pill, segmented,
   vertical, scrolling, overflow and closable forms. tabs.html shows each
   of them, and assets/basalt/js/components/tabs.js (Basalt.tabs, [data-basalt-tabs]) runs them. */
/* Every move of the indicator shares this one easing curve. */
/* A row that scrolls on its own keeps its scrollbar out of sight. */
/* The tab colors are derived once and read by every style below. A primary
   label or fill is pulled toward the body color so it holds 4.5:1 even in the
   palest palettes, and a label set on a fill always uses the on-primary token. */
.nav,
.basalt-tabs {
	--basalt-tab-quiet: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--basalt-tab-accent: color-mix(in srgb, var(--basalt-hue) 66%, var(--basalt-copy));
	--basalt-tab-fill: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--basalt-tab-ring: 0 0 0 0.2rem color-mix(in srgb, var(--basalt-hue) 40%, transparent);
	--bs-nav-link-color: var(--basalt-copy-body);
	--bs-nav-link-hover-color: var(--basalt-copy);
	--bs-nav-link-disabled-color: var(--basalt-tab-quiet);
	--bs-nav-link-font-weight: 600;
	--bs-nav-link-focus-box-shadow: var(--basalt-tab-ring);
}

.nav-link {
	transition:
		color 170ms ease,
		background-color 170ms ease,
		border-color 170ms ease;
	/* Bootstrap hard-codes its blue into the focus ring instead of reading the
      variable, so the ring is set again by hand. */
}
.nav-link:focus-visible {
	box-shadow: var(--basalt-tab-ring);
}
.nav-link.disabled,
.nav-link:disabled {
	cursor: not-allowed;
}
.nav-link {
	/* A count inside any tab stays legible whatever state the tab is in. */
}
.nav-link .badge {
	padding: 0.25em 0.5em;
	border: 1px solid var(--basalt-edge);
	font-family: "Chivo Mono", monospace;
	font-weight: 600;
	font-size: 0.7rem;
	color: var(--basalt-copy);
	background-color: var(--basalt-canvas);
}

/* A stacked nav reads from the left, and its leading icons line up in one
   column no matter how wide each glyph is. */
.nav.flex-column .nav-link {
	text-align: left;
}

.nav.flex-column .nav-link > .bi:first-child,
.basalt-tabs-vertical .nav-link > .bi:first-child {
	display: inline-block;
	flex-shrink: 0;
	width: 1.25em;
	text-align: center;
}

/* The open tab merges into the panel underneath it. */
.nav-tabs {
	--bs-nav-tabs-border-color: var(--basalt-edge);
	--bs-nav-tabs-link-hover-border-color: var(--basalt-edge) var(--basalt-edge) var(--basalt-edge);
	--bs-nav-tabs-link-active-color: var(--basalt-tab-accent);
	--bs-nav-tabs-link-active-bg: var(--basalt-plane);
	--bs-nav-tabs-link-active-border-color: var(--basalt-edge) var(--basalt-edge) var(--basalt-plane);
	--bs-nav-tabs-border-radius: 10px;
	/* Tabs stay on one row so the open tab always sits on the line; a row
     wider than its box slides sideways and fades at the hidden edge. The
     line is drawn inside the row, since a scrolling box clips anything that
     hangs over its border, and the open tab covers it with its own edge. */
	flex-wrap: nowrap;
	overflow-x: auto;
	overflow-y: hidden;
	border-bottom: 0;
	box-shadow: inset 0 calc(-1 * var(--bs-nav-tabs-border-width)) 0 var(--bs-nav-tabs-border-color);
	overscroll-behavior-x: contain;
	scrollbar-width: none;
}
.nav-tabs::-webkit-scrollbar {
	display: none;
}
.nav-tabs .nav-link {
	margin-bottom: 0;
	white-space: nowrap;
}
.nav-tabs .nav-link:hover:not(.active) {
	background-color: var(--basalt-wash);
}
.nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link {
	color: var(--basalt-tab-accent);
}

/* In a card header the header's own border is the line, so the row reaches
   one hairline further down and the open tab covers that border instead. */
.card-header-tabs {
	margin-bottom: calc(-1 * var(--bs-card-cap-padding-y) - var(--bs-border-width));
	box-shadow: none;
}

/* A picked pill carries the brand fill with the on-primary label on top. */
.nav-pills {
	--bs-nav-pills-border-radius: 999px;
	--bs-nav-pills-link-active-color: var(--basalt-on-hue);
	--bs-nav-pills-link-active-bg: var(--basalt-tab-fill);
	gap: 0.25rem;
}
.nav-pills .nav-link:hover:not(.active) {
	background-color: var(--basalt-wash);
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
	border-color: var(--basalt-tab-fill);
	color: var(--basalt-on-hue);
	background-color: var(--basalt-tab-fill);
}
.nav-pills .nav-link.active .badge {
	border-color: transparent;
	color: var(--basalt-copy);
	background-color: var(--basalt-plane);
}

/* The underlined link keeps its text color and gains a brand bar beneath. */
.nav-underline {
	--bs-nav-underline-gap: 1.5rem;
	--bs-nav-underline-link-active-color: var(--basalt-copy);
	row-gap: 0.25rem;
}
.nav-underline .nav-link.active,
.nav-underline .show > .nav-link {
	border-bottom-color: var(--basalt-hue);
}
.nav-underline .nav-link:hover:not(.active) {
	border-bottom-color: var(--basalt-edge-strong);
}

/* A panel can be reached by keyboard and shows a ring when it is; under
   reduced motion its fade is dropped as well. */
.tab-pane:focus-visible {
	border-radius: 8px;
	outline: 2px solid var(--basalt-hue);
	outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
	.nav-link,
	.tab-content > .fade {
		transition: none;
	}
}
/* .basalt-tabs reuses Bootstrap's tab markup and script, and the script drops
   an indicator (.basalt-tabs-ink) into the list that slides to the picked tab.
   The variants are -pill, -segmented, -vertical, -scroll and -closable, and
   [data-basalt-tabs-overflow] folds tabs that do not fit into a More menu. */
.basalt-tabs {
	position: relative;
	min-width: 0;
	font-size: 0.9rem;
}
.basalt-tabs .nav-link:hover,
.basalt-tabs .nav-link.active {
	color: var(--basalt-copy);
}
.basalt-tabs .nav-link:not(.active):focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
	box-shadow: none;
}
.basalt-tabs {
	/* In the segmented radios the label is what shows; the input holds focus. */
}
.basalt-tabs .btn-check:focus-visible:not(:checked) + .nav-link {
	outline: 2px solid var(--basalt-hue);
	outline-offset: -2px;
}
.basalt-tabs label.nav-link {
	margin: 0;
	cursor: pointer;
}
.basalt-tabs .btn-check:checked + .nav-link {
	color: var(--basalt-copy);
}
.basalt-tabs .nav-link > .bi {
	font-size: 1rem;
	color: var(--basalt-tab-quiet);
	transition: color 170ms ease;
}
.basalt-tabs .nav-link.active > .bi {
	color: var(--basalt-tab-accent);
}

.basalt-tabs-list {
	position: relative;
	display: flex;
	gap: 0.25rem;
	flex-wrap: nowrap;
	align-items: stretch;
	margin: 0;
	padding: 0;
	/* When the row outgrows its box it scrolls sideways instead of widening
      the page, and the script scrolls the picked tab into view. */
	overflow-x: auto;
	overflow-y: hidden;
	list-style: none;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
}
.basalt-tabs-list::-webkit-scrollbar {
	display: none;
}

.basalt-tabs-vertical .basalt-tabs-list,
.basalt-tabs-viewport .basalt-tabs-list,
.basalt-tabs[data-basalt-tabs-overflow] .basalt-tabs-list {
	overflow: visible;
}

.basalt-tabs-list > .nav-link,
.basalt-tabs-item > .nav-link {
	position: relative;
	z-index: 1;
	display: inline-flex;
	gap: 0.5rem;
	align-items: center;
	padding: 0.7rem 0.95rem;
	border: 0;
	border-radius: 8px;
	white-space: nowrap;
	color: var(--basalt-copy-body);
	background: transparent;
}

/* A count next to the label turns to the plane surface once its tab is
   picked; a small warning dot flags a tab with something new in it. */
.basalt-tabs-count {
	padding: 0.28rem 0.4rem;
	border-radius: 999px;
	border: 1px solid var(--basalt-edge);
	font:
		600 0.7rem/1 "Chivo Mono",
		monospace;
	color: var(--basalt-copy);
	background: var(--basalt-canvas);
	transition:
		background-color 170ms ease,
		border-color 170ms ease;
}
.basalt-tabs .nav-link.active .basalt-tabs-count {
	border-color: var(--basalt-hue-border);
	background: var(--basalt-plane);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-count {
		transition: none;
	}
}

.basalt-tabs-dot {
	width: 0.4rem;
	height: 0.4rem;
	border-radius: 50%;
	background: var(--basalt-warning);
	box-shadow: 0 0 0 2px var(--basalt-plane);
}

/* By default the indicator is an underline; the script writes its left,
   width, top and height from whichever tab is picked. */
.basalt-tabs-ink {
	position: absolute;
	bottom: 0;
	left: 0;
	z-index: 0;
	width: 0;
	height: 3px;
	border-radius: 3px 3px 0 0;
	background: var(--basalt-hue);
	pointer-events: none;
	transition:
		left 280ms cubic-bezier(0.3, 0.7, 0.2, 1),
		width 280ms cubic-bezier(0.3, 0.7, 0.2, 1),
		top 280ms cubic-bezier(0.3, 0.7, 0.2, 1),
		height 280ms cubic-bezier(0.3, 0.7, 0.2, 1);
}
.basalt-tabs.is-static .basalt-tabs-ink {
	transition: none;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-ink {
		transition: none;
	}
}

/* The underline rests on a hairline. When the row shares its line with a
   More button or scroll arrows, the hairline moves to the wrapper so it
   runs under those too. */
.basalt-tabs:not(.basalt-tabs-pill):not(.basalt-tabs-segmented):not(.basalt-tabs-vertical):not(.basalt-tabs-scroll):not(
		[data-basalt-tabs-overflow]
	)
	> .basalt-tabs-list,
.basalt-tabs-scroll:not(.basalt-tabs-pill),
.basalt-tabs[data-basalt-tabs-overflow]:not(.basalt-tabs-pill) {
	box-shadow: inset 0 -1px 0 var(--basalt-edge);
}

/* In the pill variant the indicator fills the tab rather than lining it. */
.basalt-tabs-pill .basalt-tabs-ink {
	top: 0;
	bottom: auto;
	border-radius: 999px;
	background: var(--basalt-hue-soft);
	box-shadow: inset 0 0 0 1px var(--basalt-hue-border);
}
.basalt-tabs-pill .nav-link {
	border-radius: 999px;
}
.basalt-tabs-pill .nav-link.active {
	color: var(--basalt-tab-accent);
}

/* The segmented control is a sunken track with a raised thumb gliding on it. */
.basalt-tabs-segmented {
	display: inline-flex;
	max-width: 100%;
}
.basalt-tabs-segmented .basalt-tabs-list {
	gap: 0;
	padding: 0.25rem;
	border-radius: 12px;
	border: 1px solid var(--basalt-edge);
	overflow-x: auto;
	overflow-y: hidden;
	background: var(--basalt-canvas);
	scrollbar-width: none;
}
.basalt-tabs-segmented .basalt-tabs-list::-webkit-scrollbar {
	display: none;
}
.basalt-tabs-segmented .nav-link {
	justify-content: center;
	padding: 0.4rem 0.95rem;
	border-radius: 9px;
	font-size: 0.84rem;
}
.basalt-tabs-segmented .basalt-tabs-ink {
	top: 0;
	bottom: auto;
	border-radius: 9px;
	background: var(--basalt-plane);
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--basalt-copy) 14%, transparent),
		0 0 0 1px var(--basalt-edge);
}

/* Icon-only tabs are square; their names live in aria-label and a tooltip. */
.basalt-tabs-icons .nav-link {
	padding: 0.4rem 0.65rem;
}
.basalt-tabs-icons .nav-link > .bi {
	font-size: 1.05rem;
}

/* The vertical variant is a column whose bar slides along the left edge.
   Each tab may carry a muted hint line under its label. */
.basalt-tabs-vertical .basalt-tabs-list {
	gap: 0.1rem;
	flex-direction: column;
	padding-left: 3px;
	box-shadow: inset 3px 0 0 var(--basalt-edge);
}
.basalt-tabs-vertical .nav-link {
	justify-content: flex-start;
	width: 100%;
	padding: 0.75rem 0.9rem;
	border-radius: 0 10px 10px 0;
	text-align: left;
	white-space: normal;
}
.basalt-tabs-vertical .nav-link:hover:not(.active) {
	background: var(--basalt-wash);
}
.basalt-tabs-vertical .nav-link.active {
	background: var(--basalt-hue-soft);
}
.basalt-tabs-vertical .basalt-tabs-ink {
	left: 0;
	width: 3px;
	border-radius: 3px;
}

.basalt-tabs-text {
	display: flex;
	gap: 0.1rem;
	flex-direction: column;
	min-width: 0;
}

.basalt-tabs-hint {
	font-size: 0.77rem;
	font-weight: 400;
	color: var(--basalt-tab-quiet);
}
.basalt-tabs .nav-link.active .basalt-tabs-hint {
	color: var(--basalt-copy-body);
}

/* The scrolling variant keeps tabs on one sliding row. An arrow sits over
   each end and the edge fades, both only while more lies in that direction. */
.basalt-tabs-scroll {
	display: flex;
	align-items: stretch;
}

.basalt-tabs-viewport {
	flex: 1 1 auto;
	scroll-behavior: smooth;
	min-width: 0;
	overflow-x: auto;
	overflow-y: hidden;
	-webkit-mask-image: linear-gradient(
		90deg,
		transparent 0,
		#000 var(--basalt-tabs-fade-l, 0px),
		#000 calc(100% - var(--basalt-tabs-fade-r, 0px)),
		transparent 100%
	);
	mask-image: linear-gradient(
		90deg,
		transparent 0,
		#000 var(--basalt-tabs-fade-l, 0px),
		#000 calc(100% - var(--basalt-tabs-fade-r, 0px)),
		transparent 100%
	);
	overscroll-behavior-x: contain;
	scrollbar-width: none;
}
.basalt-tabs-viewport::-webkit-scrollbar {
	display: none;
}
.basalt-tabs-viewport .basalt-tabs-list {
	width: max-content;
	min-width: 100%;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-viewport {
		scroll-behavior: auto;
	}
}

.basalt-tabs.has-more-left {
	--basalt-tabs-fade-l: 3.5rem;
}

.basalt-tabs.has-more-right {
	--basalt-tabs-fade-r: 3.5rem;
}

.basalt-tabs-scroll .basalt-tabs-arrow {
	position: absolute;
	top: 50%;
	z-index: 2;
	transform: translateY(-50%);
	box-shadow: var(--basalt-card-shadow);
}

.basalt-tabs-arrow-prev {
	left: 0;
}

.basalt-tabs-arrow-next {
	right: 0;
}

/* The scroll arrows, the add button and the More button share one square
   bordered look; a spent arrow vanishes and stops taking clicks. */
.basalt-tabs-arrow,
.basalt-tabs-add,
.basalt-tabs-more-btn {
	display: inline-grid;
	flex-shrink: 0;
	place-items: center;
	width: 2.1rem;
	height: 2.1rem;
	padding: 0;
	border: 1px solid var(--basalt-edge);
	border-radius: 8px;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease,
		opacity 170ms ease;
}
.basalt-tabs-arrow:hover,
.basalt-tabs-add:hover,
.basalt-tabs-more-btn:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-tabs-arrow:focus-visible,
.basalt-tabs-add:focus-visible,
.basalt-tabs-more-btn:focus-visible {
	outline: none;
	box-shadow: var(--basalt-tab-ring);
}

.basalt-tabs-arrow:disabled {
	opacity: 0;
	pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-arrow {
		transition: none;
	}
}
/* With overflow on, tabs that will not fit are hidden from the row and
   offered in the More menu instead. */
.basalt-tabs[data-basalt-tabs-overflow] {
	display: flex;
	align-items: stretch;
}
.basalt-tabs[data-basalt-tabs-overflow] .basalt-tabs-list {
	flex: 1 1 auto;
	min-width: 0;
}

.basalt-tabs .nav-link.is-overflow {
	display: none;
}

.basalt-tabs-more {
	position: static;
	display: flex;
	flex-shrink: 0;
	align-items: center;
}
.basalt-tabs-more[hidden] {
	display: none;
}
.basalt-tabs-more .dropdown-menu {
	min-width: 12rem;
}
.basalt-tabs-more .dropdown-item {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	font-size: 0.88rem;
}
.basalt-tabs-more .dropdown-item .bi {
	color: var(--basalt-tab-quiet);
}

/* The More button drops the square frame for a text label with a caret. */
.basalt-tabs-more-btn {
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	align-self: stretch;
	width: auto;
	height: auto;
	padding: 0 0.75rem;
	border-color: transparent;
	font-size: 0.86rem;
	font-weight: 600;
	white-space: nowrap;
	background: transparent;
}
.basalt-tabs-more-btn .bi {
	font-size: 0.7rem;
	transition: transform 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-more-btn .bi {
		transition: none;
	}
}
.basalt-tabs-more-btn[aria-expanded="true"] .bi {
	transform: rotate(180deg);
}
.basalt-tabs-more.has-active .basalt-tabs-more-btn {
	color: var(--basalt-copy);
}

/* Closable tabs set a close button beside each tab, never inside it, since
   a button cannot hold a button. Delete or Backspace closes the focused tab
   as well, and tabs fade in and out as they come and go. */
.basalt-tabs-closable {
	display: flex;
	gap: 0.5rem;
	align-items: center;
}
.basalt-tabs-closable .basalt-tabs-list {
	flex: 0 1 auto;
	align-items: flex-end;
	min-width: 0;
	padding-top: 0.25rem;
	overflow-x: auto;
	overflow-y: hidden;
	scrollbar-width: thin;
}
.basalt-tabs-closable .basalt-tabs-item > .nav-link {
	padding-right: 2.2rem;
}
.basalt-tabs-closable .basalt-tabs-item-pinned > .nav-link {
	padding-right: 0.95rem;
}

.basalt-tabs-item {
	position: relative;
	display: flex;
	flex-shrink: 0;
	align-items: center;
}
.basalt-tabs-item.is-leaving {
	animation: basalt-tab-out 180ms ease forwards;
}
.basalt-tabs-item.is-entering {
	animation: basalt-tab-in 210ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-tabs-item.is-leaving,
	.basalt-tabs-item.is-entering {
		animation: none;
	}
}

.basalt-tabs-close {
	position: absolute;
	top: 50%;
	right: 0.4rem;
	z-index: 2;
	transform: translateY(-50%);
	display: inline-grid;
	place-items: center;
	width: 1.4rem;
	height: 1.4rem;
	padding: 0;
	border: 0;
	border-radius: 6px;
	color: var(--basalt-tab-quiet);
	background: transparent;
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
.basalt-tabs-close:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-tabs-close:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
}

@keyframes basalt-tab-in {
	from {
		transform: translateY(4px);
		opacity: 0;
	}
}
@keyframes basalt-tab-out {
	to {
		transform: translateY(4px);
		opacity: 0;
	}
}
/* A printed page has nothing to animate toward. */
@media print {
	.basalt-tabs-ink {
		transition: none;
	}
}
/*
 * Every way the template moves through a long list: Bootstrap's .pagination
 * repainted (plus its pill and ghost looks), cursor and record pagers, the
 * card-header mini pager, step dots, load more, infinite scroll, the A to Z
 * index and the table footer pager. Sections follow the order of the demo on
 * pagination.html; the behavior sits in basalt.js (basaltPagination,
 * basaltPager, basaltLoadMore, basaltInfinite, basaltDots, basaltPageWindow).
 */
/* Bootstrap's pagination variables, keyed by state. The resting state writes
   --bs-pagination-<part>; the others add their name in front of the part. */
/* The small and large scales only change the corner and the type size. */
/* The variable prefix a state adds; the resting state adds none. */
/* Controls that answer the keyboard draw the palette ring, not an outline. */
/* Boxes without a ring of their own show a solid hue outline instead. */
/* A visitor who asks for less motion gets the end state at once. */
/* A page link takes the three colors Bootstrap holds for one state. */
/* Muted label, filled current item and focus ring are shared by every pager
   below, so each one blends its own copy of them from the palette. */
.pagination,
.basalt-pager,
.basalt-loadmore,
.basalt-infinite,
.basalt-cursor-pager,
.basalt-record-pager,
.basalt-minipager,
.basalt-dots,
.basalt-alpha {
	--basalt-page-quiet: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--basalt-page-fill: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--basalt-page-ring: 0 0 0 0.2rem color-mix(in srgb, var(--basalt-hue) 40%, transparent);
}

/* Numbers sit in the body color and the current page wears the brand fill
   with its on-hue label, which keeps every state at 4.5:1. */
.pagination {
	--bs-pagination-color: var(--basalt-copy-body);
	--bs-pagination-bg: var(--basalt-plane);
	--bs-pagination-border-color: var(--basalt-edge);
	--bs-pagination-hover-color: var(--basalt-copy);
	--bs-pagination-hover-bg: var(--basalt-wash);
	--bs-pagination-hover-border-color: var(--basalt-edge-strong);
	--bs-pagination-focus-color: var(--basalt-copy);
	--bs-pagination-focus-bg: var(--basalt-wash);
	--bs-pagination-focus-box-shadow: var(--basalt-page-ring);
	--bs-pagination-active-color: var(--basalt-on-hue);
	--bs-pagination-active-bg: var(--basalt-page-fill);
	--bs-pagination-active-border-color: var(--basalt-page-fill);
	--bs-pagination-disabled-color: var(--basalt-page-quiet);
	--bs-pagination-disabled-bg: var(--basalt-canvas);
	--bs-pagination-disabled-border-color: var(--basalt-edge);
	--bs-pagination-border-radius: 10px;
	--bs-pagination-font-size: 0.9rem;
	row-gap: 0.3rem;
	flex-wrap: wrap;
}
.pagination .page-link {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	justify-content: center;
	min-width: 2.4em;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--bs-pagination-color);
}
.pagination .page-link:hover {
	color: var(--bs-pagination-hover-color);
}
.pagination .page-link:focus-visible {
	z-index: 3;
	color: var(--bs-pagination-focus-color);
}
.pagination .page-item.active .page-link,
.pagination .page-link.active {
	border-color: var(--bs-pagination-active-border-color);
	color: var(--bs-pagination-active-color);
	background-color: var(--bs-pagination-active-bg);
}
.pagination .page-item.disabled .page-link,
.pagination .page-link.disabled,
.pagination .page-link:disabled {
	border-color: var(--bs-pagination-disabled-border-color);
	color: var(--bs-pagination-disabled-color);
	background-color: var(--bs-pagination-disabled-bg);
}
.pagination {
	/* Skipped pages read as a word to screen readers and as spaced dots here. */
}
.pagination .page-item.is-gap .page-link {
	min-width: 2em;
	letter-spacing: 0.1em;
}

.pagination-sm {
	--bs-pagination-border-radius: 8px;
	--bs-pagination-font-size: 0.8rem;
}

.pagination-lg {
	--bs-pagination-border-radius: 12px;
	--bs-pagination-font-size: 1.05rem;
}

button.page-link {
	font-family: inherit;
}

/* Pill and ghost both pull the links apart, so the joined corners Bootstrap
   draws on the first and last item give way to one radius for all. */
/* The pill look spaces round buttons of one fixed height. */
.basalt-pagination-pill {
	gap: 0.3rem;
}
.basalt-pagination-pill .page-link,
.basalt-pagination-pill .page-item:first-child .page-link,
.basalt-pagination-pill .page-item:last-child .page-link {
	margin-left: 0;
	border-radius: 999px;
}
.basalt-pagination-pill .page-link {
	min-width: 2.5em;
	height: 2.5em;
	padding-top: 0;
	padding-bottom: 0;
}

/* The ghost look hides every box until hover and marks the page with a
   soft tint rather than a solid fill. */
.basalt-pagination-ghost {
	--bs-pagination-bg: transparent;
	--bs-pagination-border-color: transparent;
	--bs-pagination-hover-border-color: transparent;
	--bs-pagination-disabled-bg: transparent;
	--bs-pagination-disabled-border-color: transparent;
	--bs-pagination-active-bg: var(--basalt-hue-soft);
	--bs-pagination-active-border-color: var(--basalt-hue-border);
	--bs-pagination-active-color: var(--basalt-copy);
	gap: 0.2rem;
}
.basalt-pagination-ghost .page-link,
.basalt-pagination-ghost .page-item:first-child .page-link,
.basalt-pagination-ghost .page-item:last-child .page-link {
	margin-left: 0;
	border-radius: 8px;
}

/* Feeds whose page numbers drift step by Newer and Older; the caption
   between them names the stretch on screen. */
.basalt-cursor-pager .btn {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
}
.basalt-cursor-pager-bar {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: auto minmax(0, 1fr) auto;
	align-items: center;
	margin-top: 1rem;
	padding-top: 1rem;
	border-top: 1px solid var(--basalt-edge);
}
.basalt-cursor-pager-caption {
	margin: 0;
	font-size: 0.8rem;
	line-height: 1.45;
	text-align: center;
	color: var(--basalt-page-quiet);
}
.basalt-cursor-pager-caption strong {
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-copy);
}

/* On a detail page the neighbors on each side are named outright, and the
   position counter sits between them; on a phone it moves above both. */
.basalt-record-pager {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	align-items: stretch;
}
@media (max-width: 575.98px) {
	.basalt-record-pager {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	}
}
.basalt-record-pager-link {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	min-width: 0;
	padding: 0.75rem 0.9rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	font: inherit;
	text-align: left;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	cursor: pointer;
	transition:
		background-color 170ms ease,
		border-color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-record-pager-link {
		transition: none;
	}
}
.basalt-record-pager-link > .bi {
	flex-shrink: 0;
	font-size: 1rem;
	color: var(--basalt-page-quiet);
}
.basalt-record-pager-link-next {
	flex-direction: row-reverse;
	text-align: right;
}
.basalt-record-pager-link:hover {
	border-color: var(--basalt-edge-strong);
	background: var(--basalt-wash);
}
.basalt-record-pager-link:focus-visible {
	outline: none;
	box-shadow: var(--basalt-page-ring);
}
.basalt-record-pager-link:disabled {
	border-style: dashed;
	background: var(--basalt-canvas);
	cursor: not-allowed;
}
.basalt-record-pager-text {
	display: flex;
	gap: 0.1rem;
	flex-direction: column;
	min-width: 0;
}
.basalt-record-pager-dir {
	font-size: 0.74rem;
	font-weight: 600;
	color: var(--basalt-page-quiet);
}
.basalt-record-pager-name {
	overflow: hidden;
	font-size: 0.88rem;
	font-weight: 600;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.basalt-record-pager-link:disabled .basalt-record-pager-name {
	font-weight: 400;
	color: var(--basalt-page-quiet);
}
.basalt-record-pager-pos {
	display: flex;
	gap: 0.1rem;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	margin: 0;
	padding: 0 0.5rem;
	font-size: 0.77rem;
	white-space: nowrap;
	color: var(--basalt-page-quiet);
}
.basalt-record-pager-pos strong {
	font:
		700 1.05rem/1.1 "Chivo Mono",
		monospace;
	color: var(--basalt-copy);
}
@media (max-width: 575.98px) {
	.basalt-record-pager-pos {
		gap: 0.4rem;
		flex-direction: row;
		grid-column: 1/-1;
		order: -1;
	}
}

/* A card header pages with two small arrows around a "2 / 5" counter. */
.basalt-minipager {
	display: inline-flex;
	gap: 0.25rem;
	align-items: center;
}
.basalt-minipager-btn {
	display: inline-grid;
	place-items: center;
	width: 1.9rem;
	height: 1.9rem;
	padding: 0;
	border: 1px solid var(--basalt-edge);
	border-radius: 8px;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-minipager-btn {
		transition: none;
	}
}
.basalt-minipager-btn:hover:not(:disabled) {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-minipager-btn:focus-visible {
	outline: none;
	box-shadow: var(--basalt-page-ring);
}
.basalt-minipager-btn:disabled {
	border-style: dashed;
	color: var(--basalt-page-quiet);
	background: var(--basalt-canvas);
	cursor: not-allowed;
}
.basalt-minipager-pos {
	min-width: 3.25rem;
	font:
		600 0.8rem/1 "Chivo Mono",
		monospace;
	text-align: center;
	color: var(--basalt-copy);
}
.basalt-minipager-pos span {
	color: var(--basalt-page-quiet);
}

/* Slides and steps get a row of dots; the current one stretches into a bar
   and the arrow keys walk along the row. */
.basalt-dots {
	display: inline-flex;
	gap: 0.1rem;
	align-items: center;
}
.basalt-dots-dot {
	position: relative;
	display: inline-grid;
	place-items: center;
	width: 1.5rem;
	height: 1.5rem;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: transparent;
	cursor: pointer;
	transition: width 280ms cubic-bezier(0.3, 0.7, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-dots-dot {
		transition: none;
	}
}
.basalt-dots-dot::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 999px;
	background: var(--basalt-edge-strong);
	transition:
		width 280ms cubic-bezier(0.3, 0.7, 0.2, 1),
		background-color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-dots-dot::before {
		transition: none;
	}
}
.basalt-dots-dot:hover::before {
	background: var(--basalt-page-quiet);
}
.basalt-dots-dot[aria-current="true"] {
	width: 2.25rem;
}
.basalt-dots-dot[aria-current="true"]::before {
	width: 1.6rem;
	background: var(--basalt-hue);
}
.basalt-dots-dot:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 0;
}

/* Load more drops the next batch under the list. Its footer stacks a meter,
   a count of what is showing, a button that spins while busy, and a done
   line once nothing is left. */
.basalt-loadmore-foot {
	display: flex;
	gap: 0.7rem;
	flex-direction: column;
	align-items: center;
	margin-top: 1.25rem;
	text-align: center;
}
.basalt-loadmore-meter {
	width: min(16rem, 100%);
	height: 4px;
	border-radius: 4px;
	overflow: hidden;
	background: var(--basalt-canvas);
	box-shadow: inset 0 0 0 1px var(--basalt-edge);
}
.basalt-loadmore-meter > span {
	display: block;
	width: var(--basalt-loadmore-done, 0%);
	height: 100%;
	border-radius: inherit;
	background: var(--basalt-hue);
	transition: width 360ms cubic-bezier(0.3, 0.7, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-loadmore-meter > span {
		transition: none;
	}
}
.basalt-loadmore-btn {
	display: inline-flex;
	gap: 0.5rem;
	align-items: center;
	justify-content: center;
	min-width: 11rem;
}
.basalt-loadmore-btn .spinner-border {
	display: none;
	width: 0.9rem;
	height: 0.9rem;
	border-width: 0.15em;
	color: currentColor;
}
.basalt-loadmore-btn.is-loading {
	cursor: progress;
}
.basalt-loadmore-btn.is-loading .spinner-border {
	display: inline-block;
}
.basalt-loadmore-btn.is-loading .basalt-loadmore-icon {
	display: none;
}
.basalt-loadmore-done {
	display: inline-flex;
	gap: 0.4rem;
	align-items: center;
	margin: 0;
	font-size: 0.86rem;
	font-weight: 600;
	color: var(--basalt-copy);
}
.basalt-loadmore-done[hidden] {
	display: none;
}
.basalt-loadmore-done .bi {
	color: color-mix(in srgb, var(--basalt-success) 55%, var(--basalt-copy));
}
.basalt-loadmore {
	/* Fresh rows fade up, and the first of them takes focus so a keyboard
      user lands where the list grew. */
}
.basalt-loadmore-new {
	animation: basalt-page-in 320ms ease both;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-loadmore-new {
		animation: none;
	}
}
.basalt-loadmore-new:focus {
	outline: none;
}
.basalt-loadmore-new:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	border-radius: 8px;
}

/* Both running counts share one look: quiet, small, figures in columns. */
.basalt-loadmore-status,
.basalt-infinite-status {
	margin: 0;
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-page-quiet);
}

/* A figure picked out inside a range or a count reads in full ink. */
.basalt-pager-range strong,
.basalt-loadmore-status strong {
	font-weight: 600;
	color: var(--basalt-copy);
}

@keyframes basalt-page-in {
	from {
		transform: translateY(6px);
		opacity: 0;
	}
}
/* Gray placeholder rows hold the space while a batch is still loading. */
.basalt-skeleton-row {
	display: grid;
	gap: 0.9rem;
	grid-template-columns: 2.5rem minmax(0, 1fr) 4rem;
	align-items: center;
	padding: 0.7rem 0;
}
.basalt-skeleton-row > span {
	display: block;
	height: 0.75rem;
	border-radius: 6px;
	background: linear-gradient(90deg, var(--basalt-canvas) 0%, var(--basalt-wash) 50%, var(--basalt-canvas) 100%);
	background-size: 200% 100%;
	animation: basalt-page-shimmer 1.1s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-skeleton-row > span {
		animation: none;
	}
}
.basalt-skeleton-row > span:first-child {
	height: 2.5rem;
	border-radius: 10px;
}

@keyframes basalt-page-shimmer {
	from {
		background-position: 100% 0;
	}
	to {
		background-position: -100% 0;
	}
}
/* Infinite scroll fetches more as the end of its box comes into view; a
   switch below turns that off in favor of a button. */
.basalt-infinite .form-check-label {
	font-size: 0.86rem;
	color: var(--basalt-copy-body);
}
.basalt-infinite-box {
	position: relative;
	max-height: 22rem;
	padding: 0 1rem;
	border: 1px solid var(--basalt-edge);
	border-radius: 12px;
	overflow-y: auto;
	background: var(--basalt-plane);
	overscroll-behavior: contain;
}
.basalt-infinite-box:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}
.basalt-infinite-sentinel {
	height: 1px;
}
.basalt-infinite-end {
	display: flex;
	gap: 0.4rem;
	align-items: center;
	justify-content: center;
	margin: 0;
	padding: 1rem 0 1.1rem;
	font-size: 0.8rem;
	color: var(--basalt-page-quiet);
}
.basalt-infinite-end[hidden] {
	display: none;
}
.basalt-infinite-foot {
	display: flex;
	gap: 0.75rem 1rem;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	margin-top: 1rem;
}

/* Long directories jump by letter. A letter with nobody under it stays in
   the row, struck through and out of reach. */
.basalt-alpha {
	display: flex;
	gap: 0.25rem;
	flex-wrap: wrap;
}
.basalt-alpha-key {
	display: inline-block;
	min-width: 2rem;
	height: 2rem;
	padding: 0 0.4rem;
	border: 1px solid transparent;
	border-radius: 8px;
	font:
		600 0.8rem "Chivo Mono",
		monospace;
	line-height: calc(2rem - 2px);
	text-align: center;
	color: var(--basalt-copy-body);
	background: transparent;
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease,
		border-color 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-alpha-key {
		transition: none;
	}
}
.basalt-alpha-key:hover:not(:disabled) {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-alpha-key:focus-visible {
	outline: none;
	box-shadow: var(--basalt-page-ring);
}
.basalt-alpha-key[aria-pressed="true"] {
	border-color: var(--basalt-page-fill);
	color: var(--basalt-on-hue);
	background: var(--basalt-page-fill);
}
.basalt-alpha-key:disabled {
	font-weight: 400;
	text-decoration: line-through;
	text-decoration-color: var(--basalt-page-quiet);
	color: var(--basalt-page-quiet);
	cursor: default;
}
.basalt-alpha-key-all {
	font-family: inherit;
}

/* Under a table one wrapping row carries the page size, the range shown,
   the page buttons and a jump-to box. Below tablet width the buttons take
   a line of their own on top. */
.basalt-pager {
	display: flex;
	gap: 0.75rem 1.25rem;
	flex-wrap: wrap;
	align-items: center;
	padding-top: 1rem;
	border-top: 1px solid var(--basalt-edge);
	font-size: 0.85rem;
}
.basalt-pager-size,
.basalt-pager-jump {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	margin: 0;
}
.basalt-pager-size .form-select,
.basalt-pager-size .basalt-select-trigger {
	width: auto;
	min-width: 4.5rem;
}
.basalt-pager-label {
	margin: 0;
	font-size: 0.8rem;
	font-weight: 600;
	white-space: nowrap;
	color: var(--basalt-page-quiet);
}
.basalt-pager-range {
	margin: 0;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-copy-body);
}
.basalt-pager-nav {
	margin-left: auto;
}
@media (max-width: 767.98px) {
	.basalt-pager-nav {
		flex-basis: 100%;
		order: -1;
		margin-left: 0;
	}
}
.basalt-pager-jump {
	position: relative;
}
.basalt-pager-jump .form-control {
	width: 4.5rem;
	text-align: center;
	font-variant-numeric: tabular-nums;
}
.basalt-pager-jump .form-control::-webkit-inner-spin-button {
	opacity: 0.6;
}
.basalt-pager {
	/* A bad page number is reported on a full-width line after everything. */
}
.basalt-pager-error {
	flex-basis: 100%;
	order: 9;
	margin: 0;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-danger) 55%, var(--basalt-copy));
}
.basalt-pager-error[hidden] {
	display: none;
}

/* Bootstrap's tooltip and popover take their colors, type and radii from the
   Basalt tokens here, and every hint built on top of them lives alongside:
   tinted tips, key-combination hints, clipped text that explains itself,
   confirm and edit popovers, the toggletip, the person card and the guided
   tour. tooltips.html shows each one; Basalt.tips in basalt.js reads
   the [data-basalt-*] attributes that switch them on. */
/* Soft tips borrow one status color for the fill, the text and the outline. */
/* Bootstrap reads each component's settings from --bs-<component>-* custom
   properties, so a whole set is written from one map. */
/* Keyboard focus draws a solid outline instead of Bootstrap's glow. */
/* Status tips keep their text near the body color, so contrast holds 4.5:1. */
.tooltip.basalt-tip-danger,
.tooltip.basalt-tip-warning,
.tooltip.basalt-tip-success {
	--bs-tooltip-bg: color-mix(in srgb, var(--basalt-tip-tone) 16%, var(--basalt-plane));
	--bs-tooltip-color: color-mix(in srgb, var(--basalt-tip-tone) 38%, var(--basalt-copy));
	filter: drop-shadow(0 0 1px color-mix(in srgb, var(--basalt-tip-tone) 70%, transparent))
		drop-shadow(0 6px 14px color-mix(in srgb, var(--basalt-copy) 12%, transparent));
}

/* A bare tooltip is dark ink on the page color, left-aligned, in the UI face. */
.tooltip {
	--bs-tooltip-bg: var(--basalt-copy);
	--bs-tooltip-color: var(--basalt-plane);
	--bs-tooltip-font-size: 0.8rem;
	--bs-tooltip-padding-x: 0.65rem;
	--bs-tooltip-padding-y: 0.4rem;
	--bs-tooltip-border-radius: 8px;
	--bs-tooltip-max-width: 240px;
	--bs-tooltip-opacity: 1;
	font-family: "Schibsted Grotesk", sans-serif;
	font-weight: 500;
	line-height: 1.4;
}
.tooltip .tooltip-inner {
	text-align: left;
}
.tooltip .tooltip-inner strong {
	font-weight: 700;
}

/* Tones come from data-bs-custom-class; the plain ink tip needs none. The
   light tip gets a hairline and a lift because its fill matches the cards. */
.tooltip.basalt-tip-light {
	--bs-tooltip-bg: var(--basalt-plane);
	--bs-tooltip-color: var(--basalt-copy);
	filter: drop-shadow(0 0 1px color-mix(in srgb, var(--basalt-copy) 45%, transparent))
		drop-shadow(0 6px 14px color-mix(in srgb, var(--basalt-copy) 16%, transparent));
}
.tooltip.basalt-tip-primary {
	--bs-tooltip-bg: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--bs-tooltip-color: var(--basalt-on-hue);
}
.tooltip.basalt-tip-success {
	--basalt-tip-tone: var(--basalt-success);
}
.tooltip.basalt-tip-warning {
	--basalt-tip-tone: var(--basalt-warning);
}
.tooltip.basalt-tip-danger {
	--basalt-tip-tone: var(--basalt-danger);
}
.tooltip[class*="basalt-tip--"] .tooltip-inner .bi {
	margin-right: 0.3rem;
}

/* Shortcut hints set the label and its keys on one line, keys in mono caps. */
.basalt-tip-row {
	display: inline-flex;
	gap: 0.6rem;
	align-items: center;
	white-space: nowrap;
}

.basalt-tip-keys {
	display: inline-flex;
	gap: 0.2rem;
}
.basalt-tip-keys kbd {
	min-width: 1.35rem;
	padding: 0.1rem 0.3rem;
	border-radius: 5px;
	font-family: "Chivo Mono", monospace;
	font-size: 0.7rem;
	font-weight: 500;
	line-height: 1.3;
	text-align: center;
	color: inherit;
	background: color-mix(in srgb, var(--bs-tooltip-color) 18%, transparent);
	box-shadow: none;
}

/* Clipped text only earns its dotted underline and tab stop once it is cut. */
.basalt-ellipsis {
	display: block;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.basalt-ellipsis.is-truncated {
	text-decoration: underline dotted color-mix(in srgb, var(--basalt-copy-muted) 60%, transparent);
	text-underline-offset: 3px;
	cursor: help;
}
.basalt-ellipsis:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	box-shadow: none;
	border-radius: 3px;
}

/* Popovers sit on the card surface with the card shadow and token text. */
.popover {
	--bs-popover-bg: var(--basalt-plane);
	--bs-popover-border-color: var(--basalt-edge-strong);
	--bs-popover-border-radius: 12px;
	--bs-popover-inner-border-radius: 11px;
	--bs-popover-box-shadow: var(--basalt-card-shadow);
	--bs-popover-font-size: 0.85rem;
	--bs-popover-max-width: 300px;
	--bs-popover-header-bg: var(--basalt-plane);
	--bs-popover-header-color: var(--basalt-copy);
	--bs-popover-header-font-size: 0.9rem;
	--bs-popover-header-padding-x: 1rem;
	--bs-popover-header-padding-y: 0.75rem;
	--bs-popover-body-color: var(--basalt-copy-body);
	--bs-popover-body-padding-x: 1rem;
	--bs-popover-body-padding-y: 0.8rem;
	font-family: "Schibsted Grotesk", sans-serif;
	line-height: 1.5;
	box-shadow: var(--bs-popover-box-shadow);
}
.popover .popover-header {
	border-bottom-color: var(--basalt-edge);
	font-weight: 650;
}
.popover .popover-body ul {
	margin: 0;
	padding-left: 1.1rem;
}
.popover .popover-body li + li {
	margin-top: 0.25rem;
}

/* A confirm popover asks one question and puts its answers bottom right. */
.popover.basalt-popconfirm {
	--bs-popover-max-width: 280px;
}

.basalt-popconfirm-title {
	margin: 0 0 0.3rem;
	font-size: 0.9rem;
	font-weight: 650;
	color: var(--basalt-copy);
}
.basalt-popconfirm-title .bi {
	margin-right: 0.3rem;
	color: color-mix(in srgb, var(--basalt-danger) 60%, var(--basalt-copy));
}

.basalt-popconfirm-text {
	margin: 0 0 0.9rem;
	font-size: 0.8rem;
	color: var(--basalt-copy-body);
}

.basalt-popconfirm-actions {
	display: flex;
	gap: 0.5rem;
	justify-content: flex-end;
}

/* The edit popover is a one-field form that validates before it saves; an
   invalid value gets a red edge and ring instead of Bootstrap's icon. */
.popover.basalt-edit {
	--bs-popover-max-width: 260px;
	width: 260px;
	max-width: calc(100vw - 2rem);
}

.basalt-edit .form-label {
	margin-bottom: 0.3rem;
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--basalt-copy);
}

.basalt-edit-actions {
	display: flex;
	gap: 0.5rem;
	justify-content: flex-end;
	margin-top: 0.8rem;
}

.basalt-edit .invalid-feedback {
	font-size: 0.75rem;
	color: color-mix(in srgb, var(--basalt-danger) 58%, var(--basalt-copy));
}
.basalt-edit .form-control.is-invalid {
	padding-right: 0.75rem;
	border-color: var(--basalt-danger);
	background-image: none;
}
.basalt-edit .form-control.is-invalid:focus {
	box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--basalt-danger) 30%, transparent);
}
.basalt-edit .input-group-text {
	border-color: var(--basalt-edge-strong);
	font-size: 0.8rem;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane-alt);
}

/* A hint is a small (i) after a figure's label. It sits on the text's
   baseline at the label's own size, so adding one never changes a line. */
/* A control at a limit (Basalt.limit) keeps its disabled look but stays
   under the pointer, so its tooltip can say why. */
.btn.disabled[data-basalt-limit] {
	pointer-events: auto;
	cursor: not-allowed;
}

[data-basalt-limit][aria-disabled="true"]:not(.btn) {
	opacity: 0.4;
	cursor: not-allowed;
}

.basalt-hint {
	display: inline-grid;
	place-items: center;
	width: 1.05em;
	height: 1.05em;
	margin-inline-start: 0.3em;
	padding: 0;
	border: 0;
	border-radius: 50%;
	font-size: 0.9em;
	line-height: 1;
	vertical-align: -0.12em;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: transparent;
	opacity: 0.75;
	cursor: help;
	transition:
		color 150ms ease,
		opacity 150ms ease;
	/* The glyph fills the button's box exactly, so the box's middle is the
     circle's middle and the -0.12em above lands it on the capitals' middle. */
}
.basalt-hint .bi,
.basalt-hint .bi::before {
	display: block;
	font-size: 1em;
	line-height: 1;
	vertical-align: 0;
}
.basalt-hint:hover,
.basalt-hint[aria-describedby] {
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	opacity: 1;
}
.basalt-hint:focus-visible {
	opacity: 1;
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
	box-shadow: none;
}

/* The label's last word and its (i) never part across lines. */
.basalt-hint-tail {
	white-space: nowrap;
}

/* A toggletip opens on click rather than hover, so touch and screen readers get it too. */
.basalt-toggletip {
	position: relative;
	display: inline-flex;
	vertical-align: middle;
}

.basalt-toggletip-btn {
	display: inline-grid;
	place-items: center;
	width: 1.5rem;
	height: 1.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	font-size: 0.9rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: transparent;
	cursor: pointer;
	transition:
		background-color 170ms ease,
		color 170ms ease;
}
.basalt-toggletip-btn:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-toggletip-btn[aria-expanded="true"] {
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
}
.basalt-toggletip-btn:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
	box-shadow: none;
}

/* The bubble hangs under its button; the script nudges it and its arrow inside the viewport. */
.basalt-toggletip-bubble {
	--basalt-toggletip-shift: 0px;
	--basalt-toggletip-arrow: 1rem;
	position: absolute;
	top: calc(100% + 0.5rem);
	left: calc(-0.5rem + var(--basalt-toggletip-shift));
	z-index: 20;
	width: max-content;
	max-width: min(17rem, 100vw - 2.5rem);
	padding: 0.7rem 0.85rem;
	border-radius: 10px;
	font-size: 0.8rem;
	font-weight: 500;
	line-height: 1.45;
	text-align: left;
	white-space: normal;
	color: var(--basalt-plane);
	background: var(--basalt-copy);
	box-shadow: 0 10px 24px color-mix(in srgb, var(--basalt-copy) 22%, transparent);
}
.basalt-toggletip-bubble[hidden] {
	display: none;
}
.basalt-toggletip-bubble::before {
	content: "";
	position: absolute;
	top: -5px;
	left: calc(var(--basalt-toggletip-arrow) - 5px);
	transform: rotate(45deg);
	width: 10px;
	height: 10px;
	border-radius: 2px 0 0 0;
	background: inherit;
}

/* The hover card previews a person and stays open while the pointer rests on it. */
.popover.basalt-hovercard {
	--bs-popover-max-width: 320px;
	--bs-popover-body-padding-x: 0;
	--bs-popover-body-padding-y: 0;
	width: 320px;
	max-width: calc(100vw - 2rem);
}

.basalt-hovercard-head {
	display: flex;
	gap: 0.85rem;
	align-items: center;
	padding: 1rem 1rem 0.85rem;
}

.basalt-hovercard-avatar {
	display: inline-grid;
	flex-shrink: 0;
	place-items: center;
	width: 46px;
	height: 46px;
	border-radius: 50%;
	font-weight: 700;
	font-size: 0.95rem;
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
}

.basalt-hovercard-name {
	margin: 0;
	font-size: 0.95rem;
	font-weight: 650;
	line-height: 1.3;
	color: var(--basalt-copy);
}

.basalt-hovercard-role {
	margin: 0;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* Three figures share a ruled strip, each value printed above its label. */
.basalt-hovercard-stats {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	margin: 0;
	border-top: 1px solid var(--basalt-edge);
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-hovercard-stats > div {
	display: flex;
	gap: 0.1rem;
	flex-direction: column-reverse;
	padding: 0.7rem 1rem;
}
.basalt-hovercard-stats > div + div {
	border-left: 1px solid var(--basalt-edge);
}
.basalt-hovercard-stats dt {
	font-weight: 500;
	font-size: 0.71rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-hovercard-stats dd {
	margin: 0;
	font-size: 0.95rem;
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-hovercard-note {
	margin: 0;
	padding: 0.75rem 1rem 0;
	font-size: 0.8rem;
	color: var(--basalt-copy-body);
}

.basalt-hovercard-actions {
	display: flex;
	gap: 0.5rem;
	padding: 0.85rem 1rem 1rem;
}
.basalt-hovercard-actions .btn {
	flex: 1 1 0;
}

.basalt-hovercard-status {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	margin-top: 0.1rem;
	font-size: 0.71rem;
	font-weight: 600;
	color: color-mix(in srgb, var(--basalt-success) 42%, var(--basalt-copy));
}
.basalt-hovercard-status::before {
	content: "";
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--basalt-success);
}

/* The tour rings the step it describes and walks forward one popover at a time. */
.basalt-tour-scope {
	position: relative;
}

.basalt-tour-target {
	position: relative;
	z-index: 2;
	border-radius: 8px;
	box-shadow:
		0 0 0 3px var(--basalt-plane),
		0 0 0 5px var(--basalt-hue);
	animation: basalt-tour-ring 1.6s ease-out infinite;
}

@keyframes basalt-tour-ring {
	0% {
		box-shadow:
			0 0 0 3px var(--basalt-plane),
			0 0 0 5px var(--basalt-hue),
			0 0 0 5px color-mix(in srgb, var(--basalt-hue) 40%, transparent);
	}
	100% {
		box-shadow:
			0 0 0 3px var(--basalt-plane),
			0 0 0 5px var(--basalt-hue),
			0 0 0 14px color-mix(in srgb, var(--basalt-hue) 0%, transparent);
	}
}
.popover.basalt-tour {
	--bs-popover-max-width: 300px;
	width: 300px;
	max-width: calc(100vw - 2.5rem);
}
.popover.basalt-tour .popover-body {
	position: relative;
	padding: 1rem 1.1rem 1rem;
}

.basalt-tour-count {
	margin: 0 0 0.3rem;
	font-family: "Chivo Mono", monospace;
	font-size: 0.7rem;
	font-weight: 500;
	letter-spacing: 0.035em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
}

.basalt-tour-title {
	margin: 0 1.75rem 0.3rem 0;
	font-size: 0.95rem;
	font-weight: 650;
	color: var(--basalt-copy);
}

.basalt-tour-text {
	margin: 0 0 1rem;
	font-size: 0.83rem;
	line-height: 1.55;
	color: var(--basalt-copy-body);
}

.basalt-tour-foot {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	justify-content: space-between;
}

/* Progress dots: the current step stretches into a short bar. */
.basalt-tour-dots {
	display: inline-flex;
	gap: 0.3rem;
}
.basalt-tour-dots span {
	width: 6px;
	height: 6px;
	border-radius: 3px;
	background: var(--basalt-edge-strong);
	transition:
		width 200ms ease,
		background-color 200ms ease;
}
.basalt-tour-dots span.is-on {
	width: 16px;
	background: var(--basalt-hue);
}

.basalt-tour-nav {
	display: inline-flex;
	gap: 0.4rem;
}

.basalt-tour-close {
	position: absolute;
	top: 0.6rem;
	right: 0.6rem;
	display: inline-grid;
	place-items: center;
	width: 1.75rem;
	height: 1.75rem;
	padding: 0;
	border: 0;
	border-radius: 6px;
	font-size: 0.8rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: transparent;
}
.basalt-tour-close:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-tour-close:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 1px;
	box-shadow: none;
}

/* Reduced motion stills the ring, the dots and Bootstrap's fades. */
@media (prefers-reduced-motion: reduce) {
	.basalt-toggletip-btn,
	.basalt-tour-dots span,
	.tooltip.fade,
	.popover.fade {
		transition: none;
	}
	.basalt-tour-target {
		animation: none;
	}
}
/* On paper nothing floats, and the ring holds still. */
@media print {
	.tooltip,
	.popover {
		display: none;
	}
	.basalt-tour-target {
		animation: none;
	}
}
/* Text, from Bootstrap's own inline elements up to the larger reading pieces
   built on top of them: keys and key combinations, headings and quotes, the
   list group and the breadcrumb trail (folding one included), the type scale
   specimen, eyebrows, steady figures and deltas, clamped paragraphs, step
   lists and icon lists. typography.html walks through all of it; the
   behavior behind [data-basalt-type-scale], kbd[data-basalt-key],
   [data-basalt-clamp-toggle] and .basalt-breadcrumb-collapse is
   Basalt.text in basalt.js. */
/* Small text controls drop the default glow for a crisp ring set off the edge. */
/* Bootstrap ships its own monospace stack and a pink code color; neither
   belongs here, so every code-like element reads the template's face and
   tokens instead. */
code,
kbd,
samp,
pre,
.font-monospace {
	font-family: "Chivo Mono", monospace;
}

code {
	padding: 0.05em 0.3em;
	border: 1px solid var(--basalt-edge);
	border-radius: 4px;
	font-size: 0.85em;
	color: var(--basalt-copy);
	background: var(--basalt-canvas);
}
pre code {
	padding: 0;
	border: 0;
	font-size: inherit;
	background: none;
}

/* A key is a small raised cap: thicker underside, centered glyph. */
kbd {
	display: inline-block;
	min-width: 1.6em;
	padding: 0.12rem 0.4rem;
	border: 1px solid var(--basalt-edge-strong);
	border-bottom-width: 2px;
	border-radius: 6px;
	font-size: 0.75rem;
	font-weight: 500;
	line-height: 1.35;
	text-align: center;
	color: var(--basalt-copy);
	background: var(--basalt-plane);
	box-shadow: none;
}

/* Combinations line their caps up in a row, e.g.
   <span class="basalt-keys"><kbd>⌘</kbd><kbd>K</kbd></span>; a word such as
   "then" between caps means the keys go one after another. A cap the script
   marks as pressed sinks by a pixel. */
.basalt-keys {
	display: inline-flex;
	gap: 0.25rem;
	align-items: center;
	white-space: nowrap;
}
.basalt-keys-then {
	padding: 0 0.1rem;
	font-size: 0.75rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-keys kbd {
	transition:
		transform 90ms ease,
		background-color 90ms ease,
		border-color 90ms ease;
}
.basalt-keys kbd.is-pressed {
	transform: translateY(1px);
	margin-bottom: 1px;
	border-bottom-width: 1px;
	border-color: var(--basalt-hue-border);
	background: var(--basalt-hue-soft);
}
@media (prefers-reduced-motion: reduce) {
	.basalt-keys kbd {
		transition: none;
	}
}

mark,
.mark {
	padding: 0.05em 0.25em;
	border-radius: 3px;
	color: var(--basalt-copy);
	background: color-mix(in srgb, var(--basalt-warning) 30%, var(--basalt-plane));
}

/* Edits and abbreviations keep their native marks, tinted to the palette. */
del {
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

ins {
	text-decoration-color: var(--basalt-success);
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

abbr[title] {
	text-decoration-color: color-mix(in srgb, var(--basalt-copy-muted) 70%, transparent);
	text-underline-offset: 3px;
}

/* Schibsted Grotesk has nothing as light as the 300 Bootstrap asks for on
   .lead and the display sizes, which leaves the browser to fake a weight.
   The lead sits at a true regular, and display type is as bold as the
   headings around it. */
.lead {
	font-weight: 400;
}

.display-1,
.display-2,
.display-3,
.display-4,
.display-5,
.display-6 {
	font-weight: 700;
	letter-spacing: -0.025em;
}

/* The base styles size small in rem, so a subtitle inside a heading would fall
   to body size; here it is a share of the heading instead. */
:is(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6) > small {
	font-size: 0.62em;
	font-weight: 500;
	letter-spacing: 0;
}

.blockquote {
	color: var(--basalt-copy);
}
.blockquote-footer {
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* The list group maps its slots onto the palette, so the selected row takes
   the accent and a disabled one goes quiet instead of Bootstrap's blue and
   gray. */
.list-group {
	--bs-list-group-color: var(--basalt-copy-body);
	--bs-list-group-bg: var(--basalt-plane);
	--bs-list-group-border-color: var(--basalt-edge);
	--bs-list-group-border-radius: 12px;
	--bs-list-group-action-color: var(--basalt-copy-body);
	--bs-list-group-action-hover-color: var(--basalt-copy);
	--bs-list-group-action-hover-bg: var(--basalt-wash);
	--bs-list-group-action-active-color: var(--basalt-copy);
	--bs-list-group-action-active-bg: var(--basalt-plane-alt);
	--bs-list-group-disabled-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-list-group-disabled-bg: var(--basalt-canvas);
	--bs-list-group-active-color: var(--basalt-on-hue);
	--bs-list-group-active-bg: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	--bs-list-group-active-border-color: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
}

.list-group-item.active {
	border-color: var(--bs-list-group-active-border-color);
	color: var(--basalt-on-hue);
	background-color: var(--bs-list-group-active-bg);
}
.list-group-item {
	/* Leading icons get a box of their own width, so a column of them stays
      aligned whatever each glyph measures. */
}
.list-group-item > .bi:first-child {
	display: inline-block;
	flex-shrink: 0;
	width: 1.25em;
	text-align: center;
}

.list-group-item-action:focus-visible {
	z-index: 3;
	outline: 0;
	box-shadow: inset 0 0 0 2px var(--basalt-hue);
}

.list-group-numbered > .list-group-item::before {
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}

/* Trail links stay quiet until pointed at; the current page is the bold one.
   Inside a folding trail, the middle levels hide behind a "…" button until
   it is pressed. */
.breadcrumb {
	--bs-breadcrumb-divider-color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	--bs-breadcrumb-item-active-color: var(--basalt-copy);
	font-size: 0.875rem;
}

.breadcrumb-item a {
	border-radius: 4px;
	text-decoration: none;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.breadcrumb-item a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
	color: var(--basalt-copy);
}
.breadcrumb-item a:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	box-shadow: none;
}
.breadcrumb-item.active {
	font-weight: 600;
}
.breadcrumb-item .bi {
	margin-right: 0.3rem;
}
.basalt-breadcrumb-collapse .breadcrumb-item.is-folded {
	display: none;
}

.basalt-breadcrumb-more {
	display: inline-grid;
	place-items: center;
	min-width: 1.75rem;
	height: 1.35rem;
	padding: 0 0.3rem;
	border: 1px solid var(--basalt-edge-strong);
	border-radius: 6px;
	font-size: 0.8rem;
	line-height: 1;
	vertical-align: middle;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
}
.basalt-breadcrumb-more:hover {
	color: var(--basalt-copy);
	background: var(--basalt-wash);
}
.basalt-breadcrumb-more:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	box-shadow: none;
}

/* Each specimen row puts the style's name and measured size on the left and
   a sample on the right. The script fills the numbers in from what the
   browser actually renders, so they cannot drift from the truth. On a phone
   the two halves stack. */
.basalt-type-scale {
	display: grid;
}
.basalt-type-scale-row {
	display: grid;
	gap: 1.5rem;
	grid-template-columns: minmax(9rem, 12rem) minmax(0, 1fr);
	align-items: center;
	padding: 1rem 0;
	border-bottom: 1px solid var(--basalt-edge);
}
.basalt-type-scale-row:first-child {
	padding-top: 0;
}
.basalt-type-scale-row:last-child {
	padding-bottom: 0;
	border-bottom: 0;
}
@media (max-width: 767.98px) {
	.basalt-type-scale-row {
		gap: 0.3rem;
		grid-template-columns: minmax(0, 1fr);
	}
}
.basalt-type-scale-name {
	display: block;
	font-family: "Chivo Mono", monospace;
	font-size: 0.77rem;
	font-weight: 500;
	color: var(--basalt-copy);
}
.basalt-type-scale-spec {
	display: block;
	margin-top: 0.2rem;
	font-family: "Chivo Mono", monospace;
	font-size: 0.7rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-type-scale-sample {
	min-width: 0;
	margin: 0;
	overflow-wrap: anywhere;
	color: var(--basalt-copy);
}

/* An eyebrow is the short mono label that sits over a heading. */
.basalt-eyebrow {
	display: block;
	margin-bottom: 0.3rem;
	font-family: "Chivo Mono", monospace;
	font-size: 0.71rem;
	font-weight: 500;
	letter-spacing: 0.055em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
}

/* Figures that update in place keep fixed-width digits so nothing shifts;
   a delta adds a direction arrow and colors itself by which way it went. */
.basalt-num {
	font-feature-settings: "tnum";
	font-variant-numeric: tabular-nums;
}

.basalt-delta {
	display: inline-flex;
	gap: 0.1rem;
	align-items: center;
	font-size: 0.77rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-delta-up {
	color: color-mix(in srgb, var(--basalt-success) 45%, var(--basalt-copy));
}
.basalt-delta-down {
	color: color-mix(in srgb, var(--basalt-danger) 55%, var(--basalt-copy));
}

/* A clamped block shows --basalt-clamp-lines lines (three unless told
   otherwise) and opens in full once toggled; print always gets every line.
   The toggle under it, [data-basalt-clamp-toggle], appears only when some
   text is actually hidden. */
.basalt-clamp {
	display: -webkit-box;
	overflow: hidden;
	-webkit-line-clamp: var(--basalt-clamp-lines, 3);
	line-clamp: var(--basalt-clamp-lines, 3);
	-webkit-box-orient: vertical;
}
.basalt-clamp.is-open {
	display: block;
	overflow: visible;
	-webkit-line-clamp: unset;
	line-clamp: none;
}
@media print {
	.basalt-clamp {
		display: block;
		overflow: visible;
		-webkit-line-clamp: unset;
	}
}

.basalt-clamp-toggle {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	margin-top: 0.4rem;
	padding: 0.1rem 0.1rem;
	border: 0;
	border-radius: 4px;
	font-size: 0.8rem;
	font-weight: 600;
	text-decoration: underline;
	text-decoration-color: color-mix(in srgb, var(--basalt-hue) 55%, transparent);
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
	color: var(--basalt-copy);
	background: transparent;
}
.basalt-clamp-toggle[hidden] {
	display: none;
}
.basalt-clamp-toggle:hover {
	text-decoration-color: var(--basalt-hue);
}
.basalt-clamp-toggle:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
	box-shadow: none;
}
.basalt-clamp-toggle .bi {
	font-size: 0.7rem;
	transition: transform 170ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.basalt-clamp-toggle .bi {
		transition: none;
	}
}
.basalt-clamp-toggle[aria-expanded="true"] .bi {
	transform: rotate(180deg);
}

/* Steps are numbered discs strung on a vertical line. A finished step trades
   its number for a check and tints the line below it; the step in progress
   is a filled disc with a soft halo. */
.basalt-list-steps {
	counter-reset: basalt-step;
	margin: 0;
	padding: 0;
	list-style: none;
}
.basalt-list-steps > li {
	counter-increment: basalt-step;
	position: relative;
	padding: 0 0 1.35rem 2.75rem;
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--basalt-copy-body);
}
.basalt-list-steps > li:last-child {
	padding-bottom: 0;
}
.basalt-list-steps > li::before {
	content: counter(basalt-step);
	position: absolute;
	top: -0.1rem;
	left: 0;
	display: grid;
	place-items: center;
	width: 1.9rem;
	height: 1.9rem;
	border-radius: 50%;
	border: 1.5px solid var(--basalt-edge-strong);
	font-size: 0.8rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane);
}
.basalt-list-steps > li:not(:last-child)::after {
	content: "";
	position: absolute;
	top: 1.95rem;
	bottom: 0.1rem;
	left: calc(0.95rem - 1px);
	width: 2px;
	border-radius: 1px;
	background: var(--basalt-edge-strong);
}
.basalt-list-steps > li.is-done::before {
	content: "\f272";
	border-color: var(--basalt-hue-border);
	font-family: "bootstrap-icons";
	font-weight: 400;
	color: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-copy));
	background: var(--basalt-hue-soft);
}
.basalt-list-steps > li.is-done::after {
	background: color-mix(in srgb, var(--basalt-hue) 55%, var(--basalt-edge-strong));
}
.basalt-list-steps > li.is-current::before {
	border-color: transparent;
	color: var(--basalt-on-hue);
	background: color-mix(in srgb, var(--basalt-hue) 86%, var(--basalt-copy));
	box-shadow: 0 0 0 4px var(--basalt-hue-soft);
}
.basalt-list-steps-title {
	display: block;
	margin-bottom: 0.1rem;
	font-weight: 650;
	color: var(--basalt-copy);
}

/* Icon lists hang a round marker beside each line: a check on .is-yes, and on
   .is-no a smaller cross with the line itself gone quiet. */
.basalt-list-icon {
	display: grid;
	gap: 0.6rem;
	margin: 0;
	padding: 0;
	font-size: 0.875rem;
	list-style: none;
}
.basalt-list-icon > li {
	position: relative;
	padding-left: 1.85rem;
	line-height: 1.5;
	color: var(--basalt-copy-body);
}
.basalt-list-icon > li::before {
	content: "\f309";
	position: absolute;
	top: 0.05rem;
	left: 0;
	display: grid;
	place-items: center;
	width: 1.3rem;
	height: 1.3rem;
	border-radius: 50%;
	font-family: "bootstrap-icons";
	font-size: 0.75rem;
	color: var(--basalt-copy-body);
	background: var(--basalt-plane-alt);
}
.basalt-list-icon > li.is-yes::before {
	content: "\f633";
	color: color-mix(in srgb, var(--basalt-success) 45%, var(--basalt-copy));
	background: color-mix(in srgb, var(--basalt-success) 16%, var(--basalt-plane));
}
.basalt-list-icon > li.is-no {
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
}
.basalt-list-icon > li.is-no::before {
	content: "\f659";
	font-size: 0.6rem;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: var(--basalt-plane-alt);
}

/* A strip that scrolls sideways dims whichever edge still hides content.
   basalt.js measures each strip and toggles has-fade-start and has-fade-end;
   each class widens its side of the mask from nothing to --basalt-fade.
   Print drops the mask, since paper cannot scroll. */
.basalt-scroll-fade {
	--basalt-fade: 2.75rem;
	--basalt-fade-start: 0px;
	--basalt-fade-end: 0px;
	-webkit-mask-image: linear-gradient(
		to right,
		transparent,
		#000 var(--basalt-fade-start),
		#000 calc(100% - var(--basalt-fade-end)),
		transparent
	);
	mask-image: linear-gradient(
		to right,
		transparent,
		#000 var(--basalt-fade-start),
		#000 calc(100% - var(--basalt-fade-end)),
		transparent
	);
}
.basalt-scroll-fade.has-fade-start {
	--basalt-fade-start: var(--basalt-fade);
}
.basalt-scroll-fade.has-fade-end {
	--basalt-fade-end: var(--basalt-fade);
}
@media print {
	.basalt-scroll-fade {
		-webkit-mask-image: none;
		mask-image: none;
	}
}

/* Search fields keep the browser's own clear control, redrawn as a thin
   cross that takes the muted text color and darkens under the pointer. */
input[type="search"]::-webkit-search-cancel-button {
	flex-shrink: 0;
	width: 0.9rem;
	height: 0.9rem;
	margin: 0 0 0 0.5rem;
	background-color: var(--basalt-copy-muted);
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.5 4.5l7 7M11.5 4.5l-7 7' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E")
		center/contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.5 4.5l7 7M11.5 4.5l-7 7' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E")
		center/contain no-repeat;
	cursor: pointer;
	transition: background-color 110ms ease;
	-webkit-appearance: none;
	appearance: none;
}
input[type="search"]::-webkit-search-cancel-button:hover {
	background-color: var(--basalt-copy);
}

/* Wrappers that let a wide table slide sideways stay put vertically: row
   borders and focus rings poke out by a pixel and would otherwise summon a
   second, useless scrollbar. */
.table-responsive {
	overflow-y: hidden;
}

/* Only the overview pages ask for movement, which keeps the rest of the app
   calm to move around in. basalt.js reads three hooks: a container with
   [data-basalt-motion] has its cards staggered in through .basalt-enter, a
   [data-basalt-countup] figure runs up to its value once, and a
   [data-basalt-lift] card rises a touch on hover. Reduced motion stops all three. */
@keyframes basalt-rise {
	from {
		transform: translateY(8px);
		opacity: 0;
	}
}
.basalt-enter {
	animation: basalt-rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Until the page has settled every animation holds its first frame (the
   cards stay unseen) and an on-screen chart stays hidden; basalt.js lets
   them all go together, so nothing moves while the page is still busy. */
.basalt-motion-held *,
.basalt-motion-held *::before,
.basalt-motion-held *::after {
	animation-play-state: paused;
}

.basalt-chart-held {
	visibility: hidden;
}

/* The stage stays out of sight until the page's own scripts have built its
   lists and charts, so nothing below them jumps as they fill in; basalt.js
   marks the page built. A page that runs no scripts shows after 2s anyway. */
:root:not(.basalt-built) .basalt-stage {
	visibility: hidden;
	animation: basalt-stage-show 0s 2s forwards;
}

@keyframes basalt-stage-show {
	to {
		visibility: visible;
	}
}
/* The lift only answers a real pointer, so touch screens never stick raised. */
[data-basalt-lift] {
	transition:
		transform 0.2s ease,
		box-shadow 0.2s ease;
}
@media (hover: hover) {
	[data-basalt-lift]:hover {
		transform: translateY(-2px);
		box-shadow: 0 14px 30px -22px color-mix(in srgb, var(--basalt-copy) 45%, transparent);
	}
}

/* Bar fills grow out of their track the first time they come into view;
   basalt.js adds the classes. A bar waiting below the fold sits at zero. */
@keyframes basalt-grow-x {
	from {
		transform: scaleX(0);
	}
}
@keyframes basalt-grow-y {
	from {
		transform: scaleY(0);
	}
}
.basalt-grow-wait-x {
	transform: scaleX(0);
}

.basalt-grow-wait-y {
	transform: scaleY(0);
}

.basalt-grow-wait-x,
.basalt-grow-x {
	transform-origin: left center;
}

.basalt-grow-wait-y,
.basalt-grow-y {
	transform-box: fill-box;
	transform-origin: center bottom;
}

/* A ring's arc runs round from nothing; a sparkline draws in from the left. */
@keyframes basalt-grow-arc {
	from {
		stroke-dasharray: 0 var(--basalt-arc-total, 100);
	}
}
@keyframes basalt-grow-line {
	from {
		clip-path: inset(0 100% 0 0);
	}
}
.basalt-grow-wait-arc {
	stroke-dasharray: 0 var(--basalt-arc-total, 100);
}

.basalt-grow-wait-line {
	clip-path: inset(0 100% 0 0);
}

.basalt-grow-arc {
	animation: basalt-grow-arc 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
	animation-delay: calc(var(--basalt-grow-i, 0) * 60ms);
}

.basalt-grow-line {
	animation: basalt-grow-line 0.9s cubic-bezier(0.33, 1, 0.68, 1) both;
	animation-delay: calc(var(--basalt-grow-i, 0) * 80ms);
}

/* A block in a wave pops in place, a little after the one before it. */
@keyframes basalt-grow-pop {
	from {
		opacity: 0;
		transform: scale(0.4);
	}
}
.basalt-grow-wait-pop {
	opacity: 0;
	transform: scale(0.4);
}

.basalt-grow-pop {
	animation: basalt-grow-pop 0.45s cubic-bezier(0.34, 1.4, 0.64, 1) both;
	animation-delay: calc(var(--basalt-grow-i, 0) * var(--basalt-grow-step, 45ms));
}

.basalt-grow-x {
	animation: basalt-grow-x 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
	animation-delay: calc(var(--basalt-grow-i, 0) * 40ms);
}

.basalt-grow-y {
	animation: basalt-grow-y 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
	animation-delay: calc(var(--basalt-grow-i, 0) * var(--basalt-grow-step, 30ms));
}

/* A piece with transitions of its own (a hover fade, a value that eases)
   would also ease out to its waiting state and back while it grows: a
   second animation per piece, hundreds at once on a long strip of days,
   started in the same frame as everything else. Growing stands in for them. */
.basalt-stage .basalt-grow-wait-x,
.basalt-stage .basalt-grow-wait-y,
.basalt-stage .basalt-grow-wait-arc,
.basalt-stage .basalt-grow-wait-line,
.basalt-stage .basalt-grow-wait-pop,
.basalt-stage .basalt-grow-x,
.basalt-stage .basalt-grow-y,
.basalt-stage .basalt-grow-arc,
.basalt-stage .basalt-grow-line,
.basalt-stage .basalt-grow-pop {
	transition: none;
}

@media (prefers-reduced-motion: reduce) {
	.basalt-enter {
		animation: none;
	}
	[data-basalt-lift],
	[data-basalt-lift]:hover {
		transform: none;
		transition: none;
	}
}
/* A row whose record also has a page of its own ends in two small icon
   buttons: bi-layout-sidebar-inset-reverse peeks at it in the drawer, and
   bi-arrows-angle-expand opens the page. Their tooltips use
   data-bs-trigger="hover" so a click never leaves one hanging. A click
   anywhere else on the row opens the drawer, while the record's name links
   to the page. Inside the drawer, .basalt-drawer-full is the solid
   "Open full page" button under the title. */
.basalt-row-actions {
	display: inline-flex;
	gap: 0.25rem;
	align-items: center;
	white-space: nowrap;
}
.basalt-row-actions .btn-icon {
	width: 34px;
	height: 34px;
	padding: 0;
}

/* On a phone the row keeps one way to each place: the record's name opens
   its page, so the expand button steps aside and the row gets the room. */
@media (max-width: 575.98px) {
	.basalt-row-actions > a.btn-icon[aria-label^="Open full page"] {
		display: none;
	}
}
.basalt-drawer-full {
	align-self: flex-start;
	margin-top: 0.9rem;
	white-space: nowrap;
}

/* With the button under it, the head lines up from the top: the avatar
   sits level with the title and the line under it, and the close button
   level with the title. */
.offcanvas-header:has(.basalt-drawer-full) {
	align-items: flex-start;
}

/* Breadcrumb extras, all shown on breadcrumbs.html: divider choices, a
   compact trail for narrow boxes and a menu for skipped levels. */
/* The quiet text tone the menu shares with the viewer. */
/* A visible keyboard ring in the palette color. */
/* Divider choices for a breadcrumb trail, set on the nav or the list. */
.breadcrumb-chevron {
	--bs-breadcrumb-divider: "›";
}

.breadcrumb-arrow {
	--bs-breadcrumb-divider: "→";
}

.breadcrumb-dot {
	--bs-breadcrumb-divider: "·";
}

/* Two breadcrumb additions, both shown on breadcrumbs.html. A compact
   trail in a narrow container keeps only the step back up ("‹ Knitwear"). */
.basalt-breadcrumb-compact {
	container-type: inline-size;
}

@container (max-width: 25rem) {
	.basalt-breadcrumb-compact .breadcrumb-item {
		display: none;
	}
	.basalt-breadcrumb-compact .breadcrumb-item:nth-last-child(2) {
		display: block;
		padding-left: 0;
	}
	.basalt-breadcrumb-compact .breadcrumb-item:nth-last-child(2)::before {
		content: "\f284";
		float: none;
		padding-right: 0.3rem;
		font-family: "bootstrap-icons";
		font-size: 0.75em;
		vertical-align: -0.05em;
	}
	.basalt-breadcrumb-compact .breadcrumb-item:nth-last-child(2) .bi {
		display: none;
	}
}
/* A menu crumb opens a dropdown listing the pages beside that level. */
.breadcrumb-item .dropdown {
	display: inline-block;
}

.basalt-breadcrumb-menu {
	display: inline-flex;
	gap: 0.3rem;
	align-items: center;
	padding: 0 0.1rem;
	border-radius: 4px;
	border: 0;
	font: inherit;
	color: color-mix(in srgb, var(--basalt-copy-muted) 72%, var(--basalt-copy));
	background: none;
}
.basalt-breadcrumb-menu[aria-expanded="true"],
.basalt-breadcrumb-menu:hover {
	color: var(--basalt-copy);
}
.basalt-breadcrumb-menu:focus-visible {
	outline: 2px solid var(--basalt-hue);
	outline-offset: 2px;
}

.breadcrumb-item .basalt-breadcrumb-menu .bi {
	margin-right: 0;
	font-size: 0.7em;
}

/* The keyboard shortcuts sheet: keys on the left, what they do beside
   them, in two columns from tablet width. */
.basalt-keys {
	display: grid;
	gap: 1.5rem;
}
@media (min-width: 768px) {
	.basalt-keys {
		grid-template-columns: 1fr 1fr;
	}
}

.basalt-keys-title {
	margin: 0 0 0.75rem;
	font-size: 0.875rem;
	font-weight: 700;
	color: var(--basalt-copy);
}

.basalt-keys-list {
	display: grid;
	gap: 0.6rem;
	margin: 0;
}
.basalt-keys-list > div {
	display: flex;
	gap: 1rem;
	align-items: baseline;
}
.basalt-keys-list dt {
	flex: 0 0 6.5rem;
	font-weight: 400;
}
.basalt-keys-list dd {
	margin: 0;
	font-size: 0.875rem;
	color: var(--basalt-copy-body);
}

.basalt-keys-none {
	margin: 0;
	font-size: 0.875rem;
	color: var(--basalt-copy-muted);
}

/*
 * Classes that hand one number or one color to a component, so markup
 * never needs a style attribute. A ring or gauge reads --value, a bar reads
 * --share, a goal marker reads --target, staggered items read --i, and
 * toned parts read --tone:
 *
 *   <div class="basalt-ring value-72">…</div>
 *   <span class="hc-legend-key tone-series-2"></span>
 *
 * Scripts that draw from live data set the same custom properties directly.
 */
.value-0 {
	--value: 0;
}

.share-0 {
	--share: 0%;
}

.target-0 {
	--target: 0;
}

.value-1 {
	--value: 1;
}

.share-1 {
	--share: 1%;
}

.target-1 {
	--target: 1;
}

.value-2 {
	--value: 2;
}

.share-2 {
	--share: 2%;
}

.target-2 {
	--target: 2;
}

.value-3 {
	--value: 3;
}

.share-3 {
	--share: 3%;
}

.target-3 {
	--target: 3;
}

.value-4 {
	--value: 4;
}

.share-4 {
	--share: 4%;
}

.target-4 {
	--target: 4;
}

.value-5 {
	--value: 5;
}

.share-5 {
	--share: 5%;
}

.target-5 {
	--target: 5;
}

.value-6 {
	--value: 6;
}

.share-6 {
	--share: 6%;
}

.target-6 {
	--target: 6;
}

.value-7 {
	--value: 7;
}

.share-7 {
	--share: 7%;
}

.target-7 {
	--target: 7;
}

.value-8 {
	--value: 8;
}

.share-8 {
	--share: 8%;
}

.target-8 {
	--target: 8;
}

.value-9 {
	--value: 9;
}

.share-9 {
	--share: 9%;
}

.target-9 {
	--target: 9;
}

.value-10 {
	--value: 10;
}

.share-10 {
	--share: 10%;
}

.target-10 {
	--target: 10;
}

.value-11 {
	--value: 11;
}

.share-11 {
	--share: 11%;
}

.target-11 {
	--target: 11;
}

.value-12 {
	--value: 12;
}

.share-12 {
	--share: 12%;
}

.target-12 {
	--target: 12;
}

.value-13 {
	--value: 13;
}

.share-13 {
	--share: 13%;
}

.target-13 {
	--target: 13;
}

.value-14 {
	--value: 14;
}

.share-14 {
	--share: 14%;
}

.target-14 {
	--target: 14;
}

.value-15 {
	--value: 15;
}

.share-15 {
	--share: 15%;
}

.target-15 {
	--target: 15;
}

.value-16 {
	--value: 16;
}

.share-16 {
	--share: 16%;
}

.target-16 {
	--target: 16;
}

.value-17 {
	--value: 17;
}

.share-17 {
	--share: 17%;
}

.target-17 {
	--target: 17;
}

.value-18 {
	--value: 18;
}

.share-18 {
	--share: 18%;
}

.target-18 {
	--target: 18;
}

.value-19 {
	--value: 19;
}

.share-19 {
	--share: 19%;
}

.target-19 {
	--target: 19;
}

.value-20 {
	--value: 20;
}

.share-20 {
	--share: 20%;
}

.target-20 {
	--target: 20;
}

.value-21 {
	--value: 21;
}

.share-21 {
	--share: 21%;
}

.target-21 {
	--target: 21;
}

.value-22 {
	--value: 22;
}

.share-22 {
	--share: 22%;
}

.target-22 {
	--target: 22;
}

.value-23 {
	--value: 23;
}

.share-23 {
	--share: 23%;
}

.target-23 {
	--target: 23;
}

.value-24 {
	--value: 24;
}

.share-24 {
	--share: 24%;
}

.target-24 {
	--target: 24;
}

.value-25 {
	--value: 25;
}

.share-25 {
	--share: 25%;
}

.target-25 {
	--target: 25;
}

.value-26 {
	--value: 26;
}

.share-26 {
	--share: 26%;
}

.target-26 {
	--target: 26;
}

.value-27 {
	--value: 27;
}

.share-27 {
	--share: 27%;
}

.target-27 {
	--target: 27;
}

.value-28 {
	--value: 28;
}

.share-28 {
	--share: 28%;
}

.target-28 {
	--target: 28;
}

.value-29 {
	--value: 29;
}

.share-29 {
	--share: 29%;
}

.target-29 {
	--target: 29;
}

.value-30 {
	--value: 30;
}

.share-30 {
	--share: 30%;
}

.target-30 {
	--target: 30;
}

.value-31 {
	--value: 31;
}

.share-31 {
	--share: 31%;
}

.target-31 {
	--target: 31;
}

.value-32 {
	--value: 32;
}

.share-32 {
	--share: 32%;
}

.target-32 {
	--target: 32;
}

.value-33 {
	--value: 33;
}

.share-33 {
	--share: 33%;
}

.target-33 {
	--target: 33;
}

.value-34 {
	--value: 34;
}

.share-34 {
	--share: 34%;
}

.target-34 {
	--target: 34;
}

.value-35 {
	--value: 35;
}

.share-35 {
	--share: 35%;
}

.target-35 {
	--target: 35;
}

.value-36 {
	--value: 36;
}

.share-36 {
	--share: 36%;
}

.target-36 {
	--target: 36;
}

.value-37 {
	--value: 37;
}

.share-37 {
	--share: 37%;
}

.target-37 {
	--target: 37;
}

.value-38 {
	--value: 38;
}

.share-38 {
	--share: 38%;
}

.target-38 {
	--target: 38;
}

.value-39 {
	--value: 39;
}

.share-39 {
	--share: 39%;
}

.target-39 {
	--target: 39;
}

.value-40 {
	--value: 40;
}

.share-40 {
	--share: 40%;
}

.target-40 {
	--target: 40;
}

.value-41 {
	--value: 41;
}

.share-41 {
	--share: 41%;
}

.target-41 {
	--target: 41;
}

.value-42 {
	--value: 42;
}

.share-42 {
	--share: 42%;
}

.target-42 {
	--target: 42;
}

.value-43 {
	--value: 43;
}

.share-43 {
	--share: 43%;
}

.target-43 {
	--target: 43;
}

.value-44 {
	--value: 44;
}

.share-44 {
	--share: 44%;
}

.target-44 {
	--target: 44;
}

.value-45 {
	--value: 45;
}

.share-45 {
	--share: 45%;
}

.target-45 {
	--target: 45;
}

.value-46 {
	--value: 46;
}

.share-46 {
	--share: 46%;
}

.target-46 {
	--target: 46;
}

.value-47 {
	--value: 47;
}

.share-47 {
	--share: 47%;
}

.target-47 {
	--target: 47;
}

.value-48 {
	--value: 48;
}

.share-48 {
	--share: 48%;
}

.target-48 {
	--target: 48;
}

.value-49 {
	--value: 49;
}

.share-49 {
	--share: 49%;
}

.target-49 {
	--target: 49;
}

.value-50 {
	--value: 50;
}

.share-50 {
	--share: 50%;
}

.target-50 {
	--target: 50;
}

.value-51 {
	--value: 51;
}

.share-51 {
	--share: 51%;
}

.target-51 {
	--target: 51;
}

.value-52 {
	--value: 52;
}

.share-52 {
	--share: 52%;
}

.target-52 {
	--target: 52;
}

.value-53 {
	--value: 53;
}

.share-53 {
	--share: 53%;
}

.target-53 {
	--target: 53;
}

.value-54 {
	--value: 54;
}

.share-54 {
	--share: 54%;
}

.target-54 {
	--target: 54;
}

.value-55 {
	--value: 55;
}

.share-55 {
	--share: 55%;
}

.target-55 {
	--target: 55;
}

.value-56 {
	--value: 56;
}

.share-56 {
	--share: 56%;
}

.target-56 {
	--target: 56;
}

.value-57 {
	--value: 57;
}

.share-57 {
	--share: 57%;
}

.target-57 {
	--target: 57;
}

.value-58 {
	--value: 58;
}

.share-58 {
	--share: 58%;
}

.target-58 {
	--target: 58;
}

.value-59 {
	--value: 59;
}

.share-59 {
	--share: 59%;
}

.target-59 {
	--target: 59;
}

.value-60 {
	--value: 60;
}

.share-60 {
	--share: 60%;
}

.target-60 {
	--target: 60;
}

.value-61 {
	--value: 61;
}

.share-61 {
	--share: 61%;
}

.target-61 {
	--target: 61;
}

.value-62 {
	--value: 62;
}

.share-62 {
	--share: 62%;
}

.target-62 {
	--target: 62;
}

.value-63 {
	--value: 63;
}

.share-63 {
	--share: 63%;
}

.target-63 {
	--target: 63;
}

.value-64 {
	--value: 64;
}

.share-64 {
	--share: 64%;
}

.target-64 {
	--target: 64;
}

.value-65 {
	--value: 65;
}

.share-65 {
	--share: 65%;
}

.target-65 {
	--target: 65;
}

.value-66 {
	--value: 66;
}

.share-66 {
	--share: 66%;
}

.target-66 {
	--target: 66;
}

.value-67 {
	--value: 67;
}

.share-67 {
	--share: 67%;
}

.target-67 {
	--target: 67;
}

.value-68 {
	--value: 68;
}

.share-68 {
	--share: 68%;
}

.target-68 {
	--target: 68;
}

.value-69 {
	--value: 69;
}

.share-69 {
	--share: 69%;
}

.target-69 {
	--target: 69;
}

.value-70 {
	--value: 70;
}

.share-70 {
	--share: 70%;
}

.target-70 {
	--target: 70;
}

.value-71 {
	--value: 71;
}

.share-71 {
	--share: 71%;
}

.target-71 {
	--target: 71;
}

.value-72 {
	--value: 72;
}

.share-72 {
	--share: 72%;
}

.target-72 {
	--target: 72;
}

.value-73 {
	--value: 73;
}

.share-73 {
	--share: 73%;
}

.target-73 {
	--target: 73;
}

.value-74 {
	--value: 74;
}

.share-74 {
	--share: 74%;
}

.target-74 {
	--target: 74;
}

.value-75 {
	--value: 75;
}

.share-75 {
	--share: 75%;
}

.target-75 {
	--target: 75;
}

.value-76 {
	--value: 76;
}

.share-76 {
	--share: 76%;
}

.target-76 {
	--target: 76;
}

.value-77 {
	--value: 77;
}

.share-77 {
	--share: 77%;
}

.target-77 {
	--target: 77;
}

.value-78 {
	--value: 78;
}

.share-78 {
	--share: 78%;
}

.target-78 {
	--target: 78;
}

.value-79 {
	--value: 79;
}

.share-79 {
	--share: 79%;
}

.target-79 {
	--target: 79;
}

.value-80 {
	--value: 80;
}

.share-80 {
	--share: 80%;
}

.target-80 {
	--target: 80;
}

.value-81 {
	--value: 81;
}

.share-81 {
	--share: 81%;
}

.target-81 {
	--target: 81;
}

.value-82 {
	--value: 82;
}

.share-82 {
	--share: 82%;
}

.target-82 {
	--target: 82;
}

.value-83 {
	--value: 83;
}

.share-83 {
	--share: 83%;
}

.target-83 {
	--target: 83;
}

.value-84 {
	--value: 84;
}

.share-84 {
	--share: 84%;
}

.target-84 {
	--target: 84;
}

.value-85 {
	--value: 85;
}

.share-85 {
	--share: 85%;
}

.target-85 {
	--target: 85;
}

.value-86 {
	--value: 86;
}

.share-86 {
	--share: 86%;
}

.target-86 {
	--target: 86;
}

.value-87 {
	--value: 87;
}

.share-87 {
	--share: 87%;
}

.target-87 {
	--target: 87;
}

.value-88 {
	--value: 88;
}

.share-88 {
	--share: 88%;
}

.target-88 {
	--target: 88;
}

.value-89 {
	--value: 89;
}

.share-89 {
	--share: 89%;
}

.target-89 {
	--target: 89;
}

.value-90 {
	--value: 90;
}

.share-90 {
	--share: 90%;
}

.target-90 {
	--target: 90;
}

.value-91 {
	--value: 91;
}

.share-91 {
	--share: 91%;
}

.target-91 {
	--target: 91;
}

.value-92 {
	--value: 92;
}

.share-92 {
	--share: 92%;
}

.target-92 {
	--target: 92;
}

.value-93 {
	--value: 93;
}

.share-93 {
	--share: 93%;
}

.target-93 {
	--target: 93;
}

.value-94 {
	--value: 94;
}

.share-94 {
	--share: 94%;
}

.target-94 {
	--target: 94;
}

.value-95 {
	--value: 95;
}

.share-95 {
	--share: 95%;
}

.target-95 {
	--target: 95;
}

.value-96 {
	--value: 96;
}

.share-96 {
	--share: 96%;
}

.target-96 {
	--target: 96;
}

.value-97 {
	--value: 97;
}

.share-97 {
	--share: 97%;
}

.target-97 {
	--target: 97;
}

.value-98 {
	--value: 98;
}

.share-98 {
	--share: 98%;
}

.target-98 {
	--target: 98;
}

.value-99 {
	--value: 99;
}

.share-99 {
	--share: 99%;
}

.target-99 {
	--target: 99;
}

.value-100 {
	--value: 100;
}

.share-100 {
	--share: 100%;
}

.target-100 {
	--target: 100;
}

.stagger-0 {
	--i: 0;
}

.stagger-1 {
	--i: 1;
}

.stagger-2 {
	--i: 2;
}

.stagger-3 {
	--i: 3;
}

.stagger-4 {
	--i: 4;
}

.stagger-5 {
	--i: 5;
}

.stagger-6 {
	--i: 6;
}

.stagger-7 {
	--i: 7;
}

.stagger-8 {
	--i: 8;
}

.stagger-9 {
	--i: 9;
}

.stagger-10 {
	--i: 10;
}

.stagger-11 {
	--i: 11;
}

.stagger-12 {
	--i: 12;
}

.stagger-13 {
	--i: 13;
}

.stagger-14 {
	--i: 14;
}

.stagger-15 {
	--i: 15;
}

.tone-series-1 {
	--tone: var(--basalt-series-1);
}

.tone-series-2 {
	--tone: var(--basalt-series-2);
}

.tone-series-3 {
	--tone: var(--basalt-series-3);
}

.tone-series-4 {
	--tone: var(--basalt-series-4);
}

.tone-series-5 {
	--tone: var(--basalt-series-5);
}

.tone-series-6 {
	--tone: var(--basalt-series-6);
}

.tone-series-7 {
	--tone: var(--basalt-series-7);
}

.tone-series-8 {
	--tone: var(--basalt-series-8);
}

.tone-hue {
	--tone: var(--basalt-hue);
}

.tone-success {
	--tone: var(--basalt-success);
}

.tone-warning {
	--tone: var(--basalt-warning);
}

.tone-danger {
	--tone: var(--basalt-danger);
}

.tone-flare {
	--tone: var(--basalt-flare);
}

.tone-plane {
	--tone: var(--basalt-plane);
}

/**
 * Photo placeholders.
 *
 * The download carries no photos: each demo photo becomes an SVG of the same
 * name and size under assets/basalt/images/multipurpose/, saying what goes
 * there. The SVG is see-through, so the wash behind it comes from here and
 * follows the palette and dark mode. Your own photos are opaque and cover it.
 */
img[src*="/images/"][src$=".svg"] {
	background-color: var(--basalt-plane-alt);
}
