/**
 * RMS by Anija · front-end staff app (theme-independent).
 *
 * Everything is scoped under .ascapp (the <body> class) so it never collides
 * with a WordPress theme. Every colour flows through a token, so light and dark
 * need no per-component work.
 *
 * THEMING — three states, chosen with the toggle in the top bar:
 *   "Match device"  no data-asc-theme attribute -> the light tokens below, with
 *                   the dark ones applied by the prefers-color-scheme block.
 *   "Light"         <html data-asc-theme="light"> -> the media block is opted out
 *                   of by :not([data-asc-theme="light"]), so light always wins.
 *   "Dark"          <html data-asc-theme="dark">  -> the explicit dark block
 *                   applies whatever the device is set to.
 * The attribute is written on <html> by a tiny script in <head> (see
 * asc_app_head) so the correct palette is in place before the first paint.
 *
 * The dark palette is deliberately written out twice (once in the media query,
 * once for the explicit attribute) because CSS cannot share a declaration block
 * across a media boundary. KEEP THE TWO BLOCKS IN SYNC.
 */

/* ---------------------------------------------------------------------
 * 1. Design tokens — light (the base palette)
 * ------------------------------------------------------------------- */

.ascapp {
	color-scheme: light;
	/* Brand */
	--brand: #4f46e5;
	--brand-strong: #4338ca;
	--brand-ink: #ffffff;
	--brand-soft: #eef2ff;
	--brand-soft-ink: #3730a3;
	--ring: rgba(79, 70, 229, 0.28);

	/* Surfaces */
	--bg: #f6f7fb;
	--bg-tint: radial-gradient(1200px 520px at 12% -12%, rgba(79, 70, 229, 0.10), transparent 62%),
	           radial-gradient(900px 460px at 92% -6%, rgba(14, 165, 233, 0.08), transparent 60%);
	--card: #ffffff;
	--card-2: #fbfcfe;
	--overlay: rgba(255, 255, 255, 0.82);

	/* Text */
	--ink: #0f172a;
	--ink-2: #334155;
	--muted: #64748b;

	/* Lines */
	--border: #e4e8ef;
	--border-soft: #eef1f6;
	--field-border: #cbd5e1;

	/* Status hues */
	--ok: #059669;      --ok-bg: #ecfdf5;   --ok-border: #a7f3d0;   --ok-ink: #065f46;
	--warn: #d97706;    --warn-bg: #fffbeb; --warn-border: #fde68a; --warn-ink: #92400e;
	--err: #dc2626;     --err-bg: #fef2f2;  --err-border: #fecaca;  --err-ink: #991b1b;
	--info: #2563eb;
	--violet: #7c3aed;
	--slate: #64748b;

	/* Elevation */
	--sh-1: 0 1px 2px rgba(15, 23, 42, 0.05);
	--sh-2: 0 4px 16px -6px rgba(15, 23, 42, 0.16);
	--sh-3: 0 18px 44px -20px rgba(15, 23, 42, 0.32);

	/* Shape + motion */
	--r-sm: 8px;
	--r: 12px;
	--r-lg: 16px;
	--r-xl: 22px;
	--t: 140ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------------------------------------------------------------------
 * 2a. Design tokens — dark, applied when the DEVICE asks for dark and the user
 *     has not explicitly chosen Light.
 * ------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
	html:not([data-asc-theme="light"]) .ascapp {
		--brand: #818cf8;
		--brand-strong: #6366f1;
		--brand-ink: #0b1020;
		--brand-soft: rgba(129, 140, 248, 0.14);
		--brand-soft-ink: #c7d2fe;
		--ring: rgba(129, 140, 248, 0.35);

		--bg: #0b1020;
		--bg-tint: radial-gradient(1200px 520px at 12% -12%, rgba(99, 102, 241, 0.20), transparent 62%),
		           radial-gradient(900px 460px at 92% -6%, rgba(14, 165, 233, 0.12), transparent 60%);
		--card: #141a2e;
		--card-2: #182038;
		--overlay: rgba(20, 26, 46, 0.82);

		--ink: #eef2ff;
		--ink-2: #c7d0e4;
		--muted: #93a0bd;

		--border: #26304c;
		--border-soft: #202942;
		--field-border: #35406186;

		--ok: #34d399;   --ok-bg: rgba(16, 185, 129, 0.14);  --ok-border: rgba(52, 211, 153, 0.38);  --ok-ink: #a7f3d0;
		--warn: #fbbf24; --warn-bg: rgba(245, 158, 11, 0.14); --warn-border: rgba(251, 191, 36, 0.38); --warn-ink: #fde68a;
		--err: #f87171;  --err-bg: rgba(239, 68, 68, 0.14);   --err-border: rgba(248, 113, 113, 0.38); --err-ink: #fecaca;
		--info: #60a5fa;
		--violet: #a78bfa;
		--slate: #94a3b8;

		--sh-1: 0 1px 2px rgba(0, 0, 0, 0.45);
		--sh-2: 0 6px 20px -8px rgba(0, 0, 0, 0.65);
		--sh-3: 0 22px 52px -22px rgba(0, 0, 0, 0.85);

		color-scheme: dark;
	}
}

/* ---------------------------------------------------------------------
 * 2b. Design tokens — dark, chosen explicitly by the user. Identical to 2a;
 *     keep the two blocks in sync (CSS can't share one across a media query).
 * ------------------------------------------------------------------- */

html[data-asc-theme="dark"] .ascapp {
	--brand: #818cf8;
	--brand-strong: #6366f1;
	--brand-ink: #0b1020;
	--brand-soft: rgba(129, 140, 248, 0.14);
	--brand-soft-ink: #c7d2fe;
	--ring: rgba(129, 140, 248, 0.35);

	--bg: #0b1020;
	--bg-tint: radial-gradient(1200px 520px at 12% -12%, rgba(99, 102, 241, 0.20), transparent 62%),
	           radial-gradient(900px 460px at 92% -6%, rgba(14, 165, 233, 0.12), transparent 60%);
	--card: #141a2e;
	--card-2: #182038;
	--overlay: rgba(20, 26, 46, 0.82);

	--ink: #eef2ff;
	--ink-2: #c7d0e4;
	--muted: #93a0bd;

	--border: #26304c;
	--border-soft: #202942;
	--field-border: #35406186;

	--ok: #34d399;   --ok-bg: rgba(16, 185, 129, 0.14);  --ok-border: rgba(52, 211, 153, 0.38);  --ok-ink: #a7f3d0;
	--warn: #fbbf24; --warn-bg: rgba(245, 158, 11, 0.14); --warn-border: rgba(251, 191, 36, 0.38); --warn-ink: #fde68a;
	--err: #f87171;  --err-bg: rgba(239, 68, 68, 0.14);   --err-border: rgba(248, 113, 113, 0.38); --err-ink: #fecaca;
	--info: #60a5fa;
	--violet: #a78bfa;
	--slate: #94a3b8;

	--sh-1: 0 1px 2px rgba(0, 0, 0, 0.45);
	--sh-2: 0 6px 20px -8px rgba(0, 0, 0, 0.65);
	--sh-3: 0 22px 52px -22px rgba(0, 0, 0, 0.85);

	color-scheme: dark;
}

/* ---------------------------------------------------------------------
 * 3. Base
 * ------------------------------------------------------------------- */

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

.ascapp {
	margin: 0;
	min-height: 100vh;
	background-color: var(--bg);
	background-image: var(--bg-tint);
	background-repeat: no-repeat;
	background-attachment: fixed;
	color: var(--ink);
	font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Noto Sans", sans-serif;
	font-size: 15px;
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

.ascapp :focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
	border-radius: 6px;
}

/* ---------------------------------------------------------------------
 * 4. Top bar
 * ------------------------------------------------------------------- */

/* Two stacked rows, not one line: identity and account on top, the section menu
   on its own bar underneath. The header keeps the background, the blur and the
   sticky behaviour so both rows travel together and a business's custom header
   colour paints the whole thing. */
.ascapp-bar {
	position: sticky;
	top: 0;
	z-index: 20;
	display: flex;
	flex-direction: column;
	padding: 0;
	background: var(--overlay);
	-webkit-backdrop-filter: saturate(180%) blur(14px);
	backdrop-filter: saturate(180%) blur(14px);
	border-bottom: 1px solid var(--border);
	box-shadow: var(--sh-1);
}

/* Row 1: brand · workspace toggle · account cluster. It wraps at every width —
   with the nav gone it rarely needs to, and when it does (a long business name
   on a phone) wrapping is better than squeezing the icon buttons. */
.ascapp-bar-top {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px 14px;
	padding: 11px 20px;
}

/* Row 2: the section menu. A hairline separates it from the row above — both
   rows share one background, so the line is what makes it read as a second bar
   rather than a taller first one. */
.ascapp-bar-nav {
	display: flex;
	align-items: center;
	/* v4.16.0: the menu is centred in its bar. It works with the sideways
	   scrolling below because .ascapp-nav is flex: 0 1 auto — it shrinks to its
	   content and is centred while it fits, and only grows to the full width
	   (where centring stops applying, and scrolling starts from the first item)
	   once it does not. justify-content: center on an OVERFLOWING flex row
	   clips the start unreachably in several browsers; sizing the child is what
	   avoids that. */
	justify-content: center;
	min-width: 0;
	padding: 5px 20px;
	border-top: 1px solid var(--border);
}

/* --- The menu button (v4.16.0) ---------------------------------------
   Hidden entirely on a desktop: above 860px the section bar has room to be a
   bar, and a hamburger there would hide a menu that was already visible.
   Every rule that COLLAPSES the menu is scoped to .asc-js, so with JavaScript
   off the bar stays open exactly as it was before this version. */
.ascapp-navtoggle { display: none; }

.ascapp-burger,
.ascapp-burger::before,
.ascapp-burger::after {
	display: block;
	width: 18px;
	height: 2px;
	border-radius: 2px;
	background: currentColor;
	transition: transform var(--t), opacity var(--t);
}
.ascapp-burger { position: relative; }
.ascapp-burger::before,
.ascapp-burger::after {
	content: "";
	position: absolute;
	left: 0;
}
.ascapp-burger::before { top: -6px; }
.ascapp-burger::after { top: 6px; }

/* Open: the three lines become a cross. Driven off aria-expanded rather than a
   second class, so the thing the screen reader is told and the thing the eye is
   shown cannot drift apart — there is only one source of truth. */
.ascapp-navtoggle[aria-expanded="true"] .ascapp-burger { background: transparent; }
.ascapp-navtoggle[aria-expanded="true"] .ascapp-burger::before { transform: translateY(6px) rotate(45deg); }
.ascapp-navtoggle[aria-expanded="true"] .ascapp-burger::after { transform: translateY(-6px) rotate(-45deg); }

.ascapp-brand {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
	gap: 9px;
	font-weight: 750;
	font-size: 16.5px;
	letter-spacing: -0.015em;
	color: var(--ink);
	text-decoration: none;
	white-space: nowrap;
}

/* A small brand mark so the bar reads as a product, not a page heading. */
.ascapp-brand::before {
	content: "";
	width: 26px;
	height: 26px;
	flex: 0 0 26px;
	border-radius: 9px;
	background: linear-gradient(135deg, var(--brand), var(--brand-strong));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 2px 8px -2px var(--ring);
}

.ascapp-brand span { color: var(--brand); }

/* The business's own logo, shown before its name. When one is present the
   gradient tile above is redundant, so it is switched off. These rules are also
   inlined by asc_app_chrome_css() so they survive a stale cached stylesheet. */
.ascapp-brand-mark {
	width: 26px;
	height: 26px;
	flex: 0 0 26px;
	border-radius: 8px;
	object-fit: cover;
	display: block;
	background: var(--card);
}
.ascapp-brand.has-mark::before { display: none; }

/* The top bar's icon buttons: notifications, customers, settings. They are the
   screens somebody opens a few times a day rather than works out of — the class
   name predates the other two and is kept so a stale cached stylesheet still
   styles all three. */
