/**
 * app-demo.css — reusable "app demo" component styles.
 *
 * A faithful, self-contained re-creation of the real ABA FT app UI, built for
 * the site-wide app-demo player (assets/js/app-demo.js + inc/app-demo.php). It
 * is NOT the website's own design system: every token below is the APP's token,
 * sourced from the app-render engine's vendored app.css
 * (ops/graphics/studio/app-render/vendor/app.css), and is SCOPED under
 * `.abaft-demo` so it never leaks into the marketing site's tokens or styles.
 *
 * Add a new demo on any page by calling abaft_app_demo() (see inc/app-demo.php);
 * that helper emits a `.abaft-demo` container whose FINAL filled state is
 * server-rendered (crawlable + the reduced-motion / no-JS fallback). The player
 * animates the SAME markup in place. Nothing here assumes the user-guide.
 *
 * Only the pieces the pilots need are built: the modal shell, form fields, time
 * pickers, the Organization / Supervisor selects, the Hour Allotment split with
 * its live "Remaining" counter, the Contact / Observation toggles, and the
 * action buttons. Extend by adding more app components under `.abaft-demo`.
 */

/* ───────────────────────────── app tokens (scoped) ───────────────────────── */
.abaft-demo {
	--ad-purple-900: #220066;
	--ad-purple-700: #3D1499;
	--ad-purple-600: #5B34B5;
	--ad-purple-500: #7C5CCF;
	--ad-purple-400: #9D82E0;
	--ad-purple-50:  #F7F4FD;

	--ad-gray-900: #1A1A2E;
	--ad-gray-600: #5E5E78;
	--ad-gray-500: #6A6A85;
	--ad-gray-400: #9E9EB4;
	--ad-gray-300: #C4C4D4;
	--ad-gray-200: #E2E2EC;
	--ad-gray-100: #F0F0F6;
	--ad-gray-50:  #F8F8FB;

	--ad-green-700: #047857;
	--ad-green-600: #059669;
	--ad-green-500: #10B981;
	--ad-green-50:  #ECFDF5;

	--ad-bg-primary: #FFFFFF;
	--ad-bg-secondary: var(--ad-gray-50);
	--ad-bg-tertiary: var(--ad-gray-100);
	--ad-bg-input: #FFFFFF;
	--ad-border: var(--ad-gray-200);
	--ad-border-secondary: var(--ad-gray-100);
	--ad-text-primary: var(--ad-gray-900);
	--ad-text-secondary: var(--ad-gray-600);
	--ad-text-tertiary: var(--ad-gray-500);
	--ad-accent: var(--ad-purple-600);
	--ad-accent-hover: var(--ad-purple-700);
	--ad-accent-light: var(--ad-purple-50);

	--ad-radius-sm: 6px;
	--ad-radius-md: 10px;
	--ad-radius-lg: 14px;
	--ad-radius-xl: 20px;
	--ad-radius-full: 9999px;
	--ad-transition: 150ms ease;
	--ad-shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
	--ad-shadow-xl: 0 8px 32px rgba(0,0,0,0.10);

	/* The app uses Plus Jakarta Sans; the marketing site self-hosts Hanken
	   Grotesk. Prefer the app face when present, then fall back cleanly. */
	font-family: 'Plus Jakarta Sans', 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
	color: var(--ad-text-primary);
	-webkit-font-smoothing: antialiased;
}

/* ─────────────────────────── window frame (the "app") ─────────────────────── */
/* A subtle desktop-app window so the modal reads as living inside the product,
   mirroring the .ug-shot--real "app window" chrome used for static captures. */
.abaft-demo {
	display: block;
	width: 100%;
	background: var(--ad-bg-secondary);
	border: 1px solid var(--ad-border);
	border-radius: var(--ad-radius-lg);
	box-shadow: var(--ad-shadow-sm);
	overflow: hidden;
}

