/* ==========================================================================
   DigiSoft brand: colours and buttons, ONE file for the whole system.

   Loaded by every surface, so a colour or button change is made here only:
   - classic FA screens   includes/main.inc (before default.css)
   - Vue / Nocturne pages resources/css/nocturne.css @imports it (Vite bundles it)
   - sign-in pages        access/auth_layout.inc (before auth.css)

   Colours: green #1A7F45 = the "good" action buttons (Add, Save, Update,
   Process, Sign in); red #D7262E (logo) = destructive buttons (Delete,
   Deactivate, Void) and the accent (links, active tab, focus ring);
   charcoal #2B2D33 / logo grey #8C8E92 = secondary.

   Button roles (use the classes, never hand-pick colours on a screen):
     .btn .btn-primary    filled green - the one main action (Add, Save, Process)
     .btn .btn-secondary  charcoal outline - Cancel, Back, Search, Export
     .btn .btn-ghost      red text - row actions (Edit), Clear filters
     .btn .btn-danger     filled red - Delete / Deactivate / Void (with jdConfirm)
     disabled             a light tint of the button's own colour
   Vue: components/ui/AppButton.vue renders these. Classic FA submit buttons
   (submit(), submit_add_or_update(), ...) get the same roles in default.css
   from their aspect / name, so PHP screens need no change.
   Selectors are doubled (.btn.btn-primary) so they beat ".nx a" / "a:link".
   Documentation: docs/ww/common/buttons.md

   Tables: the --table-* tokens and .jd-table below are THE table look for the
   whole system - Vue DataTable (components/ui/DataTable.vue), classic FA lists
   (table.tablestyle in default.css) and any hand-written grid that can't be a
   DataTable (class="jd-table"). Documentation: docs/ww/common/tables.md
   ========================================================================== */