.ascapp-gear {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	border-radius: 10px;
	color: inherit;
	text-decoration: none;
	line-height: 0;
	transition: background var(--t), color var(--t);
}
.ascapp-gear:hover { background: var(--border-soft); color: var(--brand); }
.ascapp-gear.active { background: var(--brand-soft); color: var(--brand-soft-ink); }
/* flex:0 0 auto — the icon is a flex item and would otherwise be squeezed
   narrower than 18px whenever the top bar runs short of room. */
.ascapp-gear svg { width: 18px; height: 18px; flex: 0 0 auto; display: block; }

/* Settings hub (v5.20.2). One grid of cards: 1 column below 1200px (capped at
   760px so a tablet's list does not stretch), 2 to 1599px, 3 from 1600px. Each
   card is icon + title + at most two lines of description, 78px+ tall, the whole
   card one link. Hover and focus only change colour and shadow (140ms, the
   app's --t); nothing moves, so there is nothing for reduced motion to stop. */
.ascapp-hub {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
	gap: 14px;
	margin-top: 6px;
}
.ascapp-hub.is-all { grid-template-columns: minmax(0, 1fr); gap: 12px; max-width: 760px; }
@media (min-width: 1200px) {
	.ascapp-hub.is-all { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: none; }
}
@media (min-width: 1600px) {
	.ascapp-hub.is-all { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.ascapp-hub-card {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	column-gap: 14px;
	align-content: center;
	min-height: 78px;
	padding: 14px 16px;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--sh-1);
	text-decoration: none;
	color: inherit;
	transition: border-color var(--t), box-shadow var(--t), background-color var(--t);
}
.ascapp-hub-card:hover { border-color: var(--brand); box-shadow: var(--sh-2); }
.ascapp-hub-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.ascapp-hub-card .i {
	grid-row: 1 / span 2;
	align-self: center;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border-radius: 10px;
	background: var(--brand-soft);
	color: var(--brand);
}
.ascapp-hub-card .i svg { width: 20px; height: 20px; }
.ascapp-hub-card .t { grid-column: 2; display: block; font-weight: 700; font-size: 15px; line-height: 1.3; color: var(--ink); }
.ascapp-hub-card .d {
	grid-column: 2;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
	margin-top: 3px;
	font-size: 13px;
	color: var(--muted);
	line-height: 1.4;
}

/* One line, always. The menu has a full row to itself now, but a shop with every
   module on can still outrun a phone — so it scrolls sideways. It must never
   collapse into a vertical column, which is what a wrapping flex item does once
   its siblings squeeze it. */
.ascapp-nav {
	display: flex;
	/* 0 1 auto, not 1 1 auto: see the centring note on .ascapp-bar-nav. The nav
	   is as wide as its links until they no longer fit, at which point it takes
	   the width it is given and scrolls inside it. */
	flex: 0 1 auto;
	max-width: 100%;
	min-width: 0;
	gap: 2px;
	flex-wrap: nowrap;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
	margin-left: 0;
}
.ascapp-nav::-webkit-scrollbar { display: none; }
.ascapp-nav a { flex: 0 0 auto; white-space: nowrap; }

.ascapp-nav a {
	position: relative;
	padding: 7px 12px;
	border-radius: 9px;
	text-decoration: none;
	color: var(--muted);
	font-weight: 600;
	font-size: 14px;
	transition: color var(--t), background var(--t);
}

.ascapp-nav a:hover { background: var(--border-soft); color: var(--ink); }
.ascapp-nav a.active { background: var(--brand-soft); color: var(--brand-soft-ink); }

/* Dashboard is a house rather than a word — the one entry whose icon everybody
   already reads. Its name is in title + aria-label, so it is a hover away on a
   desktop and announced properly to a screen reader. */
.ascapp-nav a.icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 7px 11px;
	line-height: 0;
}
.ascapp-nav a.icon svg { width: 18px; height: 18px; flex: 0 0 auto; display: block; }

.ascapp-user {
	margin-left: auto;
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	gap: 10px;
	font-size: 14px;
	color: var(--muted);
	white-space: nowrap;
}

.ascapp-user a {
	color: var(--ink-2);
	text-decoration: none;
	font-weight: 600;
	padding: 6px 10px;
	border-radius: 8px;
	transition: background var(--t), color var(--t);
}
.ascapp-user a:hover { background: var(--border-soft); color: var(--ink); }

/* "Good evening, {name}" can run long — never let it push Log out or the
   appearance switch off the bar. */
.ascapp-hello {
	max-width: 30ch;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* ---- Theme toggle (Match device / Light / Dark) ---- */

/* Compact cycling button that lives in the top bar and on the login card. */
.ascapp-theme-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 1px solid var(--border);
	border-radius: 10px;
	background: var(--card);
	color: var(--muted);
	cursor: pointer;
	line-height: 0;
	box-shadow: var(--sh-1);
	transition: color var(--t), border-color var(--t), background var(--t), transform var(--t);
}
.ascapp-theme-btn:hover { color: var(--brand); border-color: var(--brand); }
.ascapp-theme-btn:active { transform: scale(0.94); }
.ascapp-theme-btn svg { width: 18px; height: 18px; display: block; }

/* The labelled switch on the My account page — same segmented idiom as the
   Service Center / Warranty toggle, so the app has one way of showing a choice.
   These rules are mirrored inline by asc_app_theme_css() so a stale cached copy
   of this file can never leave the control unstyled. */
.ascapp-theme-seg {
	display: inline-flex;
	gap: 4px;
	padding: 4px;
	border: 1px solid var(--border);
	border-radius: 12px;
	background: var(--border-soft);
}
.ascapp-theme-choice {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 9px 14px;
	border: 0;
	border-radius: 9px;
	background: transparent;
	color: var(--muted);
	font: inherit;
	font-weight: 650;
	cursor: pointer;
	white-space: nowrap;
	transition: color var(--t), background var(--t), box-shadow var(--t);
}
.ascapp-theme-choice:hover { color: var(--ink); }
.ascapp-theme-choice svg { width: 18px; height: 18px; flex: 0 0 auto; display: block; }
.ascapp-theme-choice.active {
	background: var(--card);
	color: var(--brand-soft-ink);
	box-shadow: var(--sh-1);
}

/* Phones: let the switch fill the width and share it evenly. */
@media (max-width: 520px) {
	.ascapp-theme-seg { width: 100%; }
	.ascapp-theme-choice { flex: 1 1 0; justify-content: center; padding: 10px 8px; }
}

/* Workspace toggle (Service Center / Warranty) */
.ascapp-modes {
	display: inline-flex;
	flex: 0 0 auto;
	background: var(--border-soft);
	border: 1px solid var(--border);
	border-radius: 11px;
	padding: 3px;
	gap: 3px;
	margin-left: 2px;
}

.ascapp-mode {
	padding: 6px 13px;
	border-radius: 8px;
	text-decoration: none;
	color: var(--muted);
	font-weight: 700;
	font-size: 13px;
	white-space: nowrap;
	transition: color var(--t), background var(--t), box-shadow var(--t);
}
.ascapp-mode:hover { color: var(--ink); }
.ascapp-mode.active {
	background: var(--card);
	color: var(--brand-soft-ink);
	box-shadow: var(--sh-1);
}

/* ---------------------------------------------------------------------
 * 5. Announcement banner
 * ------------------------------------------------------------------- */

/* v4.16.0. This was a solid brand gradient with white text — a saturated band
   across the top of every screen, which is a lot of shouting for a line staff
   read forty times a day. It is now a soft brand-TINTED band: the same colour
   family, at a fraction of the weight, with the text in readable ink rather
   than knocked out of the colour.

   Two layers, and each earns its place. The radial is a wide, very faint pool
   of brand behind the text, which stops the band reading as a flat grey strip;
   the linear underneath fades it left to right so the bar has a direction and
   does not look like a disabled input. Both are built from var(--brand-soft)
   and var(--card-2), so a business's own palette carries through automatically
   and dark mode needs no separate rule — the tokens already differ there. */
.ascapp-banner {
	position: relative;
	background:
		radial-gradient(120% 200% at 50% -80%, var(--brand-soft), transparent 70%),
		linear-gradient(90deg, var(--card-2), var(--brand-soft) 50%, var(--card-2));
	color: var(--ink-2);
	border-bottom: 1px solid var(--border);
}

/* A hairline of full-strength brand along the top edge. One pixel of real
   colour does the job the whole saturated band used to attempt. */
.ascapp-banner::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: 2px;
	background: linear-gradient(90deg, transparent, var(--brand), transparent);
	opacity: 0.55;
}

.ascapp-banner-inner {
	position: relative;
	max-width: 1160px;
	margin: 0 auto;
	padding: 11px 20px;
	font-size: 14px;
	font-weight: 600;
	text-align: center;
	line-height: 1.45;
}
.ascapp-banner-inner a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }

/* A quote is set apart from an announcement: lighter weight, a touch of italic
   and a decorative mark, so the two kinds of message do not look like the same
   kind of instruction. The <blockquote> is inline because it is one line inside
   a band, not a block quotation in an article. */
.ascapp-banner.is-quote .ascapp-banner-inner {
	display: flex;
	align-items: baseline;
	justify-content: center;
	gap: 7px;
	font-weight: 550;
}
.ascapp-banner blockquote {
	margin: 0;
	font-style: italic;
	letter-spacing: 0.005em;
}
.ascapp-quotemark {
	font-family: Georgia, "Times New Roman", serif;
	font-size: 26px;
	line-height: 0;
	color: var(--brand);
	opacity: 0.5;
	flex: 0 0 auto;
	/* The glyph sits high in its own box; this drops it onto the text baseline
	   instead of floating above the first word. */
	transform: translateY(6px);
}

/* ---------------------------------------------------------------------
 * 6. Layout + typography
 * ------------------------------------------------------------------- */

.ascapp-main { max-width: 1160px; margin: 0 auto; padding: 26px 20px 64px; }

.ascapp h1 {
	font-size: 25px;
	font-weight: 750;
	letter-spacing: -0.022em;
	margin: 4px 0 20px;
	line-height: 1.25;
}
.ascapp h2 {
	font-size: 17px;
	font-weight: 700;
	letter-spacing: -0.012em;
	margin: 30px 0 12px;
}

/* ---------------------------------------------------------------------
 * 7. Stat cards
 * ------------------------------------------------------------------- */

.ascapp-cards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
	gap: 12px;
	margin-bottom: 24px;
}

.ascapp-card {
	position: relative;
	display: block;
	overflow: hidden;
	padding: 15px 16px 14px;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--sh-1);
	text-decoration: none;
	color: inherit;
	transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}

.ascapp-card:hover {
	transform: translateY(-2px);
	box-shadow: var(--sh-2);
	border-color: color-mix(in srgb, var(--c, var(--brand)) 40%, var(--border));
}

/* Colour rail + a matching wash so each metric is recognisable at a glance. */
.ascapp-card::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 4px;
	background: var(--c, var(--brand));
}
.ascapp-card::after {
	content: "";
	position: absolute;
	inset: 0;
	background: radial-gradient(120px 60px at 0% 0%, var(--c, var(--brand)), transparent 70%);
	opacity: 0.07;
	pointer-events: none;
}

.ascapp-card .num {
	font-size: 28px;
	font-weight: 780;
	line-height: 1.1;
	letter-spacing: -0.03em;
	font-variant-numeric: tabular-nums;
}
.ascapp-card .lbl {
	margin-top: 4px;
	font-size: 11.5px;
	font-weight: 650;
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: 0.045em;
}

.ascapp-c-total { --c: var(--brand); }
.ascapp-c-received { --c: var(--slate); }
.ascapp-c-in_repair { --c: var(--warn); }
.ascapp-c-work_done { --c: var(--violet); }
.ascapp-c-ready { --c: var(--info); }
.ascapp-c-picked_up { --c: var(--ok); }
.ascapp-c-cancelled { --c: var(--err); }
.ascapp-c-near { --c: var(--warn); }
.ascapp-c-active { --c: var(--ok); }
.ascapp-c-returned { --c: var(--slate); }

/* ---------------------------------------------------------------------
 * 8. Status badges
 * ------------------------------------------------------------------- */

.ascapp-badge {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 3px 11px;
	border-radius: 999px;
	font-size: 12px;
	font-weight: 650;
	line-height: 1.6;
	border: 1px solid transparent;
	white-space: nowrap;
}
.ascapp-badge::before {
	content: "";
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: currentColor;
	opacity: 0.85;
}