.abaft-demo-chrome {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 10px 14px;
	background: var(--ad-bg-primary);
	border-bottom: 1px solid var(--ad-border-secondary);
}
.abaft-demo-dot {
	width: 8px; height: 8px; border-radius: 50%;
	background: var(--ad-gray-300);
}
.abaft-demo-dot:nth-child(1) { background: #FF7A5C; }
.abaft-demo-dot:nth-child(2) { background: #E9C46A; }
.abaft-demo-dot:nth-child(3) { background: var(--ad-purple-400); }
.abaft-demo-chrome-title {
	margin-left: 8px;
	font-size: 0.72rem; font-weight: 600; letter-spacing: 0.02em;
	color: var(--ad-text-tertiary);
}
.abaft-demo-replay {
	margin-left: auto;
	display: inline-flex; align-items: center; gap: 5px;
	padding: 4px 10px; border: 1px solid var(--ad-border);
	border-radius: var(--ad-radius-full); background: var(--ad-bg-primary);
	font-family: inherit; font-size: 0.72rem; font-weight: 600;
	color: var(--ad-text-secondary); cursor: pointer;
	transition: all var(--ad-transition);
	opacity: 0; pointer-events: none;
}
.abaft-demo.is-done .abaft-demo-replay { opacity: 1; pointer-events: auto; }
.abaft-demo-replay:hover { border-color: var(--ad-accent); color: var(--ad-accent); background: var(--ad-accent-light); }
.abaft-demo-replay svg { width: 13px; height: 13px; }

.abaft-demo-stage { padding: 18px; }

/* ───────────────────────────── the modal surface ──────────────────────────── */
/* A flattened, in-page version of the app's .modal (no fixed overlay — the demo
   IS the surface). Keeps the app's radius, header, body padding, and shadow. */
.abaft-demo .ad-modal {
	background: var(--ad-bg-primary);
	border-radius: var(--ad-radius-xl);
	box-shadow: var(--ad-shadow-xl);
	overflow: hidden;
	box-sizing: border-box;
	width: 100%;
}
.abaft-demo .ad-modal-header {
	display: flex; align-items: center; justify-content: space-between;
	padding: 1.1rem 1.35rem;
	border-bottom: 1px solid var(--ad-border-secondary);
}
.abaft-demo .ad-modal-title { font-size: 1.05rem; font-weight: 700; margin: 0; color: var(--ad-text-primary); }
.abaft-demo .ad-modal-close {
	color: var(--ad-text-tertiary); font-size: 1.4rem; line-height: 1;
	width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
}
.abaft-demo .ad-modal-body { padding: 1.35rem; }

/* ─────────────────────────────── form primitives ──────────────────────────── */
.abaft-demo .ad-form-group { margin-bottom: 1.1rem; }
.abaft-demo .ad-form-group.compact { margin-bottom: 0.25rem; }
.abaft-demo .ad-label {
	display: block; font-size: 0.8125rem; font-weight: 600;
	color: var(--ad-text-secondary); margin-bottom: 0.375rem; letter-spacing: 0.01em;
}
.abaft-demo .ad-label.xs { font-size: 0.72rem; }

.abaft-demo .ad-input,
.abaft-demo .ad-select {
	width: 100%; box-sizing: border-box;
	padding: 0.625rem 0.875rem; font-family: inherit; font-size: 0.9375rem;
	color: var(--ad-text-primary); background: var(--ad-bg-input);
	border: 1.5px solid var(--ad-border); border-radius: var(--ad-radius-md);
	transition: border-color var(--ad-transition), box-shadow var(--ad-transition);
	outline: none; line-height: 1.2;
}
.abaft-demo .ad-input.is-placeholder,
.abaft-demo .ad-select.is-placeholder { color: var(--ad-text-tertiary); }
.abaft-demo .ad-field.is-focus .ad-input,
.abaft-demo .ad-field.is-focus .ad-select,
.abaft-demo .ad-field.is-focus .ad-time,
.abaft-demo .ad-field.is-focus .ad-textarea {
	border-color: var(--ad-accent);
	box-shadow: 0 0 0 3px var(--ad-accent-light);
}

.abaft-demo .ad-select {
	appearance: none; -webkit-appearance: none;
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236A6A85' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.75rem center;
	padding-right: 2.25rem;
}

.abaft-demo .ad-select-row { display: flex; gap: 0.5rem; align-items: center; }
.abaft-demo .ad-select-row .ad-select { flex: 1; }
.abaft-demo .ad-add-btn {
	flex-shrink: 0; width: 44px; height: 42px;
	display: inline-flex; align-items: center; justify-content: center;
	border: 1.5px solid var(--ad-border); border-radius: var(--ad-radius-md);
	background: var(--ad-bg-primary); color: var(--ad-text-secondary);
	font-size: 1.1rem; line-height: 1;
}

.abaft-demo .ad-row { display: grid; gap: 0.75rem; }
.abaft-demo .ad-row.three { grid-template-columns: 1fr 1fr 1fr; }
.abaft-demo .ad-row.two { grid-template-columns: 1fr 1fr; }

.abaft-demo .ad-textarea {
	width: 100%; box-sizing: border-box; resize: none;
	padding: 0.625rem 0.875rem; font-family: inherit; font-size: 0.9375rem;
	color: var(--ad-text-primary); background: var(--ad-bg-input);
	border: 1.5px solid var(--ad-border); border-radius: var(--ad-radius-md);
	line-height: 1.4; min-height: 3.4rem;
	transition: border-color var(--ad-transition), box-shadow var(--ad-transition);
}
.abaft-demo .ad-textarea.is-placeholder { color: var(--ad-text-tertiary); }
.abaft-demo .ad-tertiary { color: var(--ad-text-tertiary); font-weight: 400; }

/* ─────────────────────────────── time picker ──────────────────────────────── */
.abaft-demo .ad-time {
	display: flex; align-items: center;
	border: 1.5px solid var(--ad-border); border-radius: var(--ad-radius-md);
	background: var(--ad-bg-input); overflow: hidden;
	transition: border-color var(--ad-transition), box-shadow var(--ad-transition);
}
.abaft-demo .ad-time-part {
	flex: 1; min-width: 0; text-align: center;
	font-family: inherit; font-size: 0.9375rem; color: var(--ad-text-primary);
	padding: 0.625rem 0;
}
.abaft-demo .ad-time-part.is-placeholder { color: var(--ad-text-tertiary); }
.abaft-demo .ad-time-sep {
	font-size: 0.9375rem; color: var(--ad-text-tertiary); font-weight: 600;
	padding: 0 2px; flex-shrink: 0;
}
.abaft-demo .ad-time-ampm {
	padding: 0.625rem 0.75rem; border-left: 1px solid var(--ad-border-secondary);
	background: var(--ad-bg-secondary); color: var(--ad-text-secondary);
	font-size: 0.8125rem; font-weight: 700; letter-spacing: 0.04em;
	flex-shrink: 0; line-height: 1;
}

.abaft-demo .ad-date-wrap { position: relative; }
.abaft-demo .ad-date-icon {
	position: absolute; right: 0.75rem; top: 50%; transform: translateY(-50%);
	width: 16px; height: 16px; color: var(--ad-text-tertiary); pointer-events: none;
}

/* ─────────────────────────── hour allotment card ──────────────────────────── */
.abaft-demo .ad-allotment {
	background: var(--ad-bg-secondary); border: 1px solid var(--ad-border);
	border-radius: var(--ad-radius-lg); padding: 1.1rem; margin-bottom: 1.1rem;
}
.abaft-demo .ad-allotment-head {
	display: flex; align-items: center; justify-content: space-between;
	margin-bottom: 0.75rem;
}
.abaft-demo .ad-allotment-head-left { display: flex; align-items: center; gap: 0.375rem; }
.abaft-demo .ad-allotment-label { font-size: 0.8125rem; font-weight: 600; color: var(--ad-text-secondary); }
.abaft-demo .ad-help {
	width: 20px; height: 20px; border-radius: 50%;
	display: inline-flex; align-items: center; justify-content: center;
	color: var(--ad-text-tertiary);
}
.abaft-demo .ad-help svg { width: 18px; height: 18px; }
.abaft-demo .ad-remaining { font-size: 0.8125rem; color: var(--ad-text-secondary); }
.abaft-demo .ad-remaining strong {
	color: var(--ad-green-600); font-weight: 700;
	font-variant-numeric: tabular-nums;
	transition: color var(--ad-transition);
}
.abaft-demo .ad-remaining.is-counting strong { color: var(--ad-purple-600); }

.abaft-demo .ad-alloc-section {
	margin-bottom: 0.5rem; padding: 0.5rem; border-radius: var(--ad-radius-sm);
	border-left: 3px solid transparent;
}
.abaft-demo .ad-alloc-section:last-child { margin-bottom: 0; }
.abaft-demo .ad-alloc-independent { background: var(--ad-purple-50); border-left-color: var(--ad-purple-400); }
.abaft-demo .ad-alloc-supervised { background: var(--ad-green-50); border-left-color: var(--ad-green-500); }
.abaft-demo .ad-alloc-title {
	display: block; font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
	letter-spacing: 0.05em; margin-bottom: 0.4rem;
}
.abaft-demo .ad-alloc-independent .ad-alloc-title { color: var(--ad-purple-600); }
.abaft-demo .ad-alloc-supervised .ad-alloc-title { color: var(--ad-green-700); }

.abaft-demo .ad-hm { display: flex; align-items: center; gap: 0.2rem; }
.abaft-demo .ad-hm-box {
	width: 2.75rem; text-align: center; padding: 0.5rem 0.25rem;
	font-size: 0.875rem; color: var(--ad-text-primary);
	background: var(--ad-bg-input); border: 1.5px solid var(--ad-border);
	border-radius: var(--ad-radius-md); box-sizing: border-box;
	font-variant-numeric: tabular-nums;
	transition: border-color var(--ad-transition), box-shadow var(--ad-transition);
}
.abaft-demo .ad-hm-box.is-placeholder { color: var(--ad-text-tertiary); }
.abaft-demo .ad-unit { font-size: 0.75rem; font-weight: 600; color: var(--ad-text-tertiary); min-width: 0.75rem; }

/* ─────────────────────────────── toggles ──────────────────────────────────── */
.abaft-demo .ad-toggles { display: flex; gap: 0.5rem; margin-bottom: 1.1rem; }
.abaft-demo .ad-toggle {
	flex: 1;
	display: flex; align-items: center; justify-content: center; gap: 0.375rem;
	padding: 0.625rem 0.75rem; border-radius: var(--ad-radius-md);
	border: 1.5px solid var(--ad-border); background: var(--ad-bg-input);
	font-size: 0.8125rem; font-weight: 500; color: var(--ad-text-secondary);
	transition: all var(--ad-transition); text-align: center;
}
.abaft-demo .ad-toggle svg { flex-shrink: 0; opacity: 0.5; transition: opacity var(--ad-transition); }
.abaft-demo .ad-toggle.is-on {
	border-color: var(--ad-accent); background: var(--ad-accent-light);
	color: var(--ad-accent); font-weight: 600;
}
.abaft-demo .ad-toggle.is-on svg { opacity: 1; }

/* Observation duration row (revealed when Observation toggles on). */
.abaft-demo .ad-obs-row {
	display: none; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-bottom: 1.1rem;
}
.abaft-demo .ad-obs-row.is-shown { display: grid; }

/* ─────────────────────────────── actions ──────────────────────────────────── */
.abaft-demo .ad-actions { display: flex; justify-content: flex-end; gap: 0.75rem; }
.abaft-demo .ad-btn {
	padding: 0.625rem 1.25rem; font-family: inherit; font-size: 0.875rem; font-weight: 600;
	line-height: 1; border-radius: var(--ad-radius-md); border: 1px solid transparent;
	cursor: default;
}
.abaft-demo .ad-btn-secondary { background: var(--ad-bg-primary); color: var(--ad-text-primary); border-color: var(--ad-border); }
.abaft-demo .ad-btn-primary { background: var(--ad-accent); color: #fff; }
.abaft-demo .ad-btn-primary.is-highlight {
	box-shadow: 0 0 0 4px var(--ad-accent-light);
	transform: translateY(-1px);
	transition: box-shadow var(--ad-transition), transform var(--ad-transition);
}

/* ══════════════════════════ sign-verification-form demo ═══════════════════════
   Components for the "Sign a Monthly Verification Form (M-FVF)" demo: a small
   review-summary card (what you're signing), a responsible-supervisor picker
   (reuses .ad-select), the app's signature pad (Draw / Type / Upload tabs + a
   fixed-height pad + attestation + Sign Form). When SIGNED, the pad + signature
   + "Save" row stay, and the controls above/below the pad swap in place for a
   compact "Signed" header + a counter-sign waiting line. Faithful to
   app/views/verification/_signature-pad.php and reports/list.php. CONSTANT
   HEIGHT: the pad is a fixed box and each control swap is confined to its slot's
   box, so nothing expands the form mid-animation (the user-guide height-fit
   stays exact). App tokens only. */

/* Review summary: the month + M-FVF badge + the headline totals being attested. */
.abaft-demo .ad-vf-summary {
	background: var(--ad-bg-secondary); border: 1px solid var(--ad-border);
	border-radius: var(--ad-radius-lg); padding: 0.9rem 1rem; margin-bottom: 1.1rem;
}
.abaft-demo .ad-vf-summary-head {
	display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.7rem;
}
.abaft-demo .ad-vf-summary-title { font-size: 0.9rem; font-weight: 700; color: var(--ad-text-primary); }
.abaft-demo .ad-badge {
	display: inline-flex; align-items: center;
	padding: 0.12rem 0.5rem; border-radius: var(--ad-radius-full);
	font-size: 0.66rem; font-weight: 700; letter-spacing: 0.03em;
	background: var(--ad-purple-50); color: var(--ad-accent);
}
.abaft-demo .ad-vf-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; }
.abaft-demo .ad-vf-stat { text-align: left; }
.abaft-demo .ad-vf-stat-v { font-size: 1.02rem; font-weight: 700; color: var(--ad-text-primary); font-variant-numeric: tabular-nums; }
.abaft-demo .ad-vf-stat-v.is-green { color: var(--ad-green-600); }
.abaft-demo .ad-vf-stat-l { font-size: 0.68rem; font-weight: 600; color: var(--ad-text-tertiary); letter-spacing: 0.01em; }

/* ─────────────────────────── signature pad ────────────────────────────────── */
.abaft-demo .ad-sig-tabs { display: flex; gap: 0.4rem; margin-bottom: 0.6rem; }
.abaft-demo .ad-sig-tab {
	border: 1px solid var(--ad-border); background: var(--ad-bg-primary);
	color: var(--ad-text-secondary); border-radius: 8px;
	padding: 0.3rem 0.75rem; font-weight: 600; font-size: 0.76rem; line-height: 1.3;
	transition: all var(--ad-transition);
}
.abaft-demo .ad-sig-tab.is-active { background: var(--ad-purple-500); border-color: var(--ad-purple-500); color: #fff; }

/* Typed-name input (revealed only in the Type tab). */
.abaft-demo .ad-sig-typed { display: none; margin-bottom: 0.55rem; }
.abaft-demo .ad-sig-typed.is-shown { display: block; }
.abaft-demo .ad-sig-typed-input {
	width: 100%; box-sizing: border-box;
	padding: 0.5rem 0.75rem; font-family: inherit; font-size: 0.85rem;
	color: var(--ad-text-primary); background: var(--ad-bg-input);
	border: 1.5px solid var(--ad-border); border-radius: var(--ad-radius-md);
	line-height: 1.2; min-height: 2.3rem;
}
.abaft-demo .ad-sig-typed-input.is-placeholder { color: var(--ad-text-tertiary); }
.abaft-demo .ad-sig-typed-input.is-focus {
	border-color: var(--ad-accent);
	box-shadow: 0 0 0 3px var(--ad-accent-light);
}

/* Top slot: the Draw/Type/Upload tabs + typed input live here while signing; in
   the signed state a compact "Signed" header takes their place. Both layers
   share the same box (the controls define its height), so the flow height is
   IDENTICAL in every state — the height-fit reserve stays exact, nothing clips. */
.abaft-demo .ad-sig-topslot,
.abaft-demo .ad-sig-botslot { position: relative; }
.abaft-demo .ad-sig-controls { transition: opacity var(--ad-transition); }
.abaft-demo .ad-sig-signedhead {
	position: absolute; inset: 0; z-index: 2;
	display: flex; align-items: center; gap: 0.45rem;
	opacity: 0; pointer-events: none; transition: opacity var(--ad-transition);
}
.abaft-demo .ad-sig-signedhead-check {
	width: 20px; height: 20px; flex-shrink: 0; border-radius: 50%;
	background: var(--ad-green-500); color: #fff;
	display: inline-flex; align-items: center; justify-content: center;
}
.abaft-demo .ad-sig-signedhead-check svg { width: 12px; height: 12px; }
.abaft-demo .ad-sig-signedhead-t { font-size: 0.95rem; font-weight: 700; color: var(--ad-text-primary); }

/* The pad: a fixed-height dashed canvas area. A "Clear" chip sits top-right and
   a faint prompt sits centered until the signature is drawn. */
.abaft-demo .ad-sig-pad {
	position: relative;
	height: 118px;
	background: #fff;
	border: 1.5px dashed var(--ad-border);
	border-radius: var(--ad-radius-md);
	overflow: hidden;
}
.abaft-demo .ad-sig-clear {
	position: absolute; top: 0.45rem; right: 0.45rem; z-index: 2;
	background: var(--ad-bg-secondary); color: var(--ad-text-secondary);
	border-radius: var(--ad-radius-sm); padding: 0.18rem 0.55rem;
	font-size: 0.66rem; font-weight: 600;
}
/* A small green "signed" mark on the pad in the signed state (ink stays drawn).
   Sits bottom-right so it never covers the signature. */
.abaft-demo .ad-sig-signedmark {
	position: absolute; bottom: 0.5rem; right: 0.55rem; z-index: 2;
	width: 22px; height: 22px; border-radius: 50%;
	background: var(--ad-green-500); color: #fff;
	display: inline-flex; align-items: center; justify-content: center;
	opacity: 0; transform: scale(0.6); transition: opacity var(--ad-transition), transform var(--ad-transition);
}
.abaft-demo .ad-sig-signedmark svg { width: 13px; height: 13px; }
.abaft-demo .ad-sig-prompt {
	position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
	color: var(--ad-text-tertiary); font-size: 0.78rem; font-style: italic;
	transition: opacity var(--ad-transition);
}
.abaft-demo .ad-sig-pad.is-drawn .ad-sig-prompt { opacity: 0; }

/* The signature ink: a cursive name that "wipes in" left-to-right via a clip
   driven by --ad-sign-p (0 -> 1). Ink color matches the app's #1d1d6b. */
/* Typed signature ink.
   FONT NOTE: the app renders the typed signature to a canvas with
   `italic 52px "Segoe Script", "Brush Script MT", "Snell Roundhand", cursive`,
   so this mirrors that stack — but it must NOT bottom out at generic `cursive`.
   On Linux and Android none of those three exist and `cursive` resolves to a
   face whose `d` ascender is barely taller than an `a`, so at demo scale
   "Dana Whitfield" reads as "Dana Whitfiela". Named script faces still win
   where they exist; everything else lands on a self-hosted / ubiquitous italic
   serif with unambiguous letterforms. Slightly larger with a little tracking so
   ascenders survive the overlay's downscale. */
.abaft-demo .ad-sig-ink {
	position: absolute; left: 1rem; top: 50%; transform: translateY(-46%);
	font-family: 'Segoe Script', 'Brush Script MT', 'Snell Roundhand',
	             'Apple Chancery', 'Newsreader', Georgia, 'Times New Roman', serif;
	font-style: italic; font-size: 2.2rem; line-height: 1.15; letter-spacing: 0.01em;
	color: #1d1d6b;
	white-space: nowrap; pointer-events: none;
	opacity: 0;
	clip-path: inset(0 100% 0 0);
}
.abaft-demo .ad-sig-ink.is-drawn {
	opacity: 1;
	clip-path: inset(0 calc((1 - var(--ad-sign-p, 1)) * 100%) 0 0);
}

/* "Save as my signature" row + the attestation line + the Sign Form button. */
.abaft-demo .ad-sig-save {
	display: flex; align-items: center; gap: 0.45rem;
	margin: 0.6rem 0 0; font-size: 0.72rem; color: var(--ad-text-secondary);
}
.abaft-demo .ad-sig-check {
	width: 15px; height: 15px; flex-shrink: 0;
	border: 1.5px solid var(--ad-border); border-radius: 4px; background: var(--ad-bg-input);
	display: inline-flex; align-items: center; justify-content: center;
	transition: all var(--ad-transition);
}
.abaft-demo .ad-sig-check svg { width: 11px; height: 11px; color: #fff; opacity: 0; }
.abaft-demo .ad-sig-save.is-on .ad-sig-check { background: var(--ad-accent); border-color: var(--ad-accent); }
.abaft-demo .ad-sig-save.is-on .ad-sig-check svg { opacity: 1; }
.abaft-demo .ad-sig-attest {
	margin: 0.6rem 0 0.85rem; font-size: 0.68rem; line-height: 1.45; color: var(--ad-text-tertiary);
}

/* Bottom slot: the attestation + Sign Form button live here while signing; in
   the signed state a "waiting on the supervisor to counter-sign" line takes
   their place, in the same box (constant height). */
.abaft-demo .ad-sig-waiting {
	position: absolute; inset: 0; z-index: 2;
	display: flex; align-items: center;
	margin: 0; font-size: 0.72rem; line-height: 1.45; color: var(--ad-text-secondary);
	opacity: 0; pointer-events: none; transition: opacity var(--ad-transition);
}

/* ── SIGNED state ─────────────────────────────────────────────────────────────
   The completed form: keep the pad + its signature + the "Save" row visible,
   swap the tab controls for the "Signed" header and the attest+button for the
   counter-sign waiting line. Each swap happens within its slot's fixed box, so
   the demo height is unchanged (the height-fit reserve is exact — no clip). */
.abaft-demo .ad-sig-body.is-signed .ad-sig-controls { opacity: 0; visibility: hidden; }
.abaft-demo .ad-sig-body.is-signed .ad-sig-signedhead,
.abaft-demo .ad-sig-body.is-signed .ad-sig-waiting { opacity: 1; }
.abaft-demo .ad-sig-body.is-signed .ad-sig-signedmark { opacity: 1; transform: scale(1); }
/* The signed pad reads as accepted: soften the dashed border to a solid green. */
.abaft-demo .ad-sig-body.is-signed .ad-sig-pad {
	border-style: solid; border-color: var(--ad-green-500);
}
.abaft-demo .ad-sig-body.is-signed .ad-sig-clear { display: none; }

/* ══════════════════════════ import-month demo ════════════════════════════════
   Components for the "Import a past month (aggregate month summary)" demo:
   faithful to app/views/import/index.php (fieldwork context). It reuses the
   shared form primitives (.ad-select, .ad-input, .ad-row, .ad-allotment, the
   h/m boxes) and adds only: the "When"/"Where" section labels are plain
   .ad-label, the month-total counter reuses .ad-remaining, and a CONSTANT-HEIGHT
   action slot whose Save/Cancel row swaps for an "added to your total"
   confirmation in place (same box), so the final state fills the space with no
   clip and no empty gap. App tokens only. */

/* One fixed slot holding either the Save/Cancel actions (while entering) or the
   "month added" confirmation (once saved). Both layers share the box (the
   actions define its height), so the form height is IDENTICAL in every state —
   the height-fit reserve stays exact, nothing clips. */
.abaft-demo .ad-imp-actionslot { position: relative; }
.abaft-demo .ad-imp-controls { transition: opacity var(--ad-transition); }
.abaft-demo .ad-imp-added {
	position: absolute; inset: 0; z-index: 2;
	display: flex; align-items: center; gap: 0.55rem;
	padding: 0.7rem 0.85rem;
	background: var(--ad-green-50); border: 1px solid var(--ad-green-500);
	border-radius: var(--ad-radius-md);
	opacity: 0; pointer-events: none; transition: opacity var(--ad-transition);
}
.abaft-demo .ad-imp-added-check {
	width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%;
	background: var(--ad-green-500); color: #fff;
	display: inline-flex; align-items: center; justify-content: center;
}
.abaft-demo .ad-imp-added-check svg { width: 13px; height: 13px; }
.abaft-demo .ad-imp-added-text { font-size: 0.8rem; line-height: 1.35; color: var(--ad-green-700); }
.abaft-demo .ad-imp-added-text strong { color: var(--ad-green-700); font-weight: 700; font-variant-numeric: tabular-nums; }

/* ADDED state: the confirmation takes over the slot; the actions fade out. Each
   swap is confined to the slot's box, so the demo height is unchanged (no clip,
   no gap). The month total in the allotment head reads as its final value. */
.abaft-demo .ad-imp-body.is-added .ad-imp-controls { opacity: 0; visibility: hidden; }
.abaft-demo .ad-imp-body.is-added .ad-imp-added { opacity: 1; }

/* ══════════════════════════ log-rbt-session demo ═════════════════════════════
   Components for the "Log an RBT service session (the RBT day form)" demo:
   faithful to app/views/rbt/log.php. It reuses the shared form primitives
   (.ad-select, .ad-time, .ad-textarea, .ad-toggle, .ad-actions) and adds the
   RBT-specific bits: a purple-accented session "slot" card with a Session chip +
   a green Supervised chip + a live duration, an Individual/Group format segment,
   and a CONSTANT-HEIGHT action slot whose Save Entry row swaps for a "saved for
   the day" confirmation in place (same box), so the final state fills the space
   with no clip and no empty gap. NO restricted/unrestricted allotment split
   (that is fieldwork, not RBT). App tokens only. */

/* The session slot card: left purple accent + a purple-tinted head. */
.abaft-demo .ad-rbt-slot {
	border: 1px solid var(--ad-border);
	border-left: 3px solid var(--ad-purple-600);
	border-radius: var(--ad-radius-md);
	overflow: hidden; background: var(--ad-bg-primary);
	margin-bottom: 0.6rem;
}
.abaft-demo .ad-rbt-slot-head {
	display: flex; align-items: center; gap: 0.5rem;
	padding: 0.4rem 0.75rem; background: var(--ad-purple-50);
}
.abaft-demo .ad-rbt-chip {
	display: inline-flex; align-items: center;
	padding: 0.15rem 0.6rem; border-radius: var(--ad-radius-full);
	font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
	background: var(--ad-purple-50); color: var(--ad-purple-700);
	border: 1px solid var(--ad-purple-400);
}
/* The green "Supervised" chip is hidden until the session is marked supervised. */
.abaft-demo .ad-rbt-chip-sup {
	display: none;
	background: var(--ad-green-50); color: var(--ad-green-700);
	border-color: var(--ad-green-500);
}
.abaft-demo .ad-rbt-slot.is-supervised .ad-rbt-chip-sup { display: inline-flex; }
.abaft-demo .ad-rbt-dur {
	margin-left: auto; font-size: 0.78rem; font-weight: 600;
	color: var(--ad-text-secondary); font-variant-numeric: tabular-nums;
}
.abaft-demo .ad-rbt-slot-body { padding: 0.7rem 0.75rem 0.75rem; }
.abaft-demo .ad-rbt-slot-row {
	display: flex; gap: 0.6rem; align-items: flex-end; flex-wrap: wrap;
}
.abaft-demo .ad-rbt-slot-row .ad-form-group { margin-bottom: 0; }
.abaft-demo .ad-rbt-slot-row .ad-time { min-width: 8.5rem; }
.abaft-demo .ad-rbt-sup-field { flex: 1 1 11rem; min-width: 10rem; }

/* The Supervised toggle sits inline; the Supervised sub-row (format + observation
   + note) reveals when the session is marked supervised. */
.abaft-demo .ad-rbt-extra {
	display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center;
	margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px dashed var(--ad-border);
}
.abaft-demo .ad-rbt-extra .ad-toggle { flex: 0 0 auto; }
/* The Supervised/Observation toggles wear the supervision green when on. */
.abaft-demo .ad-rbt-supervised.is-on,
.abaft-demo .ad-rbt-obs.is-on {
	border-color: var(--ad-green-500); background: var(--ad-green-50); color: var(--ad-green-700);
}
.abaft-demo .ad-rbt-supervised.is-on svg,
.abaft-demo .ad-rbt-obs.is-on svg { opacity: 1; }

/* The revealed sub-row: hidden until the session is supervised. */
.abaft-demo .ad-rbt-suprow {
	display: none; flex: 1 1 100%; flex-wrap: wrap; gap: 0.5rem; align-items: center;
}
.abaft-demo .ad-rbt-suprow.is-shown { display: flex; }

/* Individual / Group format segment (solid input bg, green active pill). */
.abaft-demo .ad-rbt-seg {
	display: inline-flex; flex: 0 0 auto;
	border: 1px solid var(--ad-border); border-radius: 9px;
	overflow: hidden; background: var(--ad-bg-input);
}
.abaft-demo .ad-rbt-seg-btn {
	padding: 0.45rem 0.9rem; font-size: 0.78rem; color: var(--ad-text-secondary); line-height: 1;
}
.abaft-demo .ad-rbt-seg-btn.is-active { background: var(--ad-green-600); color: #fff; font-weight: 600; }

/* Per-contact supervision note: full width under the format/observation row. */
.abaft-demo .ad-rbt-note-wrap { flex: 1 1 100%; }
.abaft-demo .ad-rbt-note-wrap .ad-label { margin-bottom: 0.25rem; }

/* One fixed action slot: the Save Entry row (while entering) or the "saved for
   the day" confirmation (once saved). Both layers share the box (the actions
   define its height), so the form height is IDENTICAL in every state — the
   height-fit reserve stays exact, nothing clips. Mirrors .ad-imp-actionslot. */
.abaft-demo .ad-rbt-actionslot { position: relative; margin-top: 0.4rem; }
.abaft-demo .ad-rbt-controls { transition: opacity var(--ad-transition); }
.abaft-demo .ad-rbt-saved {
	position: absolute; inset: 0; z-index: 2;
	display: flex; align-items: center; gap: 0.55rem;
	padding: 0.7rem 0.85rem;
	background: var(--ad-green-50); border: 1px solid var(--ad-green-500);
	border-radius: var(--ad-radius-md);
	opacity: 0; pointer-events: none; transition: opacity var(--ad-transition);
}
.abaft-demo .ad-rbt-saved-check {
	width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%;
	background: var(--ad-green-500); color: #fff;
	display: inline-flex; align-items: center; justify-content: center;
}
.abaft-demo .ad-rbt-saved-check svg { width: 13px; height: 13px; }
.abaft-demo .ad-rbt-saved-text { font-size: 0.8rem; line-height: 1.35; color: var(--ad-green-700); font-weight: 600; }

/* SAVED state: the confirmation takes over the slot; the actions fade out. Each
   swap is confined to the slot's box, so the demo height is unchanged. */
.abaft-demo .ad-rbt-body.is-saved .ad-rbt-controls { opacity: 0; visibility: hidden; }
.abaft-demo .ad-rbt-body.is-saved .ad-rbt-saved { opacity: 1; }

/* ─────────────────────── typing caret + focus emphasis ────────────────────── */
.abaft-demo .ad-caret::after {
	content: '';
	display: inline-block; width: 1.5px; height: 1em;
	margin-left: 1px; vertical-align: text-bottom;
	background: var(--ad-accent); animation: ad-blink 900ms steps(1) infinite;
}
@keyframes ad-blink { 50% { opacity: 0; } }

/* ─────────────────────────────── responsive ───────────────────────────────── */
@media (max-width: 640px) {
	.abaft-demo .ad-row.three,
	.abaft-demo .ad-row.two { grid-template-columns: 1fr; }
	.abaft-demo .ad-obs-row.is-shown { grid-template-columns: 1fr; }
	.abaft-demo-stage { padding: 12px; }
	.abaft-demo .ad-modal-body { padding: 1rem; }
	.abaft-demo .ad-hm-box { width: 2.5rem; }
	/* RBT slot: stack the time pickers + supervisor full width on phones. */
	.abaft-demo .ad-rbt-slot-row { gap: 0.5rem; }
	.abaft-demo .ad-rbt-sup-field { flex-basis: 100%; }
}

/* ────────────────────── reduced motion / no-JS fallback ───────────────────── */
/* With no JS, the player never runs: the server-rendered FINAL state (below)
   is exactly what the crawler and the reduced-motion user see. The caret and
   replay are JS-only affordances, so they simply never appear. */
@media (prefers-reduced-motion: reduce) {
	.abaft-demo .ad-caret::after { animation: none; display: none; }
	.abaft-demo .ad-btn-primary.is-highlight { transition: none; }
	/* Sign demo: the server-rendered FINAL state is the signed form, so the ink
	   shows fully and the "Signed" header + waiting line are what the crawler /
	   reduced-motion user sees. No wipe or fade animation. */
	.abaft-demo .ad-sig-ink { clip-path: none; }
	.abaft-demo .ad-sig-controls,
	.abaft-demo .ad-sig-signedhead,
	.abaft-demo .ad-sig-waiting,
	.abaft-demo .ad-sig-signedmark,
	.abaft-demo .ad-sig-btn.is-highlight { transition: none; }
	/* Import demo: the server-rendered FINAL state is the added month, so the
	   "added to your total" confirmation is what the crawler / reduced-motion
	   user sees, with no fade. */
	.abaft-demo .ad-imp-controls,
	.abaft-demo .ad-imp-added { transition: none; }
	/* RBT demo: the server-rendered FINAL state is the saved supervised session,
	   so the "saved for the day" confirmation is what the crawler / reduced-motion
	   user sees, with no fade. */
	.abaft-demo .ad-rbt-controls,
	.abaft-demo .ad-rbt-saved { transition: none; }
}

/* ============================================================
   ONBOARDING template (.ad-ob) — step one of first-run setup.
   Radio-card option groups plus two progressive-reveal blocks
   (the fieldwork configuration, then the resolved requirements).
   `.ad-ob-reveal` is server-rendered SHOWN so the crawlable and
   reduced-motion fallback is the finished, configured state; the
   player hides it on reset and reveals it during playback.
   ============================================================ */
.abaft-demo .ad-ob {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.abaft-demo .ad-ob-sec {
  padding: 0.85rem 0.9rem 0.9rem;
  background: #fff;
  border: 1px solid var(--ad-border);
  border-radius: 12px;
}
.abaft-demo .ad-ob-sec-head {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-bottom: 0.75rem;
}
.abaft-demo .ad-ob-sec-icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--ad-accent);
  color: #fff;
}
.abaft-demo .ad-ob-sec-icon svg { width: 15px; height: 15px; }
.abaft-demo .ad-ob-sec-t {
  display: block;
  font-weight: 700;
  font-size: 0.86rem;
  line-height: 1.3;
  color: var(--ad-text-primary);
}
.abaft-demo .ad-ob-sec-s {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--ad-text-tertiary);
}

.abaft-demo .ad-ob-lbl {
  display: block;
  margin: 0.7rem 0 0.4rem;
  font-weight: 600;
  font-size: 0.72rem;
  color: var(--ad-text-secondary);
}
.abaft-demo .ad-ob-sec > .ad-ob-lbl:first-of-type { margin-top: 0; }

.abaft-demo .ad-ob-opts {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.abaft-demo .ad-ob-opts--two {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.45rem;
}
.abaft-demo .ad-ob-opt {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.6rem 0.7rem;
  border: 1.5px solid var(--ad-border);
  border-radius: 10px;
  background: #fff;
  transition: border-color 0.18s ease, background 0.18s ease;
}
.abaft-demo .ad-ob-opt.is-sel {
  border-color: var(--ad-accent);
  background: var(--ad-accent-light);
}
.abaft-demo .ad-ob-radio {
  flex: none;
  margin-top: 0.12rem;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  border: 1.5px solid var(--ad-gray-300);
  background: #fff;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.abaft-demo .ad-ob-opt.is-sel .ad-ob-radio {
  border-color: var(--ad-accent);
  box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 8px var(--ad-accent);
}
.abaft-demo .ad-ob-opt-body { min-width: 0; }
.abaft-demo .ad-ob-opt-t {
  display: block;
  font-weight: 600;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--ad-text-primary);
}
.abaft-demo .ad-ob-opt-s {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.68rem;
  line-height: 1.4;
  color: var(--ad-text-tertiary);
}
.abaft-demo .ad-ob-opt-meta {
  display: block;
  margin-top: 0.25rem;
}
.abaft-demo .ad-ob-opt-meta span {
  display: block;
  font-size: 0.66rem;
  line-height: 1.5;
  color: var(--ad-text-tertiary);
}

/* Progressive reveal: collapsed to nothing until the player shows it. */
.abaft-demo .ad-ob-reveal {
  overflow: hidden;
  max-height: 0;
  margin: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-width: 0;
  opacity: 0;
  transition: max-height 0.34s ease, opacity 0.28s ease,
              padding 0.34s ease, border-width 0.34s ease;
}
.abaft-demo .ad-ob-reveal.is-shown {
  max-height: 640px;
  opacity: 1;
}
.abaft-demo .ad-ob-sec.ad-ob-reveal.is-shown {
  padding-top: 0.85rem;
  padding-bottom: 0.9rem;
  border-width: 1px;
}
.abaft-demo .ad-ob-req.ad-ob-reveal.is-shown {
  margin-top: 0.75rem;
  padding: 0.7rem 0.8rem 0.75rem;
  border-width: 1px;
}

.abaft-demo .ad-ob-req {
  background: var(--ad-bg-secondary);
  border: 1px solid var(--ad-border);
  border-radius: 10px;
}
.abaft-demo .ad-ob-req-t {
  display: block;
  margin-bottom: 0.45rem;
  font-weight: 700;
  font-size: 0.76rem;
  color: var(--ad-text-primary);
}
.abaft-demo .ad-ob-req-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.28rem 0.9rem;
}
.abaft-demo .ad-ob-req-k {
  font-size: 0.7rem;
  color: var(--ad-text-tertiary);
}
.abaft-demo .ad-ob-req-v {
  font-size: 0.7rem;
  font-weight: 600;
  text-align: right;
  color: var(--ad-text-secondary);
}

@media (max-width: 560px) {
  .abaft-demo .ad-ob-opts--two { grid-template-columns: 1fr; }
}

/* ============================================================
   INVITE template (.ad-inv) — the supervisor's Invite Trainee
   dialog. The Send Invitation button and the "invitation sent"
   confirmation share ONE fixed slot (.ad-inv-actionslot), so the
   confirmed state fills exactly the space the button occupied:
   constant height, nothing clips. Mirrors .ad-imp-actionslot.
   ============================================================ */
.abaft-demo .ad-inv-tabs {
  display: inline-flex;
  gap: 0.25rem;
  margin-bottom: 0.85rem;
  border-bottom: 1px solid var(--ad-border);
}
.abaft-demo .ad-inv-tab {
  padding: 0.4rem 0.75rem 0.5rem;
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--ad-text-tertiary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.abaft-demo .ad-inv-tab.is-active {
  color: var(--ad-accent);
  border-bottom-color: var(--ad-accent);
}
.abaft-demo .ad-inv-note {
  margin: 0 0 0.9rem;
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--ad-text-secondary);
}
.abaft-demo .ad-inv-btn {
  width: 100%;
  justify-content: center;
}

.abaft-demo .ad-inv-actionslot { position: relative; margin-top: 0.9rem; }
.abaft-demo .ad-inv-controls { transition: opacity var(--ad-transition); }
.abaft-demo .ad-inv-sent {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  padding: 0.6rem 0.8rem;
  background: var(--ad-green-50);
  border: 1px solid var(--ad-green-500);
  border-radius: var(--ad-radius-md);
  opacity: 0; pointer-events: none;
  transition: opacity var(--ad-transition);
}
.abaft-demo .ad-inv-sent-check {
  width: 20px; height: 20px; flex-shrink: 0; border-radius: 50%;
  background: var(--ad-green-500); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
}
.abaft-demo .ad-inv-sent-check svg { width: 12px; height: 12px; }
.abaft-demo .ad-inv-sent-text {
  font-size: 0.78rem; line-height: 1.35; color: var(--ad-green-700); font-weight: 600;
}
.abaft-demo .ad-inv-actionslot.is-sent .ad-inv-controls { opacity: 0; }
.abaft-demo .ad-inv-actionslot.is-sent .ad-inv-sent { opacity: 1; }