:root {
	/* fixed palette (same in both themes) */
	--brand-red-50: #fef2f2;
	--brand-red-100: #fdecec;
	--brand-red-200: #fad4d5;
	--brand-red-300: #f5a9ac;
	--brand-red-400: #ec7176;
	--brand-red-500: #e0383f;
	--brand-red: #d7262e;
	--brand-red-700: #b81e26;
	--brand-red-800: #9c1920;
	--brand-red-900: #6e171b;
	--brand-green-200: #cdebd8;
	--brand-green: #1a7f45;
	--brand-green-700: #166b3a;
	--brand-green-800: #125830;
	--brand-charcoal: #2b2d33;
	--brand-grey: #8c8e92;
	--brand-gradient: linear-gradient(100deg, #e52329 0%, #c8174a 100%);
	--brand-gradient-hover: linear-gradient(100deg, #cc1d23 0%, #ad1340 100%);

	/* accent ramp, dark theme (100 = lightest: text on dark, 900 = darkest: tints) */
	--color-accent: #e5484d;
	--color-accent-2: #ec7176;
	--color-accent-100: #fdecec;
	--color-accent-200: #fad4d5;
	--color-accent-300: #f5a9ac;
	--color-accent-400: #ec7176;
	--color-accent-500: #e0383f;
	--color-accent-600: #b81e26;
	--color-accent-700: #8a1a20;
	--color-accent-800: #561619;
	--color-accent-900: #33141a;
	--color-charcoal: #d4d6dc;

	/* drill-down links in data tables (blue: stands apart from the red brand, which means "action") */
	--color-link: #7cb4ff;
	--color-link-hover: #b3d3ff;

	/* button roles */
	--btn-primary-bg: var(--brand-green);
	--btn-primary-hover: var(--brand-green-700);
	--btn-primary-active: var(--brand-green-800);
	--btn-primary-fg: #ffffff;
	--btn-primary-disabled-bg: #1b3a28;
	--btn-primary-disabled-fg: #6f9c80;
	--btn-secondary-fg: var(--color-text, #e9e9ed);
	--btn-secondary-border: var(--color-charcoal);
	--btn-ghost-fg: var(--color-accent);
	--btn-danger-fg: var(--color-danger, #e5848a); /* icon-only deletes (red icon, no box) */
	--btn-danger-bg: var(--brand-red);
	--btn-danger-hover: var(--brand-red-700);
	--btn-danger-active: var(--brand-red-800);
	--btn-danger-text: #ffffff;
	--btn-danger-disabled-bg: #4a1d21;
	--btn-danger-disabled-fg: #b0686c;
	--btn-disabled-fg: color-mix(in srgb, var(--color-text, #e9e9ed) 38%, transparent);
	--btn-disabled-border: color-mix(in srgb, var(--color-text, #e9e9ed) 18%, transparent);

	/* tables (same in both themes: built on the theme's neutral tokens) */
	--table-head-h: 30px;
	--table-row-h: 42px;
	--table-head-size: 11px;
	--table-head-tracking: 0.08em;
	--table-head-fg: var(--color-neutral-500);
	--table-head-bg: color-mix(in srgb, var(--color-text) 5%, transparent);
	--table-line: var(--color-neutral-800);
	--table-row-hover: var(--color-neutral-900);
	--table-row-selected: var(--color-neutral-900);
	--table-foot-bg: color-mix(in srgb, var(--color-text) 5%, transparent);
	--table-foot-fg: var(--color-text);
	--table-foot-line: var(--color-neutral-700);
	--table-foot-muted: var(--color-neutral-400);
}

/* light theme: ramp mirrored so "dark step for tints, light step for text" holds */
:root[data-theme="light"] {
	--color-accent: #d7262e;
	--color-accent-2: #e0383f;
	--color-accent-100: #4a1215;
	--color-accent-200: #6e171b;
	--color-accent-300: #a81d24;
	--color-accent-400: #d7262e;
	--color-accent-500: #e0383f;
	--color-accent-600: #ec7176;
	--color-accent-700: #f5a9ac;
	--color-accent-800: #fad4d5;
	--color-accent-900: #fdecec;
	--color-charcoal: #2b2d33;

	--color-link: #1a5bc4;
	--color-link-hover: #0f4291;

	--btn-primary-disabled-bg: var(--brand-green-200);
	--btn-primary-disabled-fg: #6fb08a;
	--btn-danger-disabled-bg: var(--brand-red-200);
	--btn-danger-disabled-fg: #e08d91;
	--btn-secondary-fg: var(--color-text, #292b31);
	--btn-danger-fg: var(--color-danger, #b3424a);
	--btn-disabled-fg: color-mix(in srgb, var(--color-text, #292b31) 40%, transparent);
	--btn-disabled-border: color-mix(in srgb, var(--color-text, #292b31) 18%, transparent);
}

/* ---------------------------------------------------------------- buttons -- */
.btn {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px;
	box-sizing: border-box;
	padding: 5.6px 10px;
	font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1.2;
	color: var(--btn-secondary-fg); background: transparent;
	border: 1px solid transparent; border-radius: 8px;
	cursor: pointer; text-decoration: none; white-space: nowrap;
	transition: background-color .12s, border-color .12s, color .12s;
}
.btn.btn:hover, .btn.btn:focus { text-decoration: none; }
.btn:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.btn:disabled, .btn[aria-disabled="true"] { cursor: not-allowed; opacity: .45; }

.btn.btn-primary, .btn.btn-primary:link, .btn.btn-primary:visited {
	color: var(--btn-primary-fg); background: var(--btn-primary-bg); border-color: var(--btn-primary-bg);
}
.btn.btn-primary:hover { color: var(--btn-primary-fg); background: var(--btn-primary-hover); border-color: var(--btn-primary-hover); }
.btn.btn-primary:active { background: var(--btn-primary-active); border-color: var(--btn-primary-active); }

.btn.btn-secondary, .btn.btn-secondary:link, .btn.btn-secondary:visited {
	color: var(--btn-secondary-fg); background: transparent; border-color: var(--btn-secondary-border);
}
.btn.btn-secondary:hover { color: var(--btn-secondary-fg); background: color-mix(in srgb, var(--btn-secondary-fg) 8%, transparent); }
.btn.btn-secondary:active { background: color-mix(in srgb, var(--btn-secondary-fg) 15%, transparent); }

.btn.btn-ghost, .btn.btn-ghost:link, .btn.btn-ghost:visited { color: var(--btn-ghost-fg); padding-inline: 2.8px; }
.btn.btn-ghost:hover { color: var(--btn-ghost-fg); background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
.btn.btn-ghost:active { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }

.btn.btn-danger, .btn.btn-danger:link, .btn.btn-danger:visited {
	color: var(--btn-danger-text); background: var(--btn-danger-bg); border-color: var(--btn-danger-bg);
}
.btn.btn-danger:hover { color: var(--btn-danger-text); background: var(--btn-danger-hover); border-color: var(--btn-danger-hover); }
.btn.btn-danger:active { background: var(--btn-danger-active); border-color: var(--btn-danger-active); }

/* disabled = a light tint of the button's own colour (after hover, so it wins) */
.btn.btn-primary:disabled, .btn.btn-primary[aria-disabled="true"] {
	opacity: 1; color: var(--btn-primary-disabled-fg);
	background: var(--btn-primary-disabled-bg); border-color: var(--btn-primary-disabled-bg);
}
.btn.btn-danger:disabled, .btn.btn-danger[aria-disabled="true"] {
	opacity: 1; color: var(--btn-danger-disabled-fg);
	background: var(--btn-danger-disabled-bg); border-color: var(--btn-danger-disabled-bg);
}
.btn.btn-secondary:disabled, .btn.btn-secondary[aria-disabled="true"] {
	opacity: 1; color: var(--btn-disabled-fg); background: transparent; border-color: var(--btn-disabled-border);
}
.btn.btn-ghost:disabled, .btn.btn-ghost[aria-disabled="true"] {
	opacity: 1; color: var(--btn-disabled-fg); background: transparent; border-color: transparent;
}

/* a .btn with no role class still looks like a button: secondary (charcoal outline) */
.btn:not(.btn-primary, .btn-secondary, .btn-ghost, .btn-danger) { border-color: var(--btn-secondary-border); }
.btn:not(.btn-primary, .btn-secondary, .btn-ghost, .btn-danger):hover { background: color-mix(in srgb, var(--btn-secondary-fg) 8%, transparent); }
.btn:not(.btn-primary, .btn-secondary, .btn-ghost, .btn-danger):disabled { opacity: 1; color: var(--btn-disabled-fg); border-color: var(--btn-disabled-border); }

.btn.btn-sm { min-height: 26px; padding: 2px 8px; font-size: 12px; }
.btn.btn-icon { width: 32px; height: 32px; min-height: 32px; padding: 0; }
.btn.btn-block { width: 100%; margin-top: 5.6px; }

/* row-level icon delete: red icon, no box (outline only on hover/focus) */
.btn.btn-icon.btn-danger, .btn.btn-icon.btn-danger:link, .btn.btn-icon.btn-danger:visited,
.btn.btn-icon.btn-danger:active { color: var(--btn-danger-fg); background: transparent; border-color: transparent; }
.btn.btn-icon.btn-danger:hover, .btn.btn-icon.btn-danger:focus-visible {
	color: var(--btn-danger-fg); background: color-mix(in srgb, var(--btn-danger-fg) 12%, transparent); border-color: var(--btn-danger-fg);
}
.btn.btn-icon.btn-danger:disabled, .btn.btn-icon.btn-danger[aria-disabled="true"] {
	color: var(--btn-disabled-fg); background: transparent; border-color: transparent;
}

/* ---------------------------------------------------------- button hover -- */
/* Every button changes colour on hover and keyboard focus, and lifts a little
   (the "floating" feel of the document-processed card): primary / danger go
   one step darker with a soft coloured shadow, secondary (and a bare .btn)
   turns green-tinted with a green border and text, ghost gets a red tint.
   Pressed = no lift, no shadow. Disabled buttons and row icons never react.
   FA's own submit buttons use the same tokens (default.css, "buttons" block).
   Documentation: docs/ww/common/buttons.md (Hover and focus) */
:root {
	--btn-secondary-hover-fg: #a6e4bf;
	--btn-secondary-hover-bg: color-mix(in srgb, var(--brand-green) 22%, transparent);
	--btn-secondary-hover-border: #3fae6f;
	--btn-secondary-active-bg: color-mix(in srgb, var(--brand-green) 32%, transparent);
	--btn-ghost-hover-bg: color-mix(in srgb, var(--color-accent) 14%, transparent);
	--btn-ghost-active-bg: color-mix(in srgb, var(--color-accent) 22%, transparent);
	--btn-neutral-hover-bg: color-mix(in srgb, var(--btn-secondary-fg) 10%, transparent);
	--btn-primary-shadow: 0 6px 14px -6px color-mix(in srgb, var(--brand-green) 85%, transparent);
	--btn-danger-shadow: 0 6px 14px -6px color-mix(in srgb, var(--brand-red) 85%, transparent);
	--btn-secondary-shadow: 0 4px 12px -6px rgba(0, 0, 0, .6);
	--btn-hover-lift: translateY(-1px);
}
:root[data-theme="light"] {
	--btn-secondary-hover-fg: var(--brand-green-800);
	--btn-secondary-hover-bg: color-mix(in srgb, var(--brand-green) 9%, transparent);
	--btn-secondary-hover-border: var(--brand-green);
	--btn-secondary-active-bg: color-mix(in srgb, var(--brand-green) 16%, transparent);
	--btn-secondary-shadow: 0 4px 12px -6px rgba(41, 43, 49, .35);
}
.btn { transition: background-color .15s, border-color .15s, color .15s, box-shadow .15s, transform .1s; }
.btn.btn-primary:not(.btn-icon, :disabled, [aria-disabled="true"]):is(:hover, :focus-visible) {
	color: var(--btn-primary-fg); background: var(--btn-primary-hover); border-color: var(--btn-primary-hover);
	box-shadow: var(--btn-primary-shadow);
}
.btn.btn-danger:not(.btn-icon, :disabled, [aria-disabled="true"]):is(:hover, :focus-visible) {
	color: var(--btn-danger-text); background: var(--btn-danger-hover); border-color: var(--btn-danger-hover);
	box-shadow: var(--btn-danger-shadow);
}
.btn.btn-secondary:not(:disabled, [aria-disabled="true"]):is(:hover, :focus-visible),
.btn:not(.btn-primary, .btn-secondary, .btn-ghost, .btn-danger, :disabled, [aria-disabled="true"]):is(:hover, :focus-visible) {
	color: var(--btn-secondary-hover-fg); background: var(--btn-secondary-hover-bg);
	border-color: var(--btn-secondary-hover-border); box-shadow: var(--btn-secondary-shadow);
}
.btn.btn-secondary:not(:disabled, [aria-disabled="true"]):active,
.btn:not(.btn-primary, .btn-secondary, .btn-ghost, .btn-danger, :disabled, [aria-disabled="true"]):active {
	background: var(--btn-secondary-active-bg);
}
.btn.btn-ghost:not(:disabled, [aria-disabled="true"]):is(:hover, :focus-visible) { color: var(--btn-ghost-fg); background: var(--btn-ghost-hover-bg); }
.btn.btn-ghost:not(:disabled, [aria-disabled="true"]):active { background: var(--btn-ghost-active-bg); }
.btn:not(.btn-icon, .btn-ghost, :disabled, [aria-disabled="true"]):hover { transform: var(--btn-hover-lift); }
.btn:not(.btn-icon):active { transform: none; box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .btn, .btn:hover { transition: none; transform: none; } }

/* ----------------------------------------------------------------- tables -- */
/* A hand-written <table> that can't be a DataTable (an entry grid with inputs,
   a statement with grouped rows): <table class="jd-table">, totals rows in
   <tfoot> or <tr class="jd-total">. Same header / row / footer as DataTable
   and the classic lists. Data lists use DataTable (Vue) / start_table() (PHP). */
table.jd-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
table.jd-table th, table.jd-table thead td {
	height: var(--table-head-h); padding: 4px 14px; text-align: left; vertical-align: middle;
	font-size: var(--table-head-size); font-weight: 500; letter-spacing: var(--table-head-tracking); text-transform: uppercase;
	color: var(--table-head-fg); background: var(--table-head-bg); border-bottom: 1px solid var(--table-line); white-space: nowrap;
}
table.jd-table td { height: var(--table-row-h); padding: 4px 14px; vertical-align: middle; border-bottom: 1px solid var(--table-line); }
table.jd-table tbody tr:hover > td { background: var(--table-row-hover); }
table.jd-table tfoot td, table.jd-table tr.jd-total > td {
	font-weight: 600; color: var(--table-foot-fg); background: var(--table-foot-bg); border-top: 2px solid var(--table-foot-line);
}
table.jd-table .num, table.jd-table th.num { text-align: right; }

/* ------------------------------------------------------------ row actions -- */
/* The coloured icon buttons at the right of a table row: one colour per meaning,
   a tinted chip at rest, solid colour + contrasting icon on hover / focus, and a
   tooltip with the action's name. The colour comes from data-jd-act="<kind>":
   - classic FA rows: set_icon() emits <span class="jd-act" data-jd-act=..> inside
     the row's link / button (includes/ui/row_actions.inc);
   - Vue: components/ui/RowAction.vue (the link / button itself carries it);
   - anything else icon-only in a table cell is tagged by js/jd_row_actions.js from
     its title / aria-label. data-jd-act="off" (or data-jd-acts="off" on a
     container) opts out. Kinds: includes/ui/row_actions.json.
   The :not(#jd-act-x) bumps specificity on purpose so a screen's own icon-button
   style (.btn-icon, scoped Vue classes) never wins over the action colour.
   Documentation: docs/ww/common/row-actions.md */
:root {
	--act-size: 30px;
	--act-icon: 17px;
	--act-radius: 8px;
	--act-gap: 6px;
	--act-chip-mix: 18%;
	--act-on: #111318;            /* icon colour on a solid (hovered) chip */
	--act-tip-bg: #e9e9ed;
	--act-tip-fg: #15161b;
	/* dark theme inks */
	--act-blue: #7c9cff;          /* gl: View GL postings */
	--act-sky: #4cc3ec;           /* view / open */
	--act-violet: #b39af0;        /* edit */
	--act-teal: #4fd1c5;          /* copy / clone */
	--act-rose: #f38595;          /* credit / return */
	--act-slate: #a7b2d6;         /* print, download */
	--act-red: #f87171;           /* delete, void */
	--act-green: #4ade80;         /* approve, select, update */
	--act-orange: #fb923c;        /* reject */
	--act-amber: #fbbf24;         /* deactivate */
	--act-magenta: #e879f9;       /* email / send */
	--act-gold: #facc15;          /* allocate */
	--act-lime: #a3e635;          /* pay */
	--act-cyan: #22d3ee;          /* receive */
	--act-indigo: #a5b4fc;        /* invoice */
	--act-grey: #9ca3af;          /* cancel, attach, locked */
}
:root[data-theme="light"] {
	--act-chip-mix: 13%;
	--act-on: #ffffff;
	--act-tip-bg: #1e2a55;
	--act-tip-fg: #ffffff;
	--act-blue: #2f5bd8;
	--act-sky: #0b7fab;
	--act-violet: #7048c8;
	--act-teal: #0f8a84;
	--act-rose: #d0364a;
	--act-slate: #4b5a86;
	--act-red: #c81e26;
	--act-green: #1a7f45;
	--act-orange: #c2410c;
	--act-amber: #b45309;
	--act-magenta: #a23b9c;
	--act-gold: #a16207;
	--act-lime: #4d7c0f;
	--act-cyan: #0e7490;
	--act-indigo: #4338ca;
	--act-grey: #64748b;
}
[data-jd-act="gl"] { --act-ink: var(--act-blue); }
[data-jd-act="view"] { --act-ink: var(--act-sky); }
[data-jd-act="edit"] { --act-ink: var(--act-violet); }
[data-jd-act="copy"] { --act-ink: var(--act-teal); }
[data-jd-act="credit"] { --act-ink: var(--act-rose); }
[data-jd-act="print"], [data-jd-act="download"] { --act-ink: var(--act-slate); }
[data-jd-act="delete"], [data-jd-act="void"] { --act-ink: var(--act-red); }
[data-jd-act="approve"] { --act-ink: var(--act-green); }
[data-jd-act="reject"] { --act-ink: var(--act-orange); }
[data-jd-act="deactivate"] { --act-ink: var(--act-amber); }
[data-jd-act="email"] { --act-ink: var(--act-magenta); }
[data-jd-act="allocate"] { --act-ink: var(--act-gold); }
[data-jd-act="pay"] { --act-ink: var(--act-lime); }
[data-jd-act="receive"] { --act-ink: var(--act-cyan); }
[data-jd-act="invoice"] { --act-ink: var(--act-indigo); }
[data-jd-act="cancel"], [data-jd-act="attach"], [data-jd-act="locked"] { --act-ink: var(--act-grey); }

/* a group of row actions (optional): right-aligned, even gaps */
.jd-acts { display: inline-flex; align-items: center; justify-content: flex-end; gap: var(--act-gap); vertical-align: middle; }

/* the chip */
[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x), .jd-act.jd-act-slot {
	position: relative; box-sizing: border-box; flex: none;
	display: inline-flex; align-items: center; justify-content: center;
	width: var(--act-size); height: var(--act-size); min-width: var(--act-size); min-height: 0;
	margin: 0; padding: 0; border: 0; border-radius: var(--act-radius);
	color: var(--act-ink, var(--act-grey)); background: color-mix(in srgb, var(--act-ink, var(--act-grey)) var(--act-chip-mix), transparent);
	font-size: 0; line-height: 1; text-decoration: none; vertical-align: middle; cursor: inherit;
	transition: background-color .15s ease, color .15s ease, box-shadow .15s ease, transform .1s ease;
}
:is(a, button)[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x),
:is(a, button) > .jd-act[data-jd-act]:not(#jd-act-x) { cursor: pointer; }
[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x) svg { width: var(--act-icon); height: var(--act-icon); flex: none; }
.jd-act-svg { fill: currentColor; }
.jd-act.jd-act-slot { visibility: hidden; pointer-events: none; }

/* the link / button around a classic chip: no box, no underline of its own */
:is(a, button):has(> .jd-act[data-jd-act]):not(#jd-act-x) {
	display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
	width: auto; height: auto; min-width: 0; min-height: 0; margin: 0; padding: 0;
	border: 0; border-radius: var(--act-radius); background: transparent; box-shadow: none;
	text-decoration: none; outline: none;
}

/* hover / keyboard focus: solid colour, contrasting icon */
:is(a, button)[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x):is(:hover, :focus-visible),
:is(a, button):is(:hover, :focus-visible) > .jd-act[data-jd-act]:not(#jd-act-x) {
	color: var(--act-on); background: var(--act-ink, var(--act-grey));
	box-shadow: 0 4px 10px -3px color-mix(in srgb, var(--act-ink, var(--act-grey)) 55%, transparent);
	outline: none;
}
:is(a, button)[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x):focus-visible,
:is(a, button):focus-visible > .jd-act[data-jd-act]:not(#jd-act-x) {
	box-shadow: 0 0 0 2px var(--color-bg, #fff), 0 0 0 4px var(--act-ink, var(--act-grey));
}
:is(a, button)[data-jd-act]:not([data-jd-act="off"]):not(#jd-act-x):active,
:is(a, button):active > .jd-act[data-jd-act]:not(#jd-act-x) { transform: scale(.92); }

/* disabled: keep the tint, no hover */
:is(button[disabled], [aria-disabled="true"])[data-jd-act]:not(#jd-act-x),
:is(button[disabled], [aria-disabled="true"]) > .jd-act[data-jd-act]:not(#jd-act-x) {
	opacity: .45; cursor: not-allowed; transform: none; box-shadow: none;
	color: var(--act-ink, var(--act-grey)); background: color-mix(in srgb, var(--act-ink, var(--act-grey)) var(--act-chip-mix), transparent);
}

/* tooltip: CSS fallback; js/jd_row_actions.js shows one floating tip instead
   (never clipped by a scrolling table) and sets html.jd-act-js */
[data-jd-act][data-tip]:not([data-jd-act="off"])::after {
	content: attr(data-tip);
	position: absolute; bottom: calc(100% + 6px); left: 50%; z-index: 20;
	transform: translate(-50%, 4px);
	padding: 6px 8px; border-radius: 5px; white-space: nowrap;
	font: 500 11px/1 Inter, system-ui, sans-serif; letter-spacing: 0; text-transform: none;
	color: var(--act-tip-fg); background: var(--act-tip-bg);
	opacity: 0; pointer-events: none; transition: opacity .12s, transform .12s;
}
:is(:hover, :focus-visible) > [data-jd-act][data-tip]::after,
[data-jd-act][data-tip]:is(:hover, :focus-visible)::after { opacity: 1; transform: translate(-50%, 0); }
html.jd-act-js [data-jd-act][data-tip]::after { content: none; }
.jd-act-tip {
	position: fixed; z-index: 10000; pointer-events: none; max-width: 280px;
	padding: 6px 8px; border-radius: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
	font: 500 11px/1 Inter, system-ui, sans-serif; color: var(--act-tip-fg); background: var(--act-tip-bg);
	box-shadow: 0 4px 12px -4px rgba(0, 0, 0, .35);
	opacity: 0; transform: translateY(4px); transition: opacity .12s, transform .12s;
}
.jd-act-tip.jd-act-tip-on { opacity: 1; transform: translateY(0); }

/* a Vue DataTable cell clips overflow (ellipsis); not around actions */
[role="gridcell"]:has([data-jd-act]) { overflow: visible; }

@media (prefers-reduced-motion: reduce) {
	[data-jd-act], [data-jd-act]::after, .jd-act-tip { transition: none; }
}
@media print {
	[data-jd-act]:not(#jd-act-x) { background: none; }
}

/* -------------------------------------------------------------- skeletons -- */
/* Loading placeholders in the shape of the page that is coming: one look for
   classic screens, Vue islands and the instant click feedback (js/jd_skeleton.js).
   Markup comes from jdSkeleton.html(template) (JS), jd_skeleton_html() (PHP,
   includes/skeleton.inc - same string) or components/ui/Skeleton*.vue.
   Templates: list, form, detail, dashboard, menu, report.
   Documentation: docs/ww/common/skeletons.md */
:root {
	--jd-sk-base: color-mix(in srgb, var(--color-text, #e9e9ed) 9%, transparent);
	--jd-sk-shine: color-mix(in srgb, var(--color-text, #e9e9ed) 16%, transparent);
	--jd-sk-line: var(--color-neutral-800, #3f424d);
	--jd-sk-panel: var(--color-surface, #232532);
}
@keyframes jd-sk-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.jd-sk {
	display: block; box-sizing: border-box; border-radius: 3px;
	background: var(--jd-sk-base) linear-gradient(90deg, transparent 30%, var(--jd-sk-shine) 50%, transparent 70%) 0 0 / 200% 100% no-repeat;
	animation: jd-sk-shimmer 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .jd-sk { animation: none; background-image: none; } }
.jd-sk-line { height: 10px; width: 70%; }
.jd-sk-line.jd-sk-lg { height: 14px; }
.jd-sk-block { height: 120px; width: 100%; }
.jd-sk-circle { width: 32px; height: 32px; border-radius: 50%; flex: none; }
.jd-sk-icon { width: 24px; height: 24px; flex: none; }
.jd-sk-input { height: 32px; width: 100%; }
.jd-sk-btn { height: 32px; width: 96px; flex: none; }
.jd-sk-tag { height: 18px; width: 64px; flex: none; }
.jd-sk-value { height: 22px; width: 55%; margin: 4px 0; }
.jd-sk-w20 { width: 20%; } .jd-sk-w30 { width: 30%; } .jd-sk-w40 { width: 40%; } .jd-sk-w50 { width: 50%; }
.jd-sk-w60 { width: 60%; } .jd-sk-w70 { width: 70%; } .jd-sk-w80 { width: 80%; } .jd-sk-w90 { width: 90%; }

/* containers */
.jd-sk-host { grid-column: 1 / -1; min-width: 0; }
.jd-sk-page { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.jd-sk-panel { background: var(--jd-sk-panel); border: 1px solid var(--jd-sk-line); min-width: 0; }
.jd-sk-ph { min-height: 40px; display: flex; align-items: center; gap: 10px; padding: 6px 14px; border-bottom: 1px solid var(--jd-sk-line); }
.jd-sk-ph .jd-sk-line { width: 140px; }
.jd-sk-pad { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.jd-sk-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; padding: 10px 14px; background: var(--jd-sk-panel); border: 1px solid var(--jd-sk-line); }
.jd-sk-bar .jd-sk-input { width: 160px; height: 28px; }
.jd-sk-bar .jd-sk-btn { height: 28px; width: 80px; }
.jd-sk-spacer { flex: 1; }
.jd-sk-tr { display: grid; grid-template-columns: 1.4fr 1fr 1fr 0.8fr 0.8fr; gap: 0 12px; align-items: center; height: var(--table-row-h, 42px); padding: 0 14px; border-bottom: 1px solid var(--jd-sk-line); }
.jd-sk-tr.jd-sk-th { height: var(--table-head-h, 30px); background: var(--table-head-bg, transparent); }
.jd-sk-tr.jd-sk-th .jd-sk-line { height: 8px; width: 50%; }
.jd-sk-tr > :nth-child(n+4) { justify-self: end; width: 60%; }
.jd-sk-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 32px; padding: 14px; }
.jd-sk-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.jd-sk-lines { gap: 10px; padding: 4px 0; }
.jd-sk-field { display: flex; flex-direction: column; gap: 7px; }
.jd-sk-field > .jd-sk-line { height: 8px; width: 30%; }
.jd-sk-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--jd-sk-line); }
.jd-sk-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.jd-sk-tile { background: var(--jd-sk-panel); border: 1px solid var(--jd-sk-line); padding: 11px 14px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.jd-sk-tile > .jd-sk-line { height: 8px; width: 45%; }
.jd-sk-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.jd-sk-grid.jd-sk-even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.jd-sk-grid.jd-sk-side { grid-template-columns: minmax(220px, 1fr) minmax(0, 2fr); }
.jd-sk-hero { display: flex; align-items: center; gap: 14px; padding: 14px; }
.jd-sk-hero > div { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.jd-sk-tabs { display: flex; gap: 18px; padding: 0 14px; height: 38px; align-items: center; border-top: 1px solid var(--jd-sk-line); }
.jd-sk-tabs .jd-sk-line { width: 72px; }
.jd-sk-kv { display: grid; grid-template-columns: minmax(90px, 0.6fr) minmax(0, 1fr); gap: 12px 16px; padding: 14px; align-items: center; }
.jd-sk-kv > .jd-sk-line:nth-child(odd) { height: 8px; width: 70%; }
.jd-sk-list { display: flex; flex-direction: column; }
.jd-sk-list > .jd-sk-item { display: flex; align-items: center; gap: 10px; height: 34px; padding: 0 14px; }
.jd-sk-menu { display: flex; flex-direction: column; gap: 16px; }
.jd-sk-sec { background: var(--jd-sk-panel); border: 1px solid var(--jd-sk-line); }
.jd-sk-sec > .jd-sk-ph { justify-content: center; }
.jd-sk-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.jd-sk-cols > .jd-sk-list { padding: 6px 0; }
.jd-sk-cols > .jd-sk-list + .jd-sk-list { border-left: 1px solid var(--jd-sk-line); }
.jd-sk-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Vue page before the bundle has mounted (ui_page()): header + tab row + body */
.jd-sk-shell { min-height: 100vh; display: flex; flex-direction: column; }
.jd-sk-top { height: 56px; flex: none; display: flex; align-items: center; gap: 14px; padding: 0 24px; border-bottom: 1px solid var(--jd-sk-line); }
.jd-sk-top .jd-sk-line { width: 120px; }
.jd-sk-top .jd-sk-input { width: min(400px, 40%); margin-left: auto; }
.jd-sk-tabbar { height: 46px; flex: none; display: flex; align-items: center; gap: 28px; padding: 0 30px; border-bottom: 1px solid var(--jd-sk-line); overflow: hidden; }
.jd-sk-tabbar .jd-sk-line { width: 80px; flex: none; }
.jd-sk-main { padding: 12px 24px 24px; }

/* the page body while the next page loads (js/jd_skeleton.js): everything else is hidden */
.jd-sk-on > :not(.jd-sk-host) { display: none !important; }

@media (max-width: 900px) {
	.jd-sk-grid, .jd-sk-grid.jd-sk-even, .jd-sk-grid.jd-sk-side { grid-template-columns: minmax(0, 1fr); }
	.jd-sk-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
	.jd-sk-form, .jd-sk-cols { grid-template-columns: minmax(0, 1fr); }
	.jd-sk-form { gap: 14px; }
	.jd-sk-cols > .jd-sk-list + .jd-sk-list { border-left: 0; border-top: 1px solid var(--jd-sk-line); }
	.jd-sk-tr { grid-template-columns: 1.4fr 1fr 0.8fr; }
	.jd-sk-tr > :nth-child(n+4) { display: none; }
	.jd-sk-tr > :nth-child(3) { justify-self: end; width: 60%; }
	.jd-sk-top, .jd-sk-main { padding-left: 16px; padding-right: 16px; }
	.jd-sk-tabbar { padding: 0 16px; }
	.jd-sk-bar .jd-sk-input { width: 100%; }
}

/* --------------------------------------------------------------------------
   Smooth page changes (cross-document view transitions). Every page loads
   this file, so a same-site link or form post cross-fades instead of flashing
   white. The header and module tabs are named only while a transition runs
   (js/jd_prefetch.js sets html.jd-vt on pageswap / pagereveal), so they stay
   still and only the content fades. Classic shell: header.jd-top / .jd-tabbar
   (themes/default/renderer.php); Nocturne: AppShell.vue (same classes as
   markers: .jd-vt-header / .jd-vt-tabs). Browsers without support ignore it.
   Documentation: docs/ww/common/prefetch.md
   -------------------------------------------------------------------------- */
@view-transition { navigation: auto; }
html.jd-vt .jd-vt-header { view-transition-name: jd-header; }
html.jd-vt .jd-vt-tabs { view-transition-name: jd-tabs; }
::view-transition-group(*) { animation-duration: 150ms; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 150ms; }
/* The chrome barely changes: swap it without a visible fade. */
::view-transition-old(jd-header), ::view-transition-old(jd-tabs) { animation: none; opacity: 0; }
::view-transition-new(jd-header), ::view-transition-new(jd-tabs) { animation: none; }
@media (prefers-reduced-motion: reduce) {
	@view-transition { navigation: none; }
}