.ascapp-badge.received { background: var(--border-soft); color: var(--muted); border-color: var(--border); }
.ascapp-badge.in_repair { background: var(--warn-bg); color: var(--warn-ink); border-color: var(--warn-border); }
.ascapp-badge.work_done { background: var(--brand-soft); color: var(--brand-soft-ink); border-color: var(--border); }
.ascapp-badge.ready { background: var(--brand-soft); color: var(--brand-soft-ink); border-color: var(--border); }
.ascapp-badge.picked_up { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-border); }
.ascapp-badge.cancelled { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-border); }

/* ---------------------------------------------------------------------
 * 9. Panels + tables
 * ------------------------------------------------------------------- */

.ascapp-panel {
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	overflow: hidden;
	box-shadow: var(--sh-1);
}

/* A wide table scrolls INSIDE this box. The page itself must never move
   sideways — that is the Phase 4 rule, and it was quietly not being kept.

   `overflow-x: auto` alone was not enough. A scroll container clips what it
   paints, but its descendants still contributed to the ROOT scrollable overflow
   area, so on a 768px tablet the whole page could be swiped ~340px sideways
   into empty space while the table sat there scrolling independently. Measured
   in a real 768px viewport, not an iframe: documentElement.scrollWidth 1095
   against a clientWidth of 753.

   `contain: paint` is what fixes it — it makes this box a containment boundary,
   so nothing inside it can be part of the page's scroll area. It was the only
   candidate that worked; max-width, min-width and overflow on the parents all
   left it at 1095. The container keeps scrolling exactly as before (measured:
   400px of internal scroll after the change), and the sticky table header still
   sticks, because it sticks to this box and this box has not changed.

   PRE-EXISTING, not introduced by Phase 5B/5F: v4.11.0 does the same thing, by
   342px on /tickets/ and 251px on /repairs/. Earlier sweeps missed it because
   they measured body.scrollWidth, which fits — it is the ROOT that overflows,
   not the body. Fixed here because 5B adds a column to one of those tables, and
   making a known-bad number worse is not something to ship. */
.ascapp-table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	contain: paint;
}

.ascapp table { width: 100%; border-collapse: collapse; }

.ascapp thead th {
	position: sticky;
	top: 0;
	z-index: 1;
	background: var(--card-2);
	text-align: left;
	font-size: 11.5px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--muted);
	padding: 11px 15px;
	border-bottom: 1px solid var(--border);
	white-space: nowrap;
}

.ascapp tbody td {
	padding: 12px 15px;
	border-bottom: 1px solid var(--border-soft);
	vertical-align: middle;
}
.ascapp tbody tr:last-child td { border-bottom: 0; }
.ascapp tbody tr { transition: background var(--t); }
.ascapp tbody tr:hover { background: var(--card-2); }

/* Definition lists (ticket / item details) */
.ascapp-defs { display: grid; grid-template-columns: 190px 1fr; margin: 0; }
.ascapp-defs dt {
	padding: 11px 15px;
	font-weight: 650;
	font-size: 13.5px;
	color: var(--muted);
	border-bottom: 1px solid var(--border-soft);
}
.ascapp-defs dd {
	padding: 11px 15px;
	margin: 0;
	border-bottom: 1px solid var(--border-soft);
	/* A single unbreakable value — a long serial number, a device name typed
	   without spaces — otherwise forces the grid track wider than the screen and
	   drags every other row out with it, scrolling the whole page sideways.
	   Measured at 514px inside a 345px column before this. Same fix Phase 4
	   applied to table cells, for the same reason. */
	min-width: 0;
	overflow-wrap: anywhere;
	word-break: break-word;
}
.ascapp-defs dt:last-of-type, .ascapp-defs dd:last-of-type { border-bottom: 0; }

/* ---------------------------------------------------------------------
 * 10. Forms
 * ------------------------------------------------------------------- */

.ascapp-field { margin-bottom: 15px; }
.ascapp-field label {
	display: block;
	font-weight: 650;
	font-size: 12.5px;
	letter-spacing: 0.01em;
	color: var(--ink-2);
	margin-bottom: 6px;
}

.ascapp input[type="text"], .ascapp input[type="email"], .ascapp input[type="search"],
.ascapp input[type="password"], .ascapp input[type="date"], .ascapp input[type="number"],
/* input[type="url"] was missing from this list, so the two URL fields on the
   business profile screen (logo, favicon) got no padding, no border and no
   border-radius — they rendered 24px tall and visibly unlike every other field
   in the app. Found by the responsive sweep, which measured them as sub-40px
   tap targets. */
.ascapp input[type="tel"], .ascapp input[type="url"], .ascapp select, .ascapp textarea {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--field-border);
	border-radius: var(--r-sm);
	font: inherit;
	color: var(--ink);
	background: var(--card);
	transition: border-color var(--t), box-shadow var(--t), background var(--t);
	-webkit-appearance: none;
	appearance: none;
}
.ascapp textarea { min-height: 76px; resize: vertical; }

.ascapp select {
	/* Keep the chevron — appearance:none removes the native one. */
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
	                  linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: calc(100% - 17px) 52%, calc(100% - 12px) 52%;
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	padding-right: 34px;
}

.ascapp input::placeholder, .ascapp textarea::placeholder { color: var(--muted); opacity: 0.75; }

.ascapp input:focus, .ascapp select:focus, .ascapp textarea:focus {
	outline: none;
	border-color: var(--brand);
	box-shadow: 0 0 0 3px var(--ring);
}

.ascapp input[type="checkbox"], .ascapp input[type="radio"] {
	width: auto;
	accent-color: var(--brand);
}

.ascapp .req { color: var(--err); font-weight: 700; }

/* Two-column form grid so long forms fit with little scrolling. */
.ascapp-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 18px; }
.ascapp-form-grid .full { grid-column: 1 / -1; }
@media (max-width: 620px) {
	.ascapp-form-grid { grid-template-columns: 1fr; column-gap: 0; }
}

/* ---------------------------------------------------------------------
 * 10b. Itemised charge rows (v5.6.0)
 *
 * One row = Particular + Amount + Remove. On a desktop the three sit on one
 * line with the description taking the space; below 620px they stack, which is
 * the same breakpoint .ascapp-form-grid already uses so the whole panel reflows
 * at one width rather than in two stages.
 *
 * grid rather than flex, because the columns have to LINE UP down the list —
 * a bill whose amounts do not form a column is a bill nobody can read down.
 *
 * The remove button sits in its own track and is bottom-aligned so it lands
 * level with the inputs beside it rather than with their labels. It is drawn by
 * the script; with JavaScript off the track is empty and collapses.
 * ------------------------------------------------------------------- */

.asc-part-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 170px) auto;
	column-gap: 12px;
	align-items: end;
}
.asc-part-row .ascapp-field { margin-bottom: 10px; }
.asc-part-del { padding-bottom: 10px; }
/* The rows repeat their two labels; a screen reader user gets them from the
 * <label> on every input, and a sighted user does not need "Particular" eight
 * times down the page. Hidden after the first row rather than removed, so the
 * association survives. */
.asc-part-row + .asc-part-row label { display: none; }
.asc-part-addwrap { margin: 4px 0 2px; }

@media (max-width: 620px) {
	.asc-part-row {
		grid-template-columns: 1fr;
		column-gap: 0;
		/* On a phone each row is its own block, so it needs a visible edge —
		 * otherwise eight rows read as sixteen unrelated fields. */
		border-top: 1px solid var(--border);
		padding-top: 12px;
		margin-top: 4px;
	}
	.asc-part-row:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
	/* …and every row shows its labels again, because there is no column header
	 * above them to inherit meaning from. */
	.asc-part-row + .asc-part-row label { display: block; }
	.asc-part-del { padding-bottom: 14px; }
}

/* A value that is deliberately not editable — the customer's phone number on
 * the edit-customer screen. Rendered as text, never as a disabled input: a
 * greyed-out box invites somebody to try to turn it on and explains nothing. */
.ascapp-fieldlabel {
	display: block;
	margin-bottom: 6px;
	font-size: 14px;
	font-weight: 600;
	color: var(--ink);
}
.ascapp-readonly {
	margin: 0 0 4px;
	padding: 10px 12px;
	border: 1px dashed var(--border);
	border-radius: 10px;
	background: var(--card-2);
	color: var(--ink);
}

/* ---------------------------------------------------------------------
 * 10c. Two-row records, and alternating columns (v5.7.0)
 *
 * THE PROBLEM. A queue row carried seven columns, the last of which held a
 * textarea and four buttons. On a laptop that column was about 300px wide, the
 * buttons wrapped into half-width stubs, and everything else was squeezed into
 * what was left.
 *
 * THE SHAPE. Each record is two <tr>s — .ascapp-jobrow across the top,
 * .ascapp-actionrow full width underneath. On a phone .ascapp-tcards turns
 * every <tr> into its own card, so the pair is stitched back together here:
 * the top loses its bottom border and its bottom radius, the bottom loses its
 * top border, its top radius and the 10px gap. One card per job, as before.
 * ------------------------------------------------------------------- */

/* The two halves read as one record: no line between them, one line after. */
.ascapp-tcards tbody tr.ascapp-jobrow > td { border-bottom: 0; padding-bottom: 6px; }
.ascapp-tcards tbody tr.ascapp-actionrow > td {
	border-bottom: 1px solid var(--border);
	padding-top: 0;
	padding-bottom: 14px;
}
.ascapp-tcards tbody tr.ascapp-actionrow:last-child > td { border-bottom: 0; }
/* Hovering anywhere on a record highlights the whole record, not half of it. */
.ascapp-tcards tbody tr.ascapp-jobrow:hover,
.ascapp-tcards tbody tr.ascapp-actionrow:hover { background: var(--card-2); }

.ascapp-actionrow .ascapp-actions { gap: 10px; row-gap: 10px; }
/* The action bar is wide now, so buttons sit at their natural size instead of
   stretching — a 900px-wide "Cancel" is not an improvement. */
.ascapp-actionrow .ascapp-btn { flex: 0 0 auto; }
.ascapp-actionrow textarea { min-width: 260px; max-width: 520px; }

/* The reported problem, above the box that answers it. */
.ascapp-jobproblem {
	margin: 0 0 10px;
	font-size: 13.5px;
	color: var(--ink-2);
	line-height: 1.5;
}
.ascapp-jobproblem-h {
	display: block;
	font-size: 11.5px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--muted);
	margin-bottom: 2px;
}

/* ---------------------------------------------------------------------
 * Alternating columns (v5.7.0)
 *
 * A wide table is hard to read across: the eye loses the row between column
 * three and column six. Tinting every other COLUMN gives it something to track.
 *
 * SUBTLE ON PURPOSE. --card-2 is the same near-white the table header already
 * uses, so nothing gains a grey block and no text loses contrast — the tint is
 * behind the cell, never on the type. Explicitly NOT dark grey.
 *
 * Desktop only. Below 700px the table is a stack of cards and each <td> is a
 * row of one, so column striping would be meaningless stripes down a card. It
 * is also skipped on the action row, which is one cell spanning everything.
 * ------------------------------------------------------------------- */
@media (min-width: 701px) {
	.ascapp-tcards tbody tr:not(.ascapp-actionrow) > td:nth-child(even),
	.ascapp-tcards thead th:nth-child(even) {
		background: var(--card-2);
	}
	/* The hover highlight has to win over the stripe, or half a row lights up. */
	.ascapp-tcards tbody tr:hover > td:nth-child(even) { background: transparent; }
}

/* ---------------------------------------------------------------------
 * 11. Buttons
 * ------------------------------------------------------------------- */

.ascapp-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	padding: 10px 17px;
	border-radius: 10px;
	border: 1px solid transparent;
	background: linear-gradient(180deg, var(--brand), var(--brand-strong));
	color: var(--brand-ink);
	font: inherit;
	font-weight: 650;
	line-height: 1.25;
	cursor: pointer;
	text-decoration: none;
	white-space: nowrap;
	box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12);
	transition: transform var(--t), box-shadow var(--t), background var(--t), border-color var(--t), color var(--t);
}
.ascapp-btn:hover { box-shadow: 0 6px 16px -6px var(--ring); transform: translateY(-1px); }
.ascapp-btn:active { transform: translateY(0); box-shadow: none; }

