/* ============================================================
   Feedback Component — form + OTP verification modal
   Scoped under .fq-form and .fq-modal so nothing leaks globally.
   Reads design tokens from common.css (--primary-source, --text-*,
   --stroke-*, --natural-50). Buttons reuse .btn / .btn-primary /
   .btn-outline-primary defined in common.css.
   ============================================================ */

/* ---------- Form container ---------- */
.fq-form-wrap { max-width: 1280px; margin: 0 auto; }

.fq-form {
	background: #fff;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 12px;
	overflow: hidden;
}
.fq-form__body { padding: 24px 24px 16px; }
.fq-form__footer {
	background: var(--natural-50, #F8F9FA);
	border-top: 1px solid var(--stroke-200, #E5E7EB);
	padding: 16px 24px;
	display: flex;
	justify-content: flex-end;
}

/* Section header with trailing divider line */
.fq-form__section-title {
	display: flex;
	align-items: center;
	gap: 16px;
	color: var(--text-hint, #374151);
	font-size: 14px;
	font-weight: 500;
	margin: 8px 0 16px;
}
.fq-form__section-title::after {
	content: "";
	flex: 1 1 auto;
	height: 1px;
	background: var(--stroke-200, #E5E7EB);
}

/* Labels & required marker */
.fq-form .form-label {
	color: var(--text-dark, #1F2937);
	font-size: 14px;
	font-weight: 500;
	margin-bottom: 6px;
}
.fq-form .required { color: #EC5042; margin-left: 2px; }

/* Form controls */
.fq-form .form-control,
.fq-form .form-select {
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	padding: 10px 14px;
	font-size: 14px;
	color: var(--text-dark, #1F2937);
	background-color: #fff;
}
.fq-form .form-control::placeholder { color: #9CA3AF; }
.fq-form .form-control:focus,
.fq-form .form-select:focus {
	border-color: var(--primary-source, #0373DF);
	box-shadow: 0 0 0 4px rgba(3, 115, 223, 0.16);
}

/* Textarea + character counter */
.fq-form__textarea-wrap { position: relative; }
.fq-form__textarea-wrap textarea { min-height: 120px; resize: vertical; }
.fq-form__counter {
	position: absolute;
	right: 12px;
	bottom: -22px;
	font-size: 12px;
	color: var(--text-hint, #374151);
}

/* Upload card */
.fq-form__upload {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 16px;
	padding: 16px 20px;
	border: 1px solid var(--stroke-200, #E5E7EB) !important;
	border-radius: 8px !important;
	background: #FFFFFF !important;
}
.fq-form__upload-title { font-size: 14px; font-weight: 600; color: var(--text-dark, #1F2937); margin: 0; }
.fq-form__upload-hint  { font-size: 12px; color: var(--text-hint, #374151); margin: 2px 0 0; }
.fq-form__upload input[type="file"] { display: none; }

@media (max-width: 575.98px) {
	.fq-form__body { padding: 16px; }
	.fq-form__footer { padding: 12px 16px; }
	.fq-form__upload { flex-direction: column; align-items: flex-start; }
}


/* ============================================================
   OTP Verification Modal
   Custom overlay (no Bootstrap JS dependency).
   Show by adding `.is-open` on `.fq-modal-backdrop` (or via the
   provided window.fqOtpModal.show() / .hide()).
   ============================================================ */

.fq-modal-backdrop {
	position: fixed;
	inset: 0;
	background: rgba(17, 24, 39, 0.5);
	display: none;
	align-items: center;
	justify-content: center;
	padding: 16px;
	z-index: 1050;
}
.fq-modal-backdrop.is-open { display: flex; }

.fq-modal {
	background: #fff;
	border-radius: 16px;
	width: 100%;
	max-width: 480px;
	box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15), 0 6px 12px rgba(0, 0, 0, 0.08);
	overflow: hidden;
	animation: fqModalIn 180ms ease-out;
}
@keyframes fqModalIn {
	from { transform: translateY(8px) scale(0.98); opacity: 0; }
	to   { transform: none; opacity: 1; }
}

.fq-modal__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 20px 24px 8px;
}
.fq-modal__title {
	font-size: 18px;
	font-weight: 700;
	color: var(--text-dark, #1F2937);
	margin: 0;
}
.fq-modal__close {
	background: none;
	border: 0;
	padding: 4px;
	line-height: 1;
	cursor: pointer;
	color: var(--text-hint, #374151);
	border-radius: 6px;
}
.fq-modal__close:hover { background: var(--stroke-100, #F3F4F6); }
.fq-modal__close svg { display: block; width: 20px; height: 20px; }

.fq-modal__body { padding: 8px 24px 8px; text-align: center; }

.fq-otp__prompt {
	font-size: 14px;
	color: var(--text-dark, #1F2937);
	margin: 12px 0 20px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	flex-wrap: wrap;
	justify-content: center;
}
.fq-otp__phone { color: var(--primary-source, #0373DF); font-weight: 600; }
.fq-otp__edit {
	background: none;
	border: 0;
	padding: 2px;
	cursor: pointer;
	color: var(--text-hint, #374151);
	border-radius: 4px;
	display: inline-flex;
}
.fq-otp__edit:hover { background: var(--stroke-100, #F3F4F6); }
.fq-otp__edit svg { width: 16px; height: 16px; display: block; }

.fq-otp__inputs {
	display: flex;
	justify-content: center;
	gap: 8px;
	margin-bottom: 20px;
}
.fq-otp__inputs input {
	width: 44px;
	height: 44px;
	text-align: center;
	font-size: 18px;
	font-weight: 500;
	color: var(--text-dark, #1F2937);
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	background: #fff;
	-moz-appearance: textfield;
}
.fq-otp__inputs input::-webkit-outer-spin-button,
.fq-otp__inputs input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.fq-otp__inputs input:focus {
	outline: none;
	border-color: var(--primary-source, #0373DF);
	box-shadow: 0 0 0 4px rgba(3, 115, 223, 0.16);
}

.fq-otp__resend {
	font-size: 14px;
	color: var(--text-hint, #374151);
	margin: 0 0 8px;
}
.fq-otp__resend strong { color: var(--text-dark, #1F2937); font-weight: 700; }
.fq-otp__resend a {
	color: var(--primary-source, #0373DF);
	font-weight: 600;
	text-decoration: none;
	cursor: pointer;
}
.fq-otp__resend a:hover { text-decoration: underline; }

.fq-modal__footer {
	display: flex;
	gap: 12px;
	padding: 16px 24px 24px;
}
.fq-modal__footer .btn { flex: 1 1 0; }

@media (max-width: 480px) {
	.fq-otp__inputs input { width: 40px; height: 40px; font-size: 16px; }
	.fq-modal__header { padding: 16px 16px 8px; }
	.fq-modal__body { padding: 8px 16px; }
	.fq-modal__footer { padding: 16px; }
}


/* ============================================================
   Feedback Success / Confirmation screen
   Scoped under .fq-success — safe to render on any page.
   ============================================================ */

.fq-success { max-width: 1280px; margin: 0 auto; }

/* Green check icon (top center) */
.fq-success__icon {
	width: 96px;
	height: 96px;
	border-radius: 50%;
	background: #E0F2E9;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0 auto 16px;
}
.fq-success__icon svg { width: 44px; height: 44px; stroke: #059669; stroke-width: 3; fill: none; }

/* Title + lede */
.fq-success__title {
	text-align: center;
	color: #047857;
	font-size: 24px;
	font-weight: 700;
	margin: 0 0 8px;
}
.fq-success__lede {
	text-align: center;
	color: var(--text-hint, #374151);
	font-size: 14px;
	margin: 0 auto 20px;
	max-width: 900px;
}

/* Reference number card (green tinted) */
.fq-success__ref-card {
	border: 1px solid #A7F3D0;
	background: #ECFDF5;
	border-radius: 12px;
	padding: 20px 24px;
	margin-bottom: 16px;
}
.fq-success__ref-label {
	text-align: center;
	color: var(--text-hint, #374151);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	margin: 0 0 10px;
}
/*
 * Three columns with equal flexible sides, so the pill sits in the middle one
 * and stays put whether or not the "Copied!" badge is showing. text-align
 * centring alone meant the pill lurched sideways the moment the badge appeared
 * — a visible jolt at the exact instant the citizen clicks.
 */
.fq-success__ref-wrap {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	align-items: center;
	text-align: center;
}
.fq-success__ref-pill { grid-column: 2; }
.fq-success__ref-copied { grid-column: 3; justify-self: start; }
.fq-success__ref-pill {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	background: #FFFFFF;
	border: 1px solid #A7F3D0;
	border-radius: 8px;
	padding: 8px 14px;
	color: #003366;
	font-weight: 700;
	font-size: 18px;
	letter-spacing: 0.02em;
}
.fq-success__ref-copy {
	background: none;
	border: 0;
	padding: 2px;
	cursor: pointer;
	color: var(--text-hint, #374151);
	border-radius: 4px;
	display: inline-flex;
}
.fq-success__ref-copy:hover { background: var(--stroke-100, #F3F4F6); }
.fq-success__ref-copy svg { width: 16px; height: 16px; display: block; }
/*
 * The copy confirmation. It was rendering correctly but was easy to miss:
 * #059669 text on the card's mint #ECFDF5 measures a contrast ratio of 3.58,
 * below the 4.5 that small text needs to be legible, at 12px, for 1.5 seconds.
 * Green on green is the worst case for the people most likely to need the
 * confirmation. Now a badge with its own ground, a darker green, and a little
 * longer on screen.
 */
.fq-success__ref-copied {
	/*
	 * display:none, not opacity:0 — an invisible badge still occupies its width
	 * inside this centred wrapper, which pushed the reference pill permanently
	 * off-centre to make room for a message that is only on screen for two and
	 * a half seconds after a click.
	 */
	display: none;
	margin-left: 10px;
	padding: 3px 10px;
	border-radius: 999px;
	background: #D1FAE5;
	border: 1px solid #6EE7B7;
	color: #065F46;
	font-weight: 600;
	font-size: 13px;
	line-height: 1.4;
	white-space: nowrap;
	vertical-align: middle;
}

/* Faded in with an animation rather than a transition: a transition cannot
   animate an element that was display:none a moment ago. */
.fq-success__ref-copied.is-visible {
	display: inline-block;
	animation: fq-copied-in 150ms ease;
}

@keyframes fq-copied-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	.fq-success__ref-copied.is-visible { animation: none; }
}
.fq-success__ref-hint {
	text-align: center;
	color: var(--text-hint, #374151);
	font-size: 13px;
	margin: 10px 0 0;
}
.fq-success__ref-divider {
	border: 0;
	border-top: 1px solid #A7F3D0;
	margin: 16px 0;
}
.fq-success__ref-meta {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 16px;
	/* Centred to match the reference number and hint above it — the whole
	   card reads as one centred confirmation block rather than a centred
	   header sitting over a left-aligned footer. */
	text-align: center;
}
.fq-success__ref-meta-label { color: var(--text-hint, #374151); font-size: 12px; margin: 0 0 2px; }
.fq-success__ref-meta-value { color: var(--text-dark, #1F2937); font-size: 14px; font-weight: 500; margin: 0; }

/* "What Happens Next?" card */
.fq-success__next-card {
	position: relative;
	background: #FFFFFF;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 12px;
	padding: 20px 24px 20px 28px;
	margin-bottom: 20px;
	overflow: hidden;
}
.fq-success__next-card::before {
	content: "";
	position: absolute;
	left: 0; top: 0; bottom: 0;
	width: 4px;
	background: var(--primary-source, #0373DF);
	border-radius: 4px 0 0 4px;
}
.fq-success__next-title {
	color: var(--text-dark, #1F2937);
	font-size: 16px;
	font-weight: 700;
	margin: 0 0 16px;
}
.fq-success__next-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 12px;
}
.fq-success__next-item {
	display: flex;
	align-items: flex-start;
	gap: 12px;
}
.fq-success__next-icon {
	flex: 0 0 40px;
	width: 40px;
	height: 40px;
	background: var(--stroke-100, #F3F4F6);
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--text-dark, #1F2937);
}
.fq-success__next-icon svg { width: 20px; height: 20px; }
.fq-success__next-heading {
	color: var(--text-dark, #1F2937);
	font-size: 14px;
	font-weight: 600;
	margin: 0 0 2px;
}
.fq-success__next-text {
	color: var(--text-hint, #374151);
	font-size: 13px;
	margin: 0;
	line-height: 1.5;
}

/* Footer action bar */
.fq-success__actions {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 12px;
	margin-top: 20px;
}
.fq-success__actions .btn-back { display: inline-flex; align-items: center; gap: 8px; }
.fq-success__actions .btn-back svg { width: 16px; height: 16px; }

@media (max-width: 575.98px) {
	.fq-success__title { font-size: 20px; }
	.fq-success__ref-card { padding: 16px; }
	.fq-success__ref-meta { grid-template-columns: 1fr; }
	.fq-success__actions { flex-direction: column-reverse; align-items: stretch; }
	.fq-success__actions .btn { justify-content: center; }
}


/* ============================================================
   Grievance / Feedback Tracking screen
   Scoped under .fq-track — safe to render on any page.
   ============================================================ */

.fq-track { max-width: 1280px; margin: 0 auto; }

.fq-track__header {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 16px;
	margin-bottom: 20px;
}
.fq-track__title {
	color: var(--text-dark, #1F2937);
	font-size: 24px;
	font-weight: 700;
	margin: 0 0 4px;
}
.fq-track__subtitle {
	color: var(--text-hint, #374151);
	font-size: 14px;
	margin: 0;
}
/*
 * The "+ New Issue" action, shared by the tracking header and the confirmation
 * footer. One class so the same action cannot end up looking or reading
 * differently depending on which page a citizen reached it from — it was
 * "Add Another Issue" on one and "+ New Issue" on the other.
 */
.fq-new-issue { white-space: nowrap; }

.fq-track__card {
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 12px;
	padding: 20px 24px;
	background: #FFFFFF;
}

.fq-track__radios {
	display: flex;
	gap: 24px;
	margin-bottom: 16px;
}
.fq-track__radios .form-check-input:checked {
	background-color: var(--primary-source, #0373DF);
	border-color: var(--primary-source, #0373DF);
}

/*
 * White dot, not the theme's purple one.
 *
 * ux4g draws the checked radio's centre with a background-image SVG whose
 * circle is filled #613AF5. Against its own white background that reads fine,
 * but the rule above fills the control blue — leaving a purple dot on a blue
 * disc, two brand colours fighting inside an 18px circle. Same geometry as
 * ux4g's (r=35%), only the fill changes.
 */
.fq-track__radios .form-check-input:checked[type="radio"] {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='35%25' fill='%23fff'/%3E%3C/svg%3E");
}
.fq-track__radios .form-check-label {
	color: var(--text-dark, #1F2937);
	font-size: 14px;
	font-weight: 500;
	cursor: pointer;
}

.fq-track__row {
	display: flex;
	gap: 16px;
	align-items: stretch;
}
.fq-track__input {
	flex: 1 1 auto;
	max-width: 480px;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	padding: 10px 14px;
	font-size: 14px;
	color: var(--text-dark, #1F2937);
	background-color: #fff;
}
.fq-track__input:focus {
	outline: none;
	border-color: var(--primary-source, #0373DF);
	box-shadow: 0 0 0 4px rgba(3, 115, 223, 0.16);
}
.fq-track__btn { white-space: nowrap; }

@media (max-width: 575.98px) {
	.fq-track__header { flex-direction: column; align-items: stretch; }
	.fq-track__new { align-self: flex-end; }
	.fq-track__row { flex-direction: column; }
	.fq-track__input { max-width: none; }
	.fq-track__btn { width: 100%; }
}


/* ============================================================
   Grievance Tracking — Results panel (list of cases + details)
   Scoped under .fq-track-results.
   ============================================================ */

.fq-track-results {
	max-width: 1280px;
	margin: 20px auto 0;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 12px;
	overflow: hidden;
	background: #FFFFFF;
}

.fq-track-results__grid {
	display: grid;
	grid-template-columns: minmax(240px, 320px) 1fr;
	min-height: 480px;
	/* Cap the pair so a long list scrolls inside the panel rather than
	   stretching it down the page and leaving the detail stranded far above
	   the case the citizen is reading. */
	max-height: 720px;
}

/*
 * Two separate things have to be told they may shrink, or the cap above does
 * nothing and the list is simply clipped instead of scrolling.
 *
 *   grid-template-rows  — the single row is otherwise auto-sized to its tallest
 *                         child, so it grows past the max-height rather than
 *                         constraining anything.
 *   min-height: 0       — grid items default to min-height:auto, i.e. "never
 *                         shrink below my content", which overrides the row.
 */
.fq-track-results__grid { grid-template-rows: minmax(0, 1fr); }
.fq-track-results__grid > * { min-height: 0; }

/* Left column — list of case cards.

   Scrolls on its own: a citizen who has raised a dozen grievances would
   otherwise have to scroll the whole page past every card to reach the
   detail, and the selected card would drift out of sight while they read it. */
.fq-track-results__list {
	border-right: 1px solid var(--stroke-200, #E5E7EB);
	background: #FBFCFD;
	overflow-y: auto;
}

/* A restrained scrollbar — the default one is heavy against the tinted list. */
.fq-track-results__list { scrollbar-width: thin; scrollbar-color: var(--stroke-200, #E5E7EB) transparent; }
.fq-track-results__list::-webkit-scrollbar { width: 8px; }
.fq-track-results__list::-webkit-scrollbar-track { background: transparent; }
.fq-track-results__list::-webkit-scrollbar-thumb {
	background: #D1D5DB;
	border-radius: 999px;
	border: 2px solid #FBFCFD;
}
.fq-track-results__list::-webkit-scrollbar-thumb:hover { background: #9CA3AF; }

/* The detail scrolls independently too, so a long grievance does not push the
   list's scroll context around. */
.fq-track-results__detail { overflow-y: auto; }
.fq-track-case {
	padding: 16px 20px;
	border-bottom: 1px solid var(--stroke-200, #E5E7EB);
	cursor: pointer;
	transition: background-color 120ms ease;
}
.fq-track-case:last-child { border-bottom: 0; }
.fq-track-case:hover { background: var(--stroke-100, #F3F4F6); }
.fq-track-case.is-active {
	background: #FFFFFF;
	box-shadow: inset 3px 0 0 var(--primary-source, #0373DF);
}

.fq-track-case__badge {
	display: inline-block;
	padding: 2px 10px;
	border-radius: 999px;
	font-size: 11px;
	font-weight: 600;
	margin-bottom: 8px;
	line-height: 1.6;
}
.fq-track-case__badge.is-rejected { background: #FEE2E2; color: #DC2626; border: 1px solid #FCA5A5; }
.fq-track-case__badge.is-pending  { background: #FEF3C7; color: #B45309; border: 1px solid #FCD34D; }
.fq-track-case__badge.is-resolved { background: #D1FAE5; color: #047857; border: 1px solid #6EE7B7; }

.fq-track-case__ref {
	color: var(--text-dark, #1F2937);
	font-size: 14px;
	font-weight: 700;
	margin: 0 0 6px;
}
.fq-track-case__meta {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 2px;
}
.fq-track-case__meta li {
	display: flex;
	align-items: center;
	gap: 8px;
	color: var(--text-hint, #374151);
	font-size: 12px;
}
.fq-track-case__meta svg {
	width: 14px;
	height: 14px;
	flex: 0 0 auto;
	color: var(--text-hint, #374151);
}

/* Right column — details panel */
.fq-track-results__detail {
	padding: 24px 28px;
}
.fq-track-results__detail-title {
	color: var(--text-dark, #1F2937);
	font-size: 18px;
	font-weight: 700;
	margin: 0 0 20px;
}
.fq-track-results__section { margin-bottom: 20px; }
.fq-track-results__section:last-child { margin-bottom: 0; }
.fq-track-results__section-title {
	color: var(--primary-source, #0373DF);
	font-size: 15px;
	font-weight: 600;
	margin: 0 0 10px;
}

/* Description text box (neutral) */
.fq-track-results__description-box {
	border: 1px solid var(--stroke-200, #E5E7EB);
	background: #FBFCFD;
	border-radius: 8px;
	padding: 14px 16px;
	color: var(--text-hint, #374151);
	font-size: 13.5px;
	line-height: 1.6;
}

/* Resolution box — status-tinted */
.fq-track-results__resolution-box {
	display: flex;
	align-items: flex-start;
	gap: 14px;
	border-radius: 8px;
	padding: 14px 16px;
	font-size: 13.5px;
	line-height: 1.6;
	border: 1px solid var(--stroke-200, #E5E7EB);
	background: #FBFCFD;
	color: var(--text-hint, #374151);
}
.fq-track-results__resolution-box.is-rejected {
	background: #FEF2F2;
	border-color: #FECACA;
	color: #7F1D1D;
}
.fq-track-results__resolution-box.is-resolved {
	background: #ECFDF5;
	border-color: #A7F3D0;
	color: #065F46;
}
.fq-track-results__resolution-icon {
	flex: 0 0 36px;
	width: 36px; height: 36px;
	border-radius: 50%;
	background: #FFFFFF;
	display: flex; align-items: center; justify-content: center;
	color: inherit;
}
.fq-track-results__resolution-icon svg { width: 18px; height: 18px; }

.fq-track-results__actions {
	display: flex;
	justify-content: flex-end;
	margin-top: 12px;
}

/* Empty resolution — for pending state */
.fq-track-results__empty {
	color: var(--text-hint, #374151);
	font-size: 13px;
	font-style: italic;
}

/* ---------- Stacked layout: the list becomes an accordion ----------

   Side by side, the list and the detail are two columns. Stacked they are
   not, and treating them as one column each produced the mess this replaces:
   a 320px scroll box nested inside the page scroll, showing a card and a half
   with the next one cropped mid-line, and the detail for whichever case was
   selected sitting somewhere below it. Tapping a card changed something the
   citizen could not see, and reaching the detail meant dragging past an inner
   scroller that swallowed the gesture.

   placeDetail() in feedback.js moves the one detail panel to sit directly
   under the open card, so a case reads top to bottom: header, then its own
   detail, then the next case. No nested scrolling, and the thing you tapped
   is attached to the thing that opened. */
@media (max-width: 768px) {
	.fq-track-results__grid {
		grid-template-columns: 1fr;
		/* Both caps must go. Either one left standing re-creates the inner
		   scroller the accordion exists to remove. */
		max-height: none;
		min-height: 0;
		grid-template-rows: auto;
	}
	.fq-track-results__list {
		border-right: 0;
		max-height: none;
		overflow: visible;
	}

	/* The card is now a disclosure header, so it carries the affordance:
	   a chevron that turns when its case is open. */
	.fq-track-case {
		position: relative;
		padding: 14px 44px 14px 16px;
	}
	.fq-track-case::after {
		content: "";
		position: absolute;
		right: 18px;
		top: 22px;
		width: 8px;
		height: 8px;
		border-right: 2px solid var(--text-hint, #6B7280);
		border-bottom: 2px solid var(--text-hint, #6B7280);
		transform: rotate(45deg);
		transform-origin: center;
		transition: transform 160ms ease;
	}
	.fq-track-case.is-active::after {
		transform: rotate(-135deg);
		border-color: var(--primary-source, #0373DF);
	}
	.fq-track-case.is-active {
		/* No bottom border: the panel below is part of the same card now, and
		   a line between them reads as a separation that is not there. */
		border-bottom: 0;
		padding-bottom: 10px;
	}
	/* The open card's summary line repeats, word for word and immediately
	   above, what the panel below states with labels — the same date, portal
	   and category twice in two different formats within one screen. The
	   labelled version is the better of the two, so the summary steps aside
	   while the case is open. Collapsed cards keep theirs: it is the only
	   thing distinguishing one from another. */
	.fq-track-case.is-active .fq-track-case__meta { display: none; }
	.fq-track-case.is-active .fq-track-case__ref { margin-bottom: 0; }

	/* The open panel, indented under its header and closed off underneath. */
	.fq-track-results__detail {
		overflow-y: visible;
		padding: 4px 16px 20px;
		background: #FFFFFF;
		border-bottom: 1px solid var(--stroke-200, #E5E7EB);
		box-shadow: inset 3px 0 0 var(--primary-source, #0373DF);
	}
	.fq-track-results__detail-head { margin-bottom: 4px; }

	/* Its own reference and badge repeat the card directly above it. */
	.fq-track-results__detail .fq-track-results__detail-ref,
	.fq-track-results__detail > .fq-track-results__detail-head > .fq-track-case__badge {
		display: none;
	}

	/* A long portal name is the common case here, not the exception —
	   "NCSC — National Commission for Scheduled Castes" has to wrap, and the
	   icon has to stay on the first line rather than centring against three. */
	.fq-track-case__meta li { align-items: flex-start; }
	.fq-track-case__meta svg { margin-top: 3px; }
	.fq-track-case__meta li span { min-width: 0; overflow-wrap: anywhere; }
}

/* ============================================================
   STATES — alerts, busy buttons, skeletons, honeypot
   The static design had none of these: no loading, error or
   empty state existed, because nothing could fail yet. Colours
   reuse the badge palette above so a warning banner and a
   "Pending" badge read as the same system.
   ============================================================ */

/* ---------- Alert banners ---------- */
.fq-alert {
	border-radius: 8px;
	padding: 12px 16px;
	font-size: 14px;
	line-height: 1.5;
	margin: 0 0 16px;
	border: 1px solid transparent;
}
.fq-alert:last-child { margin-bottom: 0; }

.fq-alert.is-error   { background: #FEE2E2; color: #991B1B; border-color: #FCA5A5; }
.fq-alert.is-warning { background: #FEF3C7; color: #92400E; border-color: #FCD34D; }
.fq-alert.is-info    { background: #DBEAFE; color: #1E40AF; border-color: #93C5FD; }

.fq-alert a { color: inherit; text-decoration: underline; }

/* Footer alert sits to the left of the submit button and takes the slack. */
.fq-form__footer { gap: 16px; }
.fq-form__alert  { flex: 1 1 auto; }
.fq-form__alert:empty { display: none; }

.fq-track__alert:empty { display: none; }
.fq-track__alert { margin-top: 16px; }

/* ---------- Busy buttons ---------- */
.btn.is-busy {
	position: relative;
	opacity: .75;
	cursor: progress;
}
.btn.is-busy::after {
	content: "";
	display: inline-block;
	width: 12px;
	height: 12px;
	margin-left: 8px;
	vertical-align: -1px;
	border: 2px solid currentColor;
	border-right-color: transparent;
	border-radius: 50%;
	animation: fq-spin .6s linear infinite;
}

@keyframes fq-spin { to { transform: rotate(360deg); } }

/* A citizen who has asked not to see motion still needs to know it is working,
   so the spinner stops rather than disappearing. */
@media (prefers-reduced-motion: reduce) {
	.btn.is-busy::after { animation: none; }
}

/* ---------- OTP modal error ---------- */
.fq-otp__error {
	margin: 12px 0 0;
	padding: 10px 12px;
	border-radius: 6px;
	background: #FEE2E2;
	border: 1px solid #FCA5A5;
	color: #991B1B;
	font-size: 13px;
	line-height: 1.45;
	text-align: center;
}

/* ---------- Disabled controls ---------- */
.fq-form .form-select:disabled,
.fq-form .form-control:disabled {
	background: var(--stroke-100, #F3F4F6);
	color: var(--text-hint, #6B7280);
	cursor: not-allowed;
}

/* ---------- Tracking results: loading skeleton ---------- */
.fq-track-results__loading { padding: 8px; }
.fq-track-results__loading span {
	display: block;
	height: 92px;
	margin-bottom: 12px;
	border-radius: 8px;
	background: linear-gradient(90deg, #F3F4F6 25%, #E5E7EB 37%, #F3F4F6 63%);
	background-size: 400% 100%;
	animation: fq-shimmer 1.4s ease infinite;
}
.fq-track-results__loading span:last-child { margin-bottom: 0; }

@keyframes fq-shimmer {
	0%   { background-position: 100% 50%; }
	100% { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
	.fq-track-results__loading span { animation: none; }
}

/* ---------- Honeypot ----------
   Off-screen rather than display:none. A bot that filters on the latter skips
   the field and sails through; this one is still "visible" to it. Kept out of
   the tab order and hidden from assistive tech at the markup level. */
.fq-form__hp {
	position: absolute !important;
	left: -9999px !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Tracking: the mobile field is revealed only when a Reference ID was entered,
   since that is the only case where the OTP has nowhere else to go. */
.fq-track__extra {
	margin-top: 20px;
	padding-top: 20px;
	border-top: 1px solid var(--stroke-200, #E5E7EB);
	max-width: 480px;
	animation: fq-reveal .18s ease;
}
.fq-track__extra .form-label {
	display: block;
	margin-bottom: 6px;
	font-size: 14px;
	font-weight: 500;
	color: var(--text-dark, #1F2937);
}
.fq-track__extra .fq-track__input { width: 100%; max-width: 100%; }

@keyframes fq-reveal {
	from { opacity: 0; transform: translateY(-4px); }
	to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	.fq-track__extra { animation: none; }
}

.fq-track__hint {
	margin: 8px 0 0;
	font-size: 13px;
	color: var(--text-hint, #6B7280);
}

@media (max-width: 767px) {
	.fq-track__row { flex-wrap: wrap; }
	.fq-track__row .fq-track__input { max-width: 100%; flex-basis: 100%; }
	.fq-track__btn { width: 100%; }
}

/* ============================================================
   TRACKING DETAIL — the statuses and sections the original
   three-badge design did not cover.
   ============================================================ */

/* The upstream vocabulary is Pending / In Progress / Resolved / Rejected /
   Returned. The design drew only three, so a case sitting In Progress or
   Returned had no badge at all — which is how a bare status code ended up
   rendered where a label belonged. */
.fq-track-case__badge.is-progress { background: #DBEAFE; color: #1E40AF; border: 1px solid #93C5FD; }
.fq-track-case__badge.is-returned { background: #EDE9FE; color: #5B21B6; border: 1px solid #C4B5FD; }

.fq-track-results__detail-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 20px;
}
.fq-track-results__detail-head .fq-track-results__detail-title { margin-bottom: 4px; }

.fq-track-results__detail-ref {
	margin: 0;
	font-size: 14px;
	font-weight: 600;
	color: var(--text-hint, #6B7280);
	letter-spacing: .01em;
}

/* Two columns on desktop, stacked on narrow screens. */
.fq-track-results__meta {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 8px 20px;
	margin: 0 0 24px;
	padding: 16px 18px;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	background: #F9FAFB;
}
.fq-track-results__meta dt {
	margin: 0;
	font-size: 13px;
	font-weight: 500;
	color: var(--text-hint, #6B7280);
}
.fq-track-results__meta dd {
	margin: 0;
	font-size: 14px;
	color: var(--text-dark, #1F2937);
	word-break: break-word;
}

/* Attachments, grouped under who attached them. The outer box spaces the
   groups; each group's own list spaces its rows more tightly, so the blocks
   read as blocks. See renderDocs() in feedback.js. */
.fq-track-results__docs {
	display: flex;
	flex-direction: column;
	gap: 18px;
}
.fq-track-results__doc-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

/* Subordinate to the blue "Attachments" title above it, and deliberately not
   blue itself: the Preview and Download links in every row are blue, and a
   blue heading sitting among them reads as one more link. */
.fq-track-results__doc-group-title {
	margin: 0 0 8px;
	/* Size and colour are restated in the typography guard further down,
	   where they need !important to beat the theme's global h4. Kept in step
	   with that block so reading either one tells the truth. */
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #667085;
}
.fq-track-results__doc {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 6px 16px;
	padding: 10px 14px;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	background: #F9FAFB;
	font-size: 14px;
}
/* Takes the slack so the badge, date and actions sit together on the right
   instead of being spread across the row by space-between. */
.fq-track-results__doc-name {
	color: var(--text-dark, #1F2937);
	overflow-wrap: anywhere;
	flex: 1 1 auto;
	min-width: 0;
}
.fq-track-results__doc-meta { color: var(--text-hint, #6B7280); font-size: 13px; white-space: nowrap; }


.fq-track-results__doc-actions {
	display: flex;
	align-items: baseline;
	gap: 14px;
	flex: 0 0 auto;
}
.fq-track-results__doc-action {
	font-size: 13px;
	font-weight: 600;
	color: var(--primary-source, #0373DF);
	text-decoration: none;
	white-space: nowrap;
}
.fq-track-results__doc-action:hover,
.fq-track-results__doc-action:focus-visible { text-decoration: underline; }

/* A refresh that failed. Error colours, not warning ones — the citizen asked
   for a file and did not get it. */
.fq-track-results__doc-error {
	margin: 10px 0 0;
	font-size: 13px;
	/* The same red as the inline field errors, so one failure does not look
	   like a different class of problem from another. */
	color: #B91C1C;
}
.fq-track-results__doc-error:empty { display: none; }

/* Attachment rows on a phone: the filename takes a line, the date and the
   actions share the one below it.

   The break is pinned with flex: 0 0 100% rather than left to flex-basis,
   because basis alone still lets a SHORT filename pull the next item up onto
   its line — which made every row wrap at a different point and the block read
   as ragged. This must come after the base .fq-track-results__doc-* rules
   above: the specificity is identical, so source order is what decides. */
@media (max-width: 768px) {
	.fq-track-results__doc { gap: 6px 12px; }
	.fq-track-results__doc-name { flex: 0 0 100%; }
	.fq-track-results__doc-actions { margin-left: auto; }
	.fq-track-results__docs { gap: 16px; }
}



@media (max-width: 767px) {
	.fq-track-results__meta { grid-template-columns: 1fr; gap: 2px; }
	.fq-track-results__meta dd { margin-bottom: 10px; }
	.fq-track-results__detail-head { flex-direction: column; }
}

/* ============================================================
   TYPOGRAPHY GUARD

   Every heading in this component was rendering at the theme's
   global heading size rather than the one designed here: the
   page title at 40px instead of 24px, "Issue Details" at 32px
   instead of 18px, the section headings at 28px instead of 15px,
   and each of them at weight 500 rather than 700/600.

   Two stylesheets cause it. Elementor's kit writes
   `.elementor-kit-6 h2 { font-size: 32px; font-weight: 500 }`,
   which at (0,1,1) outranks a single component class; and
   ux4gCustom.css sets the h1/h2/h3 sizes with `!important`,
   which no amount of specificity can beat.

   So the component's own type scale is restated here, scoped to
   the feedback roots and marked !important — matching what the
   theme itself already does to these tags. Nothing outside this
   feature is touched.
   ============================================================ */

.fq-track .fq-track__title,
.fq-success .fq-success__title,
.fq-success .fq-success__next-title,
.fq-track-results .fq-track-results__detail-title,
.fq-track-results .fq-track-results__section-title,
.fq-track-results .fq-track-results__doc-group-title,
.fq-modal .fq-modal__title {
	font-family: inherit;
	line-height: 1.35;
}

.fq-track .fq-track__title {
	font-size: 24px !important;
	font-weight: 700 !important;
	color: var(--text-dark, #1F2937);
}

.fq-success .fq-success__title {
	font-size: 24px !important;
	font-weight: 700 !important;
	color: #047857;
}

.fq-success .fq-success__next-title {
	font-size: 16px !important;
	font-weight: 700 !important;
	color: var(--text-dark, #1F2937);
}

.fq-track-results .fq-track-results__detail-title {
	font-size: 18px !important;
	font-weight: 700 !important;
	color: var(--text-dark, #1F2937);
}

.fq-track-results .fq-track-results__section-title {
	font-size: 15px !important;
	font-weight: 600 !important;
	color: var(--primary-source, #0373DF);
}

.fq-modal .fq-modal__title {
	font-size: 18px !important;
	font-weight: 700 !important;
	color: var(--text-dark, #1F2937);
}

/* The attachment group headings are <h4>, so the same thing happened to them:
   they rendered LARGER than the blue "Attachments" heading they sit under,
   which inverted the hierarchy — the group read as the section and the section
   as a label. Restated here for the same reason as everything above it. */
.fq-track-results .fq-track-results__doc-group-title {
	font-size: 10px !important;
	font-weight: 700 !important;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	/*
	 * A literal, not var(--text-hint, ...). --text-hint IS defined in
	 * common.css as #374151, so the fallback beside it never applied and the
	 * heading kept rendering at the same dark grey as the body text.
	 *
	 * #878f9f was the intended shade but measures 3.25:1 on white — under the
	 * 4.5:1 AA needs at this size, since 10px bold is not "large text". This
	 * is the nearest lighter grey that clears it, at 4.97:1.
	 */
	color: #667085;
}

/* ============================================================
   ATTACHMENTS — the chosen files, before they are uploaded

   The API takes one file per request and allows five per case,
   so the citizen builds a list here and feedback.js sends them
   in sequence once the OTP is verified. Files are held in JS
   rather than in the input, because a FileList cannot be edited
   and a second pick would otherwise replace the first.
   ============================================================ */

.fq-form__files {
	list-style: none;
	margin: 12px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.fq-form__file {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 14px;
	border: 1px solid var(--stroke-200, #E5E7EB);
	border-radius: 8px;
	background: #F9FAFB;
	font-size: 14px;
}

.fq-form__file-name {
	flex: 1 1 auto;
	color: var(--text-dark, #1F2937);
	overflow-wrap: anywhere;
}

.fq-form__file-size {
	flex: 0 0 auto;
	font-size: 13px;
	color: var(--text-hint, #6B7280);
	white-space: nowrap;
}

/* A real button, not an icon-only div: it needs to be reachable by keyboard
   and to announce which file it removes. */
.fq-form__file-remove {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	line-height: 1;
	font-size: 18px;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--text-hint, #6B7280);
	cursor: pointer;
}
.fq-form__file-remove:hover,
.fq-form__file-remove:focus-visible {
	background: #FEE2E2;
	color: #DC2626;
	outline: none;
}

@media (max-width: 575px) {
	.fq-form__file { flex-wrap: wrap; }
	.fq-form__file-name { flex-basis: 100%; }
}

/* ============================================================
   ICON BUTTON GUARD

   Elementor's kit styles EVERY button:

     .elementor-kit-6 button { border:1px solid; padding:9px 16px;
                               border-radius:8px; line-height:20px;
                               font-size:14px }

   At (0,1,1) that outranks a single component class, so each of
   this feature's icon buttons was drawn as a bordered, rounded
   rectangle with 16px of side padding forced into a 24px box —
   which is why the file-remove "x" sat squashed in a corner of a
   blue-outlined pill instead of centred in a circle, and why the
   modal close and edit-phone controls were 52x38 and 48x34
   rather than square.

   These selectors are two classes deep, which beats it without
   needing !important. Padding, border, radius and line-height
   are all restated because each one was being overridden.
   ============================================================ */

.fq-form__files .fq-form__file-remove,
.fq-modal .fq-modal__close,
.fq-otp__prompt .fq-otp__edit,
.fq-success__ref-pill .fq-success__ref-copy {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	padding: 0;
	border: 0;
	background: transparent;
	line-height: 1;
	cursor: pointer;
	transition: background-color .15s ease, color .15s ease;
}

.fq-form__files .fq-form__file-remove {
	width: 28px;
	height: 28px;
	border-radius: 50%;
	font-size: 20px;
	color: var(--text-hint, #6B7280);
}
.fq-form__files .fq-form__file-remove:hover,
.fq-form__files .fq-form__file-remove:focus-visible {
	background: #FEE2E2;
	color: #DC2626;
	outline: none;
}

.fq-modal .fq-modal__close {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	color: var(--text-hint, #6B7280);
}
.fq-modal .fq-modal__close:hover,
.fq-modal .fq-modal__close:focus-visible {
	background: var(--stroke-100, #F3F4F6);
	outline: none;
}
.fq-modal .fq-modal__close svg { width: 18px; height: 18px; }

.fq-otp__prompt .fq-otp__edit {
	width: 24px;
	height: 24px;
	border-radius: 50%;
	color: var(--primary-source, #0373DF);
}
.fq-otp__prompt .fq-otp__edit:hover,
.fq-otp__prompt .fq-otp__edit:focus-visible {
	background: #F0F7FF;
	outline: none;
}
.fq-otp__prompt .fq-otp__edit svg { width: 14px; height: 14px; }

.fq-success__ref-pill .fq-success__ref-copy {
	width: 28px;
	height: 28px;
	border-radius: 50%;
	color: var(--primary-source, #0373DF);
}
.fq-success__ref-pill .fq-success__ref-copy:hover,
.fq-success__ref-pill .fq-success__ref-copy:focus-visible {
	background: #F0F7FF;
	outline: none;
}
.fq-success__ref-pill .fq-success__ref-copy svg { width: 16px; height: 16px; }

/* ------------------------------------------------------------
   Page title

   The submission page prints its title from the template rather
   than from a template part, so it had no component class and
   took the theme's 40px/500 h1 — against the 24px/700 used by
   the tracking and confirmation pages. Same scale for all four.

   !important for the same reason as the other headings:
   ux4gCustom.css sets the h1 size with !important, which
   specificity alone cannot beat.
   ------------------------------------------------------------ */
.fq-page-title {
	font-size: 24px !important;
	font-weight: 700 !important;
	line-height: 1.35;
	color: var(--text-dark, #1F2937);
}

/* Character counter: silent until the limit is actually exceeded. */
.fq-form__counter.is-over { color: #DC2626; font-weight: 700; }

/* Full-width notice shown INSTEAD of the results grid.

   An expired verification or an empty result has nothing for either column,
   so the grid is hidden entirely rather than left standing empty beside a
   message squeezed into the narrow list strip. */
.fq-track-results__notice { padding: 24px 28px; }
.fq-track-results__notice .fq-alert { margin: 0; }

@media (max-width: 767px) {
	.fq-track-results__notice { padding: 18px 20px; }
}

/* ============================================================
   INLINE FIELD ERRORS

   Replaces the browser's native validation bubble, which shows
   one field at a time and renders in the browser's UI language
   rather than the page's.

   Mirrors the pattern the SMILE consent forms already use
   (page-template/smile-consent-form.php), in this feature's own
   namespace. Bootstrap's .is-invalid / .invalid-feedback are
   loaded site-wide but deliberately not used: .is-invalid injects
   a background SVG icon and bumps padding-right, which changes
   the control's shape.
   ============================================================ */

/*
 * Make the resting border the same on every control in this feature.
 *
 * common.css sets `.form-control { border: 1px solid var(--input-border-color)
 * !important }` site-wide. That matches inputs and textareas but NOT
 * .form-select, so the text fields were rendering at #C0BEBE while the two
 * dropdowns beside them kept the component's own #E5E7EB — visibly darker
 * boxes next to lighter ones on the same row.
 *
 * Restated here with !important to match, scoped to this feature's own roots.
 * common.css is left alone: it is loaded on every page of the site and the
 * inconsistency is only a problem where the two control types sit together.
 */
.fq-form .form-control,
.fq-form .form-select,
.fq-track .form-control {
	border: 1px solid var(--stroke-200, #E5E7EB) !important;
}

/*
 * !important again, for the same reason: an !important shorthand beats a plain
 * border-color at any specificity, so without it the field kept its ordinary
 * border and only the message below turned red.
 */
.fq-form .fq-field-error,
.fq-form .fq-field-error:hover,
.fq-track .fq-field-error,
.fq-track .fq-field-error:hover {
	border-color: #DC2626 !important;
}

/* Also beats the blue focus ring — .fq-track__input carries its own at
   feedback-component.css:497-501, separate from the form's. While a field is
   still wrong, focusing it should not make it look resolved. */
.fq-form .fq-field-error:focus,
.fq-track .fq-field-error:focus {
	border-color: #DC2626 !important;
	box-shadow: 0 0 0 4px rgba(220, 38, 38, .16);
	outline: none;
}

.fq-field-error-msg {
	display: block;
	margin: 6px 0 0;
	font-size: 13px;
	line-height: 1.45;
	color: #B91C1C;
}

/*
 * The description's counter is absolutely positioned 22px below its textarea
 * (.fq-form__counter), so a message in the normal flow lands on top of it.
 * This clears that space. The counter sits right-aligned, the message left, so
 * the two coexist on the same line rather than stacking.
 */
.fq-field-error-msg.is-below-counter {
	margin-top: 24px;
	padding-right: 90px;
}

/* Upload problems sit under the upload block they describe. */
.fq-form__upload-error { margin-top: 12px; }
.fq-form__upload-error:empty { display: none; }
.fq-form__upload-error .fq-alert { margin: 0; }