.ascapp-btn.ghost {
	background: var(--card);
	color: var(--ink-2);
	border-color: var(--field-border);
	box-shadow: var(--sh-1);
}
.ascapp-btn.ghost:hover { background: var(--card-2); border-color: var(--brand); color: var(--ink); }

.ascapp-btn.danger {
	background: var(--card);
	color: var(--err);
	border-color: var(--err-border);
	box-shadow: var(--sh-1);
}
.ascapp-btn.danger:hover { background: var(--err-bg); border-color: var(--err); }

.ascapp-btn.small { padding: 7px 12px; font-size: 13px; border-radius: 9px; }

.ascapp-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.ascapp-panel .ascapp-actions { margin-top: 16px; }
.ascapp-quick { margin-top: 6px; }
@media (max-width: 620px) {
	.ascapp-actions > * { flex: 1 1 100%; }
	.ascapp-actions .ascapp-btn { width: 100%; justify-content: center; }
}

/* Count pill inside dashboard / stage buttons */
.ascapp-pill {
	display: inline-block;
	min-width: 21px;
	padding: 1px 7px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.24);
	font-size: 12px;
	font-weight: 750;
	line-height: 1.5;
	text-align: center;
	font-variant-numeric: tabular-nums;
}
.ascapp-btn.ghost .ascapp-pill { background: var(--brand-soft); color: var(--brand-soft-ink); }

/* A PILL THAT IS A LINK IS A CONTROL, NOT A BADGE.
   The rule above styles a count sitting inside a button — 20px tall, which is
   right for something nobody presses. Phase 5D then reused the same class for
   the claim stage FILTERS, which are links people tap, and they inherited the
   20px. On a phone that is half the 40px minimum the rest of the app holds to,
   and the responsive sweep counted 18 of them across 360/390/412.
   Selecting on `a` keeps the count badges exactly as they were. */
a.ascapp-pill {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	min-height: 40px;
	padding: 4px 14px;
	font-size: 13px;
	text-decoration: none;
	border: 1px solid var(--border);
	background: var(--card);
	color: var(--muted);
}
a.ascapp-pill:hover { background: var(--border-soft); color: var(--ink); }
a.ascapp-pill.active { background: var(--brand-soft); color: var(--brand-soft-ink); border-color: transparent; }

/* Stage toggle (New Repairs / Under Repair, Ready / Uncollected) */
.ascapp-subnav { display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 16px; }

/* ---------------------------------------------------------------------
 * 12. Notices
 * ------------------------------------------------------------------- */

.ascapp-notice {
	border-radius: var(--r);
	padding: 12px 15px;
	margin: 0 0 18px;
	font-weight: 550;
	border: 1px solid;
	box-shadow: var(--sh-1);
}
.ascapp-notice.ok { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-ink); }
.ascapp-notice.err { background: var(--err-bg); border-color: var(--err-border); color: var(--err-ink); }
.ascapp-notice.warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-ink); }
.ascapp-notice strong { font-weight: 750; }

/* ---------------------------------------------------------------------
 * 13. Toolbar + search
 * ------------------------------------------------------------------- */

.ascapp-toolbar {
	display: flex;
	gap: 12px;
	flex-wrap: wrap;
	align-items: flex-end;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	padding: 14px 16px;
	margin-bottom: 18px;
	box-shadow: var(--sh-1);
}
.ascapp-toolbar .ascapp-field { margin: 0; }

.ascapp-search { display: flex; gap: 10px; margin: 0 0 20px; max-width: 580px; }
.ascapp-search input[type="search"] { flex: 1 1 auto; min-width: 0; padding: 11px 14px; }
.ascapp-search .ascapp-btn { flex: 0 0 auto; }

/* ---------------------------------------------------------------------
 * 14. Login / forgot / denied
 * ------------------------------------------------------------------- */

.ascapp-login-wrap {
	min-height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
}

.ascapp-login {
	width: 100%;
	max-width: 400px;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	padding: 32px 28px;
	box-shadow: var(--sh-3);
}
.ascapp-login .logo {
	text-align: center;
	font-size: 22px;
	font-weight: 780;
	letter-spacing: -0.02em;
	margin-bottom: 4px;
}
.ascapp-login .logo span { color: var(--brand); }
.ascapp-login .sub { text-align: center; color: var(--muted); font-size: 13.5px; margin-bottom: 24px; }
.ascapp-login .ascapp-btn { width: 100%; margin-top: 10px; padding: 12px 18px; }
.ascapp-login img.brandlogo {
	display: block;
	width: 108px;
	height: 108px;
	border-radius: 50%;
	object-fit: cover;
	margin: 0 auto 16px;
	border: 3px solid var(--card);
	box-shadow: 0 4px 18px -6px rgba(15, 23, 42, 0.45), 0 0 0 1px var(--border);
}
.ascapp-login-links { text-align: center; margin: 18px 0 0; font-size: 13px; }
/* inline-flex + min-height: "Forgot password?" was 108x18, which is a link a
   thumb misses. Everything else tappable in the product is 44px (Phase 4); the
   sign-in card was never swept, because the harness runs signed in. */
.ascapp-login-links a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 0 12px;
	color: var(--brand);
	text-decoration: none;
	font-weight: 650;
}
.ascapp-login-links a:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------
 * 15. Vendor footer
 * ------------------------------------------------------------------- */

/* v5.20.2. One quiet line under the page: "© 2026 Anija Digital · RMS v5.20.2
   · Support: 9764479522 · sales@anija.app" — smaller than the UI, muted, links
   no louder than the text around them. Two groups (who / how to reach us) that
   wrap onto two lines on a phone rather than into a block of three.

   No fixed positioning, so it cannot overlap content or the mobile navigation:
   .ascapp-foot has always been a normal block at the end of the document. It is
   hidden in print (section 24). */
.ascapp-foot {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 2px 0;
	max-width: 1160px;
	margin: 0 auto;
	padding: 14px 20px 20px;
	text-align: center;
	color: var(--muted);
	font-size: 12px;
	line-height: 1.5;
}
.ascapp-foot-id,
.ascapp-foot-support { display: inline-flex; flex-wrap: wrap; justify-content: center; align-items: center; }
.ascapp-foot-legal { display: inline; color: var(--muted); }
.ascapp-foot-sep { margin: 0 .5em; opacity: .7; }
/* A flex row drops the space between items: the label keeps its own. */
.ascapp-foot-lbl { margin-right: .35em; }
.ascapp-foot a { color: var(--ink-2); text-decoration: none; font-weight: 500; }
.ascapp-foot a:hover { color: var(--brand); text-decoration: underline; }
@media (max-width: 700px) {
	.ascapp-foot-id,
	.ascapp-foot-support { flex-basis: 100%; }
	.ascapp-foot-sep.is-mid,
	.ascapp-foot-lbl { display: none; }
}

/* v5.20.2. A date-time in a list (All Jobs' Received): the date, and the time
   under it, smaller and muted. The cell keeps a readable minimum width so the
   pinned action buttons never squeeze it (desktop-shell.php pins them). */
.ascapp-when { display: inline-flex; flex-direction: column; line-height: 1.3; white-space: nowrap; }
.ascapp-when .h { font-size: 12px; color: var(--muted); }
.ascapp td.is-when { min-width: 6.5rem; white-space: nowrap; }

/* v5.5.0. An internal reference — the job card number — shown beside the
   customer's tracking ID on a ticket. Monospaced and boxed so the two cannot be
   mistaken for each other at a glance, which is the entire failure this feature
   has to prevent; the note beside it says which is which in words. */
.ascapp-internal {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 13px;
	font-weight: 650;
	padding: 1px 7px;
	border: 1px solid var(--border);
	border-radius: 6px;
	background: var(--card-2);
}
.ascapp-internal-note { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }

/* ---------------------------------------------------------------------
 * 16. Utilities
 * ------------------------------------------------------------------- */

.ascapp-muted { color: var(--muted); }
.ascapp-mt { margin-top: 18px; }
.ascapp-right { text-align: right; }

/* ---------------------------------------------------------------------
 * 17. Warranty workspace
 * ------------------------------------------------------------------- */

.ascw-badge {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 3px 11px;
	border-radius: 999px;
	font-size: 12px;
	font-weight: 700;
	line-height: 1.6;
	border: 1px solid transparent;
	white-space: nowrap;
}
.ascw-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.85; }
.ascw-badge.active { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-border); }
.ascw-badge.near { background: var(--warn-bg); color: var(--warn-ink); border-color: var(--warn-border); }
.ascw-badge.expired { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-border); }
.ascw-badge.returned { background: var(--border-soft); color: var(--muted); border-color: var(--border); }

.ascw-part2-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ascw-scanmode {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	font-size: 13px;
	background: var(--border-soft);
	border: 1px solid var(--border);
	border-radius: 999px;
	padding: 5px 12px;
}
.ascw-scanmode label { font-weight: 650; display: inline-flex; align-items: center; gap: 5px; margin: 0; }
.ascw-scanmode input { width: auto; }

.ascw-block {
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	padding: 15px 15px 5px;
	margin-top: 14px;
	background: var(--card-2);
}
.ascw-block-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.ascw-block-n { font-weight: 800; color: var(--muted); font-size: 12.5px; letter-spacing: 0.04em; }

.ascw-serial-row { display: flex; gap: 8px; }
.ascw-serial-row input { flex: 1; }
.ascw-serials { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

.ascw-chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: var(--brand-soft);
	color: var(--brand-soft-ink);
	border: 1px solid var(--border);
	border-radius: 999px;
	padding: 3px 6px 3px 11px;
	font-size: 13px;
	font-weight: 700;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.ascw-chip-x {
	border: 0;
	background: rgba(127, 127, 127, 0.18);
	color: inherit;
	border-radius: 50%;
	width: 18px;
	height: 18px;
	line-height: 1;
	cursor: pointer;
	font-size: 13px;
	transition: background var(--t);
}
.ascw-chip-x:hover { background: rgba(127, 127, 127, 0.34); }

/* Serial verification states: blue (checking) → green (free) / red (duplicate).
   These three rules are ALSO inlined on the intake page, so a stale cached copy
   of this file can never leave every chip looking the same. */
.ascw-chip.pending { background: var(--brand-soft); color: var(--brand-soft-ink); border-color: var(--border); }
.ascw-chip.ok { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-border); }
.ascw-chip.dup { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-border); }

.ascw-legend { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; font-size: 12px; color: var(--muted); margin: 6px 0 0; }
.ascw-legend > span { display: inline-flex; align-items: center; }
.ascw-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.ascw-dot.pending { background: var(--brand); }
.ascw-dot.ok { background: var(--ok); }
.ascw-dot.dup { background: var(--err); }

.ascw-warn { margin: 10px 0 4px; }
.ascw-help {
	background: #0f172a;
	color: #e2e8f0;
	border-radius: var(--r-sm);
	padding: 11px 13px;
	font-size: 13px;
	overflow-x: auto;
	border: 1px solid var(--border);
}

/* ---------------------------------------------------------------------
 * 18. Responsive
 * ------------------------------------------------------------------- */

/* Tablets and small laptops: tighten the padding. The nav no longer has to be
   rescued onto a row of its own here — it has had one since it moved to the
   second bar. */
@media (max-width: 1080px) {
	.ascapp-bar-top { gap: 8px 12px; padding: 10px 16px; }
	.ascapp-bar-nav { padding: 5px 16px; }
	/* When row 1 wraps: brand first, then the workspace toggle, then the
	   account cluster pushed to the right of whichever line it lands on. */
	.ascapp-modes { order: 1; }
	.ascapp-user { order: 2; margin-left: auto; }
}

@media (max-width: 860px) {
	.ascapp-bar-top { padding: 10px 14px; }
	.ascapp-bar-nav { padding: 3px 14px; }

	.ascapp-main { padding: 18px 13px 60px; }
	.ascapp h1 { font-size: 21px; }
	.ascapp h2 { font-size: 16px; margin-top: 24px; }

	/* Bigger touch targets; 16px inputs stop iOS zoom-on-focus. */
	.ascapp-btn { min-height: 44px; padding: 11px 16px; }
	/* The "small" button is the one that actually gets tapped — it is every row
	   action on every queue. 38px was under the comfortable target size. */
	.ascapp-btn.small { min-height: 44px; padding: 10px 14px; }
	.ascapp input, .ascapp select, .ascapp textarea { font-size: 16px; }

	.ascapp-toolbar { padding: 12px; }
	.ascapp-toolbar .ascapp-field,
	.ascapp-toolbar .ascapp-btn,
	.ascapp-toolbar > a.ascapp-btn { flex: 1 1 100%; }

	.ascapp-cards { grid-template-columns: repeat(2, 1fr); gap: 10px; }
	.ascapp-card .num { font-size: 24px; }

	.ascapp-defs { grid-template-columns: 1fr; }
	.ascapp-defs dt { border-bottom: 0; padding-bottom: 0; }
	.ascapp-defs dd { padding-top: 2px; }

	.ascapp-actions .ascapp-btn { flex: 1 1 auto; }
	.ascapp-form-grid { grid-template-columns: 1fr; }
	.ascapp-quick .ascapp-btn { flex: 1 1 100%; }
	.ascapp-subnav .ascapp-btn { flex: 1 1 0; }

	/* Sticky headers fight short scroll areas on phones. */
	.ascapp thead th { position: static; }
}

@media (max-width: 420px) {
	.ascapp-cards { grid-template-columns: 1fr 1fr; }
	.ascapp-brand { font-size: 15.5px; }
	.ascapp-brand::before { width: 22px; height: 22px; flex-basis: 22px; border-radius: 7px; }
	.ascapp-search { flex-wrap: wrap; }
	.ascapp-search .ascapp-btn { flex: 1 1 100%; }
	.ascapp-login { padding: 26px 20px; }
}

/* ---------------------------------------------------------------------
 * 19. Motion + print
 * ------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	.ascapp *, .ascapp *::before, .ascapp *::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
	.ascapp-card:hover, .ascapp-btn:hover { transform: none; }
}

@media print {
	.ascapp { background: #fff; }
	.ascapp-bar, .ascapp-banner, .ascapp-foot, .ascapp-actions, .ascapp-toolbar, .ascapp-search { display: none !important; }
	.ascapp-panel, .ascapp-card { box-shadow: none; border-color: #d0d5dd; }
	.ascapp-main { padding: 0; max-width: none; }
}

/* =====================================================================
 * 20. Phase 4 — UI/UX, responsive and accessibility layer
 *
 * Appended as its own section rather than edited into the rules above, so the
 * cascade stays predictable: everything here is either a new component or a
 * deliberate override that has to win, and none of it silently changes a
 * selector another screen depends on.
 * ================================================================== */

/* --- 20.1 Skip link -------------------------------------------------
 * First tab stop on every page. Off-screen until focused.
 */
.ascapp-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	padding: 12px 18px;
	background: var(--brand);
	color: var(--brand-ink);
	font-weight: 650;
	border-radius: 0 0 var(--r) 0;
	text-decoration: none;
}
.ascapp-skip:focus { left: 0; }

/* --- 20.2 Focus visibility ------------------------------------------
 * A keyboard user must always be able to see where they are. Applied through
 * :focus-visible so a mouse click does not leave a ring behind.
 */
.ascapp a:focus-visible,
.ascapp button:focus-visible,
.ascapp input:focus-visible,
.ascapp select:focus-visible,
.ascapp textarea:focus-visible,
.ascapp [tabindex]:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
	border-radius: var(--r-sm);
}

/* --- 20.3 Empty states ----------------------------------------------
 * What is empty, why, and the one thing to do next.
 */
.ascapp-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 8px;
	padding: 48px 24px;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--sh-1);
}
.ascapp-empty .ascapp-empty-icon {
	width: 44px;
	height: 44px;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var(--border-soft);
	color: var(--muted);
	margin-bottom: 4px;
}
.ascapp-empty .ascapp-empty-icon svg { width: 22px; height: 22px; display: block; }
.ascapp-empty h2 {
	margin: 0;
	font-size: 17px;
	font-weight: 700;
	color: var(--ink);
}
.ascapp-empty p {
	margin: 0;
	max-width: 46ch;
	color: var(--muted);
	font-size: 14px;
	line-height: 1.55;
}
.ascapp-empty .ascapp-empty-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	justify-content: center;
	margin-top: 10px;
}

/* --- 20.4 Form sections ---------------------------------------------
 * Grouping long forms into labelled blocks. <fieldset>/<legend> so the grouping
 * is announced, not merely drawn.
 */
.ascapp-fieldset {
	border: 0;
	padding: 0;
	margin: 0 0 22px;
	min-width: 0; /* fieldset defaults to min-content and breaks the grid */
}
.ascapp-fieldset:last-of-type { margin-bottom: 8px; }
.ascapp-fieldset > legend {
	padding: 0;
	margin: 0 0 12px;
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--muted);
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
}
.ascapp-fieldset > legend::after {
	content: "";
	flex: 1 1 auto;
	height: 1px;
	background: var(--border);
}

/* --- 20.5 Field help + inline errors --------------------------------- */
.ascapp-field .ascapp-help {
	display: block;
	margin-top: 5px;
	font-size: 12.5px;
	line-height: 1.45;
	color: var(--muted);
}
.ascapp-field .ascapp-err {
	display: block;
	margin-top: 5px;
	font-size: 12.5px;
	font-weight: 600;
	color: var(--err);
}
.ascapp-field.has-error input,
.ascapp-field.has-error select,
.ascapp-field.has-error textarea { border-color: var(--err); }

/* --- 20.6 Busy buttons ----------------------------------------------
 * A form that has been submitted must look submitted. The label swap and the
 * disable both happen in JS (asc_app_form_script) — this is only the look.
 */
.ascapp-btn[aria-busy="true"] {
	position: relative;
	opacity: 0.75;
	cursor: progress;
	pointer-events: none;
}
.ascapp-btn[aria-busy="true"]::after {
	content: "";
	width: 13px;
	height: 13px;
	margin-left: 9px;
	display: inline-block;
	vertical-align: -2px;
	border: 2px solid currentColor;
	border-right-color: transparent;
	border-radius: 50%;
	animation: ascapp-spin 620ms linear infinite;
}
@keyframes ascapp-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
	.ascapp-btn[aria-busy="true"]::after { animation: none; opacity: .55; }
}

/* --- 20.7 Active filter chips ---------------------------------------- */
.ascapp-chips {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
	margin: 0 0 14px;
}
.ascapp-chips .ascapp-chips-label {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--muted);
}
.ascapp-chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 6px 10px 6px 12px;
	font-size: 13px;
	font-weight: 600;
	color: var(--brand-soft-ink);
	background: var(--brand-soft);
	border: 1px solid var(--border);
	border-radius: 999px;
	text-decoration: none;
	line-height: 1.3;
}
.ascapp-chip .k { font-weight: 500; color: var(--muted); }
.ascapp-chip .x {
	display: inline-grid;
	place-items: center;
	width: 20px;
	height: 20px;
	margin-right: -3px;
	border-radius: 50%;
	font-size: 15px;
	line-height: 1;
	color: var(--muted);
}
.ascapp-chip:hover .x { background: var(--card); color: var(--ink); }
.ascapp-chip-clear {
	color: var(--muted);
	background: transparent;
	border-style: dashed;
}
.ascapp-chip-clear:hover { color: var(--ink); border-color: var(--field-border); }

/* --- 20.8 Result summary + pager ------------------------------------- */
.ascapp-resultbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin: 0 0 12px;
	font-size: 13.5px;
	color: var(--muted);
}
.ascapp-resultbar strong { color: var(--ink); font-weight: 650; }

.ascapp-pager {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
	margin-top: 18px;
}
.ascapp-pager .ascapp-pager-status {
	font-size: 13.5px;
	color: var(--muted);
	font-variant-numeric: tabular-nums;
}
.ascapp-pager .is-disabled {
	opacity: 0.45;
	pointer-events: none;
}

/* --- 20.9 Responsive tables — the main mobile fix ---------------------
 * A six-column table inside a 360px viewport is a 1,000px-wide strip you drag
 * sideways to read one row. Below 700px each row becomes a card and each cell
 * carries its own column name, taken from data-label. The markup is one table
 * in both cases, so nothing is duplicated and screen readers still get a table
 * on the desktop layout.
 *
 * Opt in per table with .ascapp-tcards so a table that genuinely needs its grid
 * (a comparison, a matrix) can keep scrolling instead.
 */
@media (max-width: 700px) {
	.ascapp-tcards { display: block; }
	.ascapp-tcards thead {
		/* Visually gone, but not display:none — the header cells stay in the
		   accessibility tree for anyone navigating the table by column.
		   display:block matters: `overflow` does not apply to a
		   table-header-group, so with the default display the nowrap header row
		   kept its full ~508px width and pushed the whole PAGE sideways on a
		   360px screen. Measured, not guessed. */
		display: block;
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		clip-path: inset(50%);
		white-space: nowrap;
	}
	.ascapp-tcards thead tr,
	.ascapp-tcards thead th { display: block; width: 1px; overflow: hidden; }
	.ascapp-tcards tbody { display: block; }
	.ascapp-tcards tbody tr {
		display: block;
		padding: 13px 14px;
		border: 1px solid var(--border);
		border-radius: var(--r);
		background: var(--card);
		box-shadow: var(--sh-1);
	}
	.ascapp-tcards tbody tr + tr { margin-top: 10px; }
	/* v5.7.0. A record is two <tr>s; a phone must still see ONE card. The top
	   half keeps its border except at the bottom, the bottom half keeps its
	   border except at the top, and the gap between them goes. */
	.ascapp-tcards tbody tr.ascapp-jobrow {
		border-bottom: 0;
		border-bottom-left-radius: 0;
		border-bottom-right-radius: 0;
		padding-bottom: 4px;
	}
	.ascapp-tcards tbody tr.ascapp-jobrow + tr.ascapp-actionrow {
		margin-top: 0;
		border-top: 0;
		border-top-left-radius: 0;
		border-top-right-radius: 0;
		padding-top: 4px;
	}
	.ascapp-tcards tbody tr.ascapp-jobrow > td { border-bottom: 0; padding-bottom: 5px; }
	.ascapp-tcards tbody tr.ascapp-actionrow > td { border-bottom: 0; padding: 6px 0 0; }
	/* Full-width, easily tapped buttons — the same rule the old actions cell
	   had, kept now that the bar is where they live. */
	.ascapp-actionrow .ascapp-btn { flex: 1 1 100%; width: 100%; justify-content: center; }
	.ascapp-actionrow textarea { min-width: 0; max-width: none; width: 100%; }
	.ascapp-tcards tbody tr:hover { background: var(--card); }
	.ascapp-tcards tbody td {
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 4px 12px;
		width: auto;
		padding: 5px 0;
		border: 0;
		font-size: 14px;
		/* The value is an anonymous flex item, so it cannot be targeted directly
		   and keeps min-width:auto. Without these two the label's fixed 33% plus
		   an unbreakable value (a long device string, a full timestamp) pushed
		   the row to 564px inside a 304px card and scrolled the whole document
		   sideways. Wrapping and breaking are what keep the page at 360px. */
		overflow-wrap: anywhere;
		word-break: break-word;
	}
	.ascapp-tcards tbody td::before {
		content: attr(data-label);
		flex: 0 0 33%;
		max-width: 33%;
		min-width: 0;
		font-size: 12px;
		font-weight: 700;
		text-transform: uppercase;
		letter-spacing: 0.045em;
		color: var(--muted);
	}
	.ascapp-tcards tbody td:empty { display: none; }
	/* The lead cell (tracking id / serial) is the card's title. */
	.ascapp-tcards tbody td.is-lead {
		display: block;
		font-size: 16px;
		font-weight: 700;
		padding: 0 0 8px;
		margin-bottom: 6px;
		border-bottom: 1px solid var(--border-soft);
	}
	.ascapp-tcards tbody td.is-lead::before { content: none; }
	/* Free-text cells read better as a block than as a label/value pair. */
	.ascapp-tcards tbody td.is-block { display: block; padding-top: 8px; }
	.ascapp-tcards tbody td.is-block::before {
		display: block;
		max-width: none;
		margin-bottom: 3px;
	}
	/* The actions cell becomes a full-width button row. */
	.ascapp-tcards tbody td.is-actions {
		display: block;
		padding: 11px 0 0;
		margin-top: 8px;
		border-top: 1px solid var(--border-soft);
	}
	.ascapp-tcards tbody td.is-actions::before { content: none; }
	.ascapp-tcards tbody td.is-actions .ascapp-actions { gap: 10px; }
	.ascapp-tcards tbody td.is-actions .ascapp-btn { flex: 1 1 auto; }
	.ascapp-tcards tbody td.is-actions form { display: block; width: 100%; }
	.ascapp-tcards tbody td.is-actions textarea { width: 100%; }
	/* The card IS the panel now — drop the wrapper's frame so they don't nest. */
	.ascapp-panel:has(> .ascapp-tcards),
	.ascapp-table-scroll:has(> .ascapp-tcards) {
		background: transparent;
		border: 0;
		box-shadow: none;
		overflow: visible;
	}
}

/* --- 20.10 Touch targets ---------------------------------------------
 * Everything tappable gets 44px of height on a touch-sized screen. The nav and
 * the user menu were 32–36px, and the footer links 18px.
 */
@media (max-width: 860px) {
	.ascapp-nav a {
		min-height: 44px;
		display: inline-flex;
		align-items: center;
		padding: 0 14px;
	}
	.ascapp-nav a.icon { padding: 0 12px; }
	.ascapp-mode { min-height: 40px; display: inline-flex; align-items: center; }
	.ascapp-user a,
	.ascapp-hello { min-height: 44px; display: inline-flex; align-items: center; }
	.ascapp-gear,
	.ascapp-theme-btn { width: 44px !important; height: 44px !important; }
	/* 44px as of v4.16.0. This block's own comment says the target is 44 and
	   then set the footer links to 24 — they measured 36px on a phone, and were
	   the last controls in the product under the standard. Found by measuring
	   the DOM on a screen the release did not otherwise touch. */
	.ascapp-foot a {
		display: inline-flex;
		align-items: center;
		padding: 0 4px;
		min-height: 44px;
	}
	/* Tapping the customer's number to call them is the whole point of showing
	   it on the Pickup Desk. */
	.ascapp td a[href^="tel:"] {
		display: inline-block;
		padding: 6px 0;
		min-height: 34px;
	}
	.ascapp-brand { min-height: 44px; }
	/* Space between a destructive control and the safe one beside it. */
	.ascapp-actions .ascapp-btn.danger { margin-left: auto; }
	.ascapp-tcards td.is-actions .ascapp-btn.danger { margin-left: 0; }
}

/* --- 20.11 Nav scroll affordance -------------------------------------
 * The nav scrolls sideways when it does not fit. Without an edge fade there is
 * nothing on screen to say so.
 */
.ascapp-nav { scroll-snap-type: x proximity; }
.ascapp-nav a { scroll-snap-align: start; }
@media (max-width: 1080px) {
	.ascapp-nav {
		-webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 22px), transparent 100%);
		mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 22px), transparent 100%);
	}
	.ascapp-nav.is-scrollend {
		-webkit-mask-image: none;
		mask-image: none;
	}
}

/* --- 20.12 Legibility -------------------------------------------------
 * 11.5px uppercase is below what reads comfortably on a phone held at arm's
 * length. Nudged up; the hierarchy is carried by weight and colour anyway.
 */
.ascapp thead th { font-size: 12px; }
.ascapp-card .lbl { font-size: 12.5px; }
@media (max-width: 860px) {
	.ascapp thead th { font-size: 12.5px; }
	.ascapp-card .lbl { font-size: 13px; line-height: 1.35; }
}

/* --- 20.13 Dashboard hierarchy ----------------------------------------
 * Same numbers, same links — but the statuses that need someone to act are
 * given the weight, and the archive counts step back.
 */
.ascapp-statgroup { margin-bottom: 22px; }
.ascapp-statgroup > h2 {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--muted);
	margin: 0 0 10px;
}
.ascapp-cards.is-primary .ascapp-card { padding: 18px 16px; }
.ascapp-cards.is-primary .ascapp-card .num { font-size: 34px; }
.ascapp-cards.is-secondary { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.ascapp-cards.is-secondary .ascapp-card { padding: 12px 14px; background: var(--card-2); }
.ascapp-cards.is-secondary .ascapp-card .num { font-size: 20px; }
.ascapp-cards.is-secondary .ascapp-card .lbl { font-size: 12px; }
@media (max-width: 860px) {
	.ascapp-cards.is-primary { grid-template-columns: repeat(2, 1fr); }
	.ascapp-cards.is-primary .ascapp-card .num { font-size: 27px; }
	.ascapp-cards.is-secondary { grid-template-columns: repeat(3, 1fr); }
	.ascapp-cards.is-secondary .ascapp-card .num { font-size: 17px; }
	.ascapp-cards.is-secondary .ascapp-card .lbl { font-size: 11.5px; }
}
@media (max-width: 420px) {
	.ascapp-cards.is-secondary { grid-template-columns: repeat(3, 1fr); }
}

/* --- 20.14 Status badges ---------------------------------------------
 * Ready and Work done used to be the same colour, which made the one screen
 * that shows both — the Pickup Desk — unreadable at a glance. Colour is never
 * the only signal: every badge already carries its own text.
 */
.ascapp-badge.ready {
	background: var(--ok-bg);
	color: var(--ok-ink);
	border-color: var(--ok-border);
}
.ascapp-badge.ready::before { background: var(--ok); }
.ascapp-badge.picked_up {
	background: var(--border-soft);
	color: var(--ink-2);
	border-color: var(--border);
}
.ascapp-badge.picked_up::before { background: var(--slate); }

/* --- 20.15 Print ------------------------------------------------------
 * The existing print block hides the chrome. These finish the job: no pagers,
 * no filter chips, no buttons, and rows that do not split across a page break.
 */
@media print {
	.ascapp-pager,
	.ascapp-chips,
	.ascapp-resultbar,
	.ascapp-skip,
	.ascapp-empty-actions,
	.ascapp-subnav,
	.ascapp-btn { display: none !important; }
	.ascapp-tcards tbody tr,
	.ascapp tbody tr { page-break-inside: avoid; }
	.ascapp-defs { page-break-inside: avoid; }
	.ascapp a { text-decoration: none; color: #000; }
}

/* --- 20.16 Screen-reader-only text -----------------------------------
 * Text that must be announced but not drawn: table captions, the name of an
 * icon-only control, the "remove this filter" wording behind a × glyph.
 */
.ascapp-sr {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* --- 20.17 Auth card heading -----------------------------------------
 * The sign-in / suspended / no-access cards now use a real <h1> where they had
 * a styled <div>, so the page has a heading and a screen reader announces what
 * it has landed on. Kept visually identical to the old subtitle.
 */
.ascapp-login h1.sub {
	font-size: 13.5px;
	font-weight: 600;
	line-height: 1.4;
	margin: 0 0 24px;
}

/* --- 20.18 The last few tap targets ----------------------------------
 * Found by measuring every screen at 360px rather than by reading the CSS:
 * a "back" link 20px tall, a phone number at 34px, and the de-emphasised
 * dashboard labels still under 12px.
 */
.ascapp-back {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	min-height: 40px;
	padding: 6px 0;
	color: var(--muted);
	font-size: 14px;
	text-decoration: none;
}
.ascapp-back:hover { color: var(--brand); }

@media (max-width: 860px) {
	.ascapp-back { min-height: 44px; }
	.ascapp td a[href^="tel:"] { min-height: 40px; padding: 9px 0; }
	.ascapp-cards.is-secondary .ascapp-card .lbl { font-size: 12px; }
}

/* A filter chip is a tap target — removing a filter is one of the most common
   things anyone does on a narrow screen. */
@media (max-width: 860px) {
	.ascapp-chip { min-height: 40px; padding: 8px 12px 8px 14px; }
}

/* --- 20.11 Narrow phones (360px) --------------------------------------
   360px is the most common Android width there is, and the app did not quite
   fit it. The greeting, the settings gear and the appearance switch together
   need 349px, and .ascapp-user was flex: 0 0 auto — so it refused to give any
   of that back and the page could be dragged 18px sideways on EVERY screen.

   Letting the cluster shrink and clipping the greeting harder costs nothing:
   "Good morning, Owner" was already ellipsised at 30ch, this makes it 12ch when
   there is no room. All three tap targets stay 44px.

   Pre-existing — v4.11.0 does the same thing. Found because the sweep harness
   was changed to probe whether the page ACTUALLY scrolls sideways rather than
   comparing body.scrollWidth, which had been hiding it. */
@media (max-width: 420px) {
	.ascapp-user { flex: 0 1 auto; min-width: 0; gap: 6px; }
	/* Two more icon buttons joined the cluster in v4.14.0 (notifications and
	   customers). At 360px the greeting is what has to give: My account is still
	   one tap away behind the gear, and clipping it to a couple of characters
	   would be worse than not showing it. */
	/* .ascapp-user a is (0,1,1) and would out-specify a bare .ascapp-hello. */
	.ascapp-user .ascapp-hello { display: none; }
}

/* --- 20.12 Switch rows -------------------------------------------------
   A checkbox is 13px square and nobody aims at it: the row is what gets
   tapped, and clicking a <label for> toggles the control. So the row is the
   control as far as a thumb is concerned, and it has to be 44px like every
   other target. These used to carry inline flex styles and came out 19px tall
   on a phone. */
.ascapp-switch {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 44px;
	cursor: pointer;
}
.ascapp-switch input[type="checkbox"] {
	width: auto;
	margin: 0;
	flex: 0 0 auto;
}

/* ---------------------------------------------------------------------
 * 21. v4.16.0 — the collapsible mobile menu, the centred dashboard, and
 *     the footer tap targets
 * ------------------------------------------------------------------- */

/* --- 21.1 The menu, collapsed on small screens ------------------------
   861px is the number, and it appears in exactly two places: here, and in the
   matchMedia() call in asc_app_nav_script(). Below it the section bar is a
   drop-down behind the button; above it, it is a bar.

   EVERY rule here is scoped to .asc-js. Without JavaScript the button is never
   shown and the bar is never hidden, so the menu behaves exactly as it did
   before — a menu that can only be opened by script must not be hideable by
   CSS alone. */
@media (max-width: 860px) {
	.asc-js .ascapp-navtoggle {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		flex: 0 0 auto;
		/* 44px, like every other control a thumb has to find. */
		width: 44px;
		height: 44px;
		margin-left: -6px;
		padding: 0;
		border: 1px solid var(--border);
		border-radius: 11px;
		background: var(--card);
		color: var(--ink-2);
		cursor: pointer;
	}
	.asc-js .ascapp-navtoggle:hover { color: var(--brand); border-color: var(--brand); }

	/* Collapsed. The bar keeps its place in the header when open, so the page
	   below is pushed down rather than covered — on a phone an overlay menu
	   that hides the page behind it is disorienting, and this one is short. */
	.asc-js .ascapp-bar-nav { display: none; }
	.asc-js .ascapp-bar-nav.is-open {
		display: block;
		padding: 8px 14px 12px;
	}

	/* Open, the menu is a LIST, not a sideways scroller. A row of chips you
	   have to swipe is fine as permanent furniture at the top of a screen and
	   wrong as a menu somebody just opened to find one thing. */
	.asc-js .ascapp-bar-nav.is-open .ascapp-nav {
		flex-direction: column;
		flex-wrap: nowrap;
		align-items: stretch;
		max-width: none;
		width: 100%;
		gap: 2px;
		overflow: visible;
	}
	.asc-js .ascapp-bar-nav.is-open .ascapp-nav a {
		display: flex;
		align-items: center;
		width: 100%;
		min-height: 44px;
		padding: 10px 14px;
		font-size: 15px;
	}
	/* Dashboard is an icon-only link. In a vertical list an unlabelled square
	   is a mystery, so the icon gets its accessible name shown beside it — the
	   name is already in aria-label; ::after prints the same word. */
	.asc-js .ascapp-bar-nav.is-open .ascapp-nav a.icon {
		justify-content: flex-start;
		gap: 10px;
		line-height: 1.2;
	}
	.asc-js .ascapp-bar-nav.is-open .ascapp-nav a.icon::after {
		content: none;
		font-weight: 600;
	}
}

/* --- 21.2 The centred dashboard ---------------------------------------
   Only the two dashboards — asc_app_shell_open() puts .is-dashboard on <main>
   for the 'home' and 'warranty' views and nothing else. A dashboard is a
   summary you take in at a glance, so centring it reads as deliberate; a list
   of tickets is a working surface, and centred rows of data are measurably
   harder to scan, so those stay left. */
.ascapp-main.is-dashboard { text-align: center; }

/* Text-align: center cascades into every cell of every card, which is what is
   wanted here — but the search field and the buttons need real centring, not
   inherited text alignment. */
.ascapp-main.is-dashboard .ascapp-search {
	margin-left: auto;
	margin-right: auto;
}
.ascapp-main.is-dashboard .ascapp-quick,
.ascapp-main.is-dashboard .ascapp-actions { justify-content: center; }
.ascapp-main.is-dashboard .ascapp-subnav { justify-content: center; }

/* The heading gets a little room above the cards now that nothing anchors it
   to the left edge. */
.ascapp-main.is-dashboard h1 { margin-bottom: 6px; }
.ascapp-main.is-dashboard .ascapp-statgroup > h2 { text-align: center; }

/* A notice is a sentence, and a centred paragraph of running text is harder to
   read than a left-aligned one. The card is centred; its contents are not. */
.ascapp-main.is-dashboard .ascapp-notice { text-align: left; }

/* The footer links were the last controls under the 44px standard. Fixed in
   §20.10 where the rest of the touch-target rules already live, rather than
   overridden from here — two rules disagreeing about one control is how the
   24px got there in the first place. */

/* ---------------------------------------------------------------------
 * 22. v4.17.0 — foldable sections, and two-column definition lists
 * ------------------------------------------------------------------- */

/* --- 22.1 Two-column details ------------------------------------------
   .ascapp-defs is a label/value grid, one pair per row. .is-2col puts TWO
   pairs on a row, which is what turns a thirteen-row ticket header into six.
   It steps down to one pair per row at 980px — two columns of a definition
   list stop being readable well before a phone, because each value column is
   then about twelve characters wide. Below 620px the existing rule takes over
   and stacks the label above the value. */
.ascapp-defs.is-2col { grid-template-columns: 150px minmax(0, 1fr) 150px minmax(0, 1fr); }
@media (max-width: 980px) {
	.ascapp-defs.is-2col { grid-template-columns: 190px minmax(0, 1fr); }
}
/* AND the phone step has to be repeated for .is-2col explicitly. The existing
   rule that stacks label above value is `.ascapp-defs { grid-template-columns:
   1fr }` at 620px — one class, so `.ascapp-defs.is-2col` out-specifies it and
   the ticket header kept a 190px label column against a 157px value column on
   a 375px screen. Measured, not guessed. */
@media (max-width: 620px) {
	.ascapp-defs.is-2col { grid-template-columns: 1fr; }
}

/* --- 22.2 Foldable sections -------------------------------------------
   A <details>, styled to read as a bar. No JavaScript is involved in opening
   one: the element does that itself, which is also why the keyboard and screen
   reader behaviour is right without any of it being written here. */
.ascapp-sec {
	margin-top: 14px;
	background: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--sh-1);
	overflow: hidden;
}

.ascapp-sec-head {
	display: flex;
	align-items: center;
	gap: 12px;
	/* 44px of height for a thumb, and the whole bar is the target — not just
	   the words in it. */
	min-height: 52px;
	padding: 12px 16px;
	cursor: pointer;
	font-weight: 700;
	font-size: 15px;
	color: var(--ink);
	/* The default disclosure triangle is replaced by the chevron below. Both
	   properties are needed: the first for everything modern, the second for
	   WebKit, which ignores it. */
	list-style: none;
	-webkit-tap-highlight-color: transparent;
}
.ascapp-sec-head::-webkit-details-marker { display: none; }
.ascapp-sec-head:hover { background: var(--border-soft); }

/* A real focus ring. The bar is a keyboard control and was previously a
   heading, so this is new behaviour that has to be visible. */
.ascapp-sec-head:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: -2px;
}

.ascapp-sec-title { flex: 0 1 auto; min-width: 0; }

/* THE POINT OF THE WHOLE RELEASE. The closed bar carries the fact somebody
   would have opened the section for, so folding hides the detail and not the
   information. It is allowed to wrap on a phone rather than being clipped. */
.ascapp-sec-meta {
	flex: 1 1 auto;
	min-width: 0;
	text-align: right;
	font-weight: 600;
	font-size: 13px;
	color: var(--muted);
}

.ascapp-sec-chev {
	flex: 0 0 auto;
	width: 9px;
	height: 9px;
	margin-right: 3px;
	border-right: 2px solid var(--muted);
	border-bottom: 2px solid var(--muted);
	transform: rotate(45deg);
	transition: transform var(--t);
}
.ascapp-sec[open] > .ascapp-sec-head > .ascapp-sec-chev { transform: rotate(-135deg); }
.ascapp-sec[open] > .ascapp-sec-head { border-bottom: 1px solid var(--border); }

.ascapp-sec-body { padding: 4px 16px 18px; }

/* The section supplies the frame now, so a panel inside one must not draw a
   second frame around itself — the money panel is a .ascapp-panel and would
   otherwise nest a card inside a card. */
.ascapp-sec-body > .ascapp-panel {
	border: 0;
	box-shadow: none;
	border-radius: 0;
	background: transparent;
	padding: 0 !important;
}
/* A heading as the first thing inside a section repeats the bar above it. */
.ascapp-sec-body > h2:first-child { margin-top: 4px; }

/* Destructive sections say so before they are opened. --err-ink / --err-border
   are the tokens the cancelled badge and the danger button already use, so this
   is the same red the rest of the product means "this closes it for good" with,
   and it flips correctly in dark mode without a second rule. */
.ascapp-sec.is-danger .ascapp-sec-head { color: var(--err-ink); }
.ascapp-sec.is-danger .ascapp-sec-meta { color: var(--err-ink); opacity: 0.85; }
.ascapp-sec.is-danger { border-color: var(--err-border); }
.ascapp-sec.is-danger .ascapp-sec-chev { border-color: var(--err-ink); }
.ascapp-sec.is-danger .ascapp-sec-head:hover { background: var(--err-bg); }

@media (max-width: 620px) {
	.ascapp-sec-head {
		flex-wrap: wrap;
		gap: 2px 10px;
		padding: 11px 14px;
	}
	/* On a phone the summary drops onto its own line under the title rather
	   than being squeezed to nothing beside it. */
	.ascapp-sec-title { flex: 1 1 auto; }
	.ascapp-sec-meta { flex: 1 1 100%; text-align: left; order: 3; }
	.ascapp-sec-chev { order: 2; margin-left: auto; }
	.ascapp-sec-body { padding: 4px 12px 16px; }
}

/* Printing. asc_app_section_script() opens every section before the dialog
   appears — a closed <details> prints nothing at all, and a printed ticket
   missing its history would be a silent regression. These rules only make the
   result look like a document rather than like a stack of controls. */
@media print {
	.ascapp-sec {
		border: 0;
		box-shadow: none;
		margin-top: 10px;
		page-break-inside: avoid;
	}
	.ascapp-sec-head {
		min-height: 0;
		padding: 0 0 4px;
		font-size: 14px;
		border-bottom: 1px solid #d0d5dd !important;
	}
	.ascapp-sec-chev { display: none; }
	.ascapp-sec-body { padding: 6px 0 0; }
	/* Nothing anybody can act on belongs on paper. */
	.ascapp-sec.is-danger { display: none !important; }
}

/* ---------------------------------------------------------------------
 * 23. v4.18.0 — a dashboard that reads as centred, and an arranged
 *     action row
 * ------------------------------------------------------------------- */

/* --- 23.1 The dashboard actually looking centred ----------------------
   v4.16.0 centred the dashboard and it measured perfectly symmetric — equal
   140px margins, every heading centred. It still did not LOOK centred, and the
   reason is that symmetry is not the same thing as being a centred object: the
   stat grids are `repeat(auto-fit, …, 1fr)`, so on a 1440px screen four cards
   stretched to 1,134px and hugged both edges. A row of cards spanning the whole
   window reads as a full-width layout no matter where its midpoint is.

   So the cards stop stretching and become a group with a width of its own,
   sitting in a column narrower than the page. Everything below 861px is
   untouched — this whole block is behind a min-width query — because on a
   phone the cards SHOULD fill the screen, and the existing 860px/420px rules
   set explicit column counts that a higher-specificity rule here would
   otherwise beat. */
@media (min-width: 861px) {
	/* One centred column for every top-level block on the dashboard. */
	.ascapp-main.is-dashboard > * {
		max-width: 940px;
		margin-left: auto;
		margin-right: auto;
	}
	/* The quick-search box keeps its own measure. The width cap above is one
	   class more specific than `.ascapp-search { max-width: 580px }`, so
	   without this line the search field grew to 940px — a search box you can
	   type a tracking ID into does not want to be that wide. Measured. */
	.ascapp-main.is-dashboard .ascapp-search { max-width: 580px; }

	/* Cards sized to their content, then centred as a group, instead of being
	   stretched to whatever width is going spare. */
	.ascapp-main.is-dashboard .ascapp-cards.is-primary {
		grid-template-columns: repeat(auto-fit, minmax(180px, 215px));
		justify-content: center;
	}
	.ascapp-main.is-dashboard .ascapp-cards.is-secondary {
		grid-template-columns: repeat(auto-fit, minmax(140px, 180px));
		justify-content: center;
	}

	/* --- 23.1b v4.23.0 — the dashboard that is also a working surface ------
	   The Warranty dashboard grew two lists (expiring soon, claims waiting) and
	   kept its table, and none of that fits a 940px reading column: the table
	   had five columns squeezed into it while 220px of page sat empty either
	   side. It keeps the centring — it is still a summary — and takes the
	   shell's own width, so it matches All Tickets instead of exceeding it.
	   One class more specific than the rule above, so no !important is needed. */
	.ascapp-main.is-dashboard.is-wide > * { max-width: 1160px; }
	.ascapp-main.is-dashboard.is-wide .ascapp-search { max-width: 580px; }
}

/* --- 23.1c The two-column band ----------------------------------------
   Two sections side by side on a wide screen, stacked on a narrow one, with no
   media query of its own: auto-fit with a 340px minimum does the collapse, and
   a rule that cannot be forgotten is better than one that can. `min-width: 0`
   on the children is what stops a wide table inside one column from pushing the
   grid past the page — the same fix section 5's table wrapper needed. */
.ascapp-band {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
	gap: 18px;
	align-items: start;
	margin: 22px 0 0;
}
.ascapp-band > section { min-width: 0; }
.ascapp-band h2 { margin-top: 0; }

/* --- 23.2 The page action bar -----------------------------------------
   Leaving on the left, doing on the right, and a real gap between the two so
   "Back" is not read as one more button in the row. Wraps on a phone with the
   actions dropping to their own line rather than being squeezed. */
.ascapp-pagebar {
	display: flex;
	align-items: center;
	gap: 10px 18px;
	flex-wrap: wrap;
	margin: 0 0 16px;
}
.ascapp-pagebar .ascapp-back { margin-right: auto; }
.ascapp-pagebar-actions {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
}
.ascapp-pagebar-actions form { margin: 0; }

@media (max-width: 620px) {
	/* The actions take the full width and share it evenly, so four small
	   buttons become two tidy rows instead of a ragged four. */
	.ascapp-pagebar-actions { flex: 1 1 100%; }
	.ascapp-pagebar-actions > * { flex: 1 1 calc(50% - 4px); }
	.ascapp-pagebar-actions .ascapp-btn { width: 100%; justify-content: center; }
}

/* --- 23.3 The note form -----------------------------------------------
   Writing comes before reading, so the form is the first thing in the Notes
   section. It is capped at a comfortable measure — a full-width textarea on a
   1440px screen is not a nicer place to type two sentences. */
.ascapp-noteform { max-width: 640px; margin: 4px 0 18px; }
.ascapp-noteform .ascapp-actions { margin-top: 10px; }

/* The list the "View notes" button jumps to. scroll-margin keeps the heading
   clear of the sticky top bar, which would otherwise cover the first row. */
#asc-notes-list { scroll-margin-top: 120px; }
#asc-notes-list:focus { outline: none; }

/* ---------------------------------------------------------------------
 * 24. v4.19.0 — "recorded so far", above the add-a-note box
 * ------------------------------------------------------------------- */

/* The repair-queue box became an ADD box, so what is already on the job has to
   be visible beside it — an empty box with the notes nowhere in sight would
   read as "the notes are gone". Deliberately quiet and capped in height: this
   is a reminder of what you wrote, not the place you read the whole history
   (that is the ticket page). It scrolls if a long job has accumulated a lot. */
.ascapp-notesofar {
	max-width: 320px;
	max-height: 96px;
	overflow-y: auto;
	margin: 0 0 6px;
	padding: 7px 9px;
	border-left: 3px solid var(--border);
	background: var(--card-2);
	border-radius: 0 8px 8px 0;
	font-size: 12.5px;
	line-height: 1.45;
	color: var(--ink-2);
}
.ascapp-notesofar-h {
	display: block;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--muted);
	margin-bottom: 2px;
}

/* In a phone card the row is already narrow — let it use the width it has. */
@media (max-width: 860px) {
	.ascapp-notesofar { max-width: none; }
}

/* ---------------------------------------------------------------------
 * v4.24.0 — the payment ledger and vendor claims.
 *
 * Deliberately small. Everything here reuses an existing component (the card
 * table, the pill, the stat card); these rules only colour the two things that
 * had no colour of their own: money going the wrong way, and a claim that is
 * late. The claim pills themselves are printed inline by asc_vclaim_css() for
 * the reason this project has learned repeatedly — a cache can serve a
 * stylesheet older than the control that needs it.
 * ------------------------------------------------------------------- */

/* A refund is the only negative number in the ledger, so it is the only one
 * that gets a colour. Everything else stays the body colour: colouring every
 * amount would make the one that matters disappear into the pattern. */
.ascapp-refund { color: #a3341f; }
.ascapp-taken  { color: inherit; }

/* The free-repair reason boxes are hidden by script when the discount is not
 * "free". Declared here so the hidden state survives a browser that applies
 * CSS before the inline script runs, and harmless where it never does. */
.asc-js [data-asc-freeonly][hidden] { display: none; }

/* v4.25.0 — the vendor-claim origin choice and the inline hand-off steps. */

/* A group label for a set of radios: the <span> that stands in for a <label>
 * when the control it names is several inputs rather than one. */
.ascapp-flabel {
	display: block;
	margin-bottom: 6px;
	font-weight: 600;
	font-size: 13px;
	color: var(--ink-2, #334155);
}

/* Keep the two customer choices together while retaining 44px tap targets.
 * Wrap on narrow screens instead of clipping either label. */
.ascapp-choices {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 2px 20px;
}
.ascapp-choices .ascapp-switch { white-space: nowrap; }

/* Each inline send/receive step inside a warranty claim is its own form, so
 * they need separating from one another or they read as one long form. */
.ascapp-wvc-step + .ascapp-wvc-step {
	margin-top: 6px;
}

/* v4.26.1 — the vendor product blocks, built to read like warranty intake. */
.ascapp-vp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ascapp-vp-mode { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.ascapp-vp-mode label { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; }
.ascapp-vp-block + .ascapp-vp-block { margin-top: 12px; }
.ascapp-vp-num { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.ascapp-vp-scanrow { display: flex; gap: 8px; align-items: center; }
.ascapp-vp-scanrow input { flex: 1 1 auto; min-width: 0; }
/* The single-item fields exist for a browser with no JavaScript. Where the
 * script runs, the blocks above already ask for all of it. */
.asc-js [data-asc-nojs] { display: none; }

/* ---------------------------------------------------------------------
 * 25. Online requests (v5.9.0)
 *
 * The module draws the same components as everything else — cards, badges,
 * a card-table, an empty state — so almost all it needs is its own accent per
 * status and the three small pieces that are genuinely new: the secondary line
 * inside a cell, the action form that lives in a table cell, and the fold that
 * holds a request's timeline.
 *
 * Every colour here is a token, so dark mode needs no block of its own.
 * ------------------------------------------------------------------- */

/* Dashboard card accents. Attention states are warm, the workshop states are
 * the product's own blues and violets, finished work is green, refused is red —
 * the same reading the ticket dashboard already teaches. */
.ascapp-c-o-all { --c: var(--brand); }
.ascapp-c-o-requested { --c: var(--warn); }
.ascapp-c-o-staff_on_way { --c: var(--info); }
.ascapp-c-o-picked_up { --c: var(--violet); }
.ascapp-c-o-under_repair { --c: var(--warn); }
.ascapp-c-o-ready { --c: var(--info); }
.ascapp-c-o-delivery_requested { --c: var(--violet); }
.ascapp-c-o-out_for_delivery { --c: var(--violet); }
.ascapp-c-o-collection_requested { --c: var(--info); }
.ascapp-c-o-delivered { --c: var(--ok); }
.ascapp-c-o-collected { --c: var(--ok); }
.ascapp-c-o-rejected { --c: var(--err); }

/* Status pills. Four tints, exactly as the ticket badges use four: waiting on
 * us, moving, done, refused. More than four and the colour stops meaning
 * anything. */
.ascapp-badge.o-requested,
.ascapp-badge.o-under_repair { background: var(--warn-bg); color: var(--warn-ink); border-color: var(--warn-border); }
.ascapp-badge.o-staff_on_way,
.ascapp-badge.o-picked_up,
.ascapp-badge.o-ready,
.ascapp-badge.o-delivery_requested,
.ascapp-badge.o-out_for_delivery,
.ascapp-badge.o-collection_requested { background: var(--brand-soft); color: var(--brand-soft-ink); border-color: var(--border); }
.ascapp-badge.o-delivered,
.ascapp-badge.o-collected { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-border); }
.ascapp-badge.o-rejected { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-border); }

/* A second line under the value in a cell: the phone under the name, the time
 * under the address. Block, so it never runs on and never needs a <br>. */
.ascapp-sub {
	display: block;
	margin-top: 3px;
	font-size: 12.5px;
	line-height: 1.45;
	color: var(--muted);
	overflow-wrap: anywhere;
}
.ascapp-sub a { color: inherit; }
.ascapp-sub a:hover { color: var(--brand); }

/* The accept / dispatch form, inside the actions cell. It carries a select and
 * sometimes a job card number, so it stacks rather than sitting on one line —
 * a row of controls squeezed into a table column is unusable on any screen. */
.ascapp-rowform {
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-width: 190px;
	margin: 0;
}
.ascapp-rowform .ascapp-field { margin: 0; }
.ascapp-rowform .ascapp-field label { font-size: 12px; margin-bottom: 3px; }
.ascapp-rowform .ascapp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.ascapp-rowform .ascapp-btn { flex: 1 1 auto; justify-content: center; }

/* The timeline fold. Closed by default: it is the answer to "what happened to
 * this one", which is a question asked about a single request, not about
 * twenty-five of them at once. */
.ascapp-timeline { margin-top: 6px; }
.ascapp-timeline > summary {
	cursor: pointer;
	font-size: 12.5px;
	font-weight: 650;
	color: var(--muted);
}
.ascapp-timeline > summary:hover { color: var(--brand); }
.ascapp-timeline ol {
	margin: 8px 0 0;
	padding: 0 0 0 14px;
	border-left: 2px solid var(--border);
	list-style: none;
	font-size: 12.5px;
	line-height: 1.5;
	font-weight: 400;
}
.ascapp-timeline li { margin-bottom: 7px; }
.ascapp-timeline li:last-child { margin-bottom: 0; }
.ascapp-timeline .t { color: var(--muted); }
.ascapp-timeline .n { display: block; color: var(--muted); }

/* The public link, which people read off the screen and type into a phone. */
.ascapp-online-url {
	margin: 0 0 6px;
	font-size: 14px;
	font-weight: 650;
	overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------
 * 26. Online requests: the dashboard banner and the menu badge (v5.9.2)
 *
 * The two places a shop finds out that somebody is waiting. Both say it in
 * words as well as in colour, because a red dot on its own is not a message.
 * ------------------------------------------------------------------- */

.ascapp-online-alert {
	display: flex;
	align-items: center;
	gap: 12px;
	margin: 0 0 18px;
	padding: 13px 16px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--card);
	box-shadow: var(--sh-1);
	color: inherit;
	text-decoration: none;
}
.ascapp-online-alert:hover { border-color: var(--brand); }
.ascapp-online-alert .txt { flex: 1 1 auto; min-width: 0; line-height: 1.4; }
.ascapp-online-alert .txt strong { font-weight: 700; }
.ascapp-online-alert .sub { color: var(--muted); font-size: 13px; }
.ascapp-online-alert .go {
	flex: 0 0 auto;
	align-self: center;
	padding: 7px 14px;
	border-radius: 9px;
	background: var(--border-soft);
	color: var(--ink-2);
	font-size: 13px;
	font-weight: 650;
	white-space: nowrap;
}

/* Something is waiting. */
.ascapp-online-alert.is-new {
	border-color: var(--err-border);
	background: var(--err-bg);
	color: var(--err-ink);
}
.ascapp-online-alert.is-new:hover { border-color: var(--err); }
.ascapp-online-alert.is-new .sub { color: inherit; opacity: 0.82; }
.ascapp-online-alert.is-new .go { background: var(--err); color: #fff; }
.ascapp-online-alert .dot {
	flex: 0 0 auto;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: var(--err);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--err) 22%, transparent);
}
@media (max-width: 520px) {
	.ascapp-online-alert { flex-wrap: wrap; }
	.ascapp-online-alert .go { width: 100%; text-align: center; }
}

/* The count in the section menu, so it is visible from every screen and not
 * only from the dashboard. */
.ascapp-nav a.has-badge { display: inline-flex; align-items: center; gap: 7px; }
.ascapp-navbadge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 19px;
	height: 19px;
	padding: 0 6px;
	border-radius: 999px;
	background: var(--err);
	color: #fff;
	font-size: 11.5px;
	font-weight: 750;
	line-height: 1;
}

/* The model year, beside the item on a request row. */
.ascapp-year {
	display: inline-block;
	margin-left: 6px;
	padding: 1px 7px;
	border: 1px solid var(--border);
	border-radius: 999px;
	background: var(--border-soft);
	color: var(--muted);
	font-size: 12px;
	font-weight: 650;
}

/* The Reject form is its own form (see asc_online_reject_form), so it needs a
 * little air under the accept form it now sits beneath. */
.ascapp-rowform.is-reject { margin-top: 8px; }

/* ---------------------------------------------------------------------
 * 27. Pickup staff list (v5.11.0)
 *
 * Two columns on a desktop, stacked on a phone. Plain repeated rows, because
 * the list works without JavaScript and a shop has five riders, not fifty.
 * ------------------------------------------------------------------- */

.ascapp-setshead {
	margin: 26px 0 4px;
	font-size: 15px;
	font-weight: 750;
	color: var(--ink);
}
.ascapp-stafflist { margin: 12px 0 6px; }
.ascapp-staffrow {
	display: grid;
	grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
	gap: 10px;
	margin-bottom: 8px;
}
.ascapp-staffrow.is-head {
	margin-bottom: 4px;
	font-size: 12px;
	font-weight: 650;
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
@media (max-width: 620px) {
	.ascapp-staffrow { grid-template-columns: 1fr; gap: 6px; margin-bottom: 14px; }
	.ascapp-staffrow.is-head { display: none; }
}

/* ---------------------------------------------------------------------------
 * v5.12.0 — the existing-customer line on an online request.
 *
 * One rule, because the rest of the block is ordinary .ascapp-sub text. The
 * duplicate-records warning is the only part that has to catch the eye: it
 * means the shop has two records on one number and somebody should merge them,
 * which is a job for a person and not something the product should silently
 * pick a winner for.
 * ------------------------------------------------------------------------ */
.ascapp-sub.is-warn { color: var(--warn-ink); font-weight: 600; }
