/* Shared components — Academic Destination Nepal
 *
 * The pieces every page reuses, defined once. Built on the tokens in
 * tokens.css, and usable from both halves of this codebase: the 96 templates
 * written in Tailwind utilities, and the 14 ERP pages written in inline
 * styles. A component here is the one place a button's height, a field's
 * label spacing or an empty state's shape is decided.
 *
 * Why this exists: before it, each page invented its own. That is how the
 * platform ended up with eight font families and with violet, purple and
 * indigo all meaning "primary" depending on which page you were looking at.
 *
 * Rules for adding to this file:
 *   - No new colour literals. Use a token, or add one to tokens.css.
 *   - Every interactive element is at least 44px tall (WCAG 2.5.8, and a
 *     thumb on a phone).
 *   - Never remove a focus ring. a11y.css owns focus and loads after this.
 *
 * Loaded after tokens.css and before a11y.css.
 */

/* ---- Buttons ---------------------------------------------------------- */

.adn-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 20px;
    border: 1px solid transparent;
    border-radius: 12px;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 700;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}

.adn-btn:disabled,
.adn-btn[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
}

.adn-btn--primary {
    background: #4f46e5;
    color: #ffffff;
}
.adn-btn--primary:hover:not(:disabled) { background: #4338ca; }

.adn-btn--secondary {
    background: transparent;
    color: #4f46e5;
    border-color: #c7d2fe;
}
.adn-btn--secondary:hover:not(:disabled) { background: #eef2ff; }

.adn-btn--ghost {
    background: transparent;
    color: #475569;
}
.adn-btn--ghost:hover:not(:disabled) { background: #f1f5f9; }

/* Destructive is deliberately not red-by-default at rest: a row of red
 * buttons stops reading as danger. It commits to red on hover, when the
 * pointer is already on it. */
.adn-btn--danger {
    background: #fff1f2;
    color: #be123c;
    border-color: #fecdd3;
}
.adn-btn--danger:hover:not(:disabled) {
    background: #e11d48;
    color: #ffffff;
    border-color: #e11d48;
}

.adn-btn--block { width: 100%; }

/* ---- Form fields ------------------------------------------------------ */

/* The label is part of the component, not an optional extra. 338 of 398
 * controls in this codebase have no programmatic label; using .adn-field
 * makes the correct thing the easy thing. */
.adn-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 16px;
}

.adn-field__label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #334155;
}

.adn-field__label[data-required]::after {
    content: " *";
    color: #e11d48;
}

.adn-field__input,
.adn-field__select,
.adn-field__textarea {
    min-height: 44px;
    padding: 10px 12px;
    border: 1px solid #cbd5e1;
    border-radius: 10px;
    background: #ffffff;
    color: #0f172a;
    font-family: inherit;
    font-size: 0.9375rem;
    width: 100%;
}

.adn-field__textarea { min-height: 96px; resize: vertical; }

/* Never colour alone: 1.4.1 means the error must be readable to somebody who
 * cannot distinguish the border from the default one. The message carries it. */
.adn-field__input[aria-invalid="true"],
.adn-field__select[aria-invalid="true"],
.adn-field__textarea[aria-invalid="true"] {
    border-color: #e11d48;
}

.adn-field__hint  { font-size: 0.75rem; color: #64748b; }
.adn-field__error { font-size: 0.75rem; color: #be123c; font-weight: 600; }

/* ---- Card ------------------------------------------------------------- */

.adn-card {
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 16px;
    padding: 20px;
}

.adn-card__title {
    font-size: 1rem;
    font-weight: 700;
    color: #0f172a;
    margin: 0 0 4px;
}

.adn-card__meta { font-size: 0.8125rem; color: #64748b; }

/* ---- Badge ------------------------------------------------------------ */

/* Fixed meanings. These were used interchangeably across pages, which is
 * worse than using them badly - a colour that means three things means
 * nothing. */
.adn-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    border: 1px solid transparent;
    white-space: nowrap;
}

.adn-badge--ok      { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.adn-badge--warn    { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.adn-badge--danger  { background: #fff1f2; color: #be123c; border-color: #fecdd3; }
.adn-badge--neutral { background: #f1f5f9; color: #475569; border-color: #e2e8f0; }

/* ---- Empty state ------------------------------------------------------ */

/* This one earns its place. Sessions 39-46 repeatedly found working features
 * that nobody could reach, and a blank panel is indistinguishable from a
 * broken one. An empty state says what the thing is, why there is nothing
 * here, and what to do next. */
.adn-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 8px;
    padding: 40px 24px;
    border: 1px dashed #cbd5e1;
    border-radius: 16px;
    background: #f8fafc;
}

.adn-empty__title  { font-size: 0.9375rem; font-weight: 700; color: #334155; }
.adn-empty__body   { font-size: 0.8125rem; color: #64748b; max-width: 46ch; }
.adn-empty__action { margin-top: 8px; }

/* ---- Dark surfaces ---------------------------------------------------- */

/* The ERP and the studios run on near-black. Same components, same shapes,
 * same spacing - only the surface changes. Set data-surface="dark" on a
 * container (the ERP shell already has one) rather than forking the classes.
 */
[data-surface="dark"] .adn-card {
    background: #1e293b;
    border-color: rgba(255, 255, 255, 0.08);
}
[data-surface="dark"] .adn-card__title { color: #f8fafc; }
[data-surface="dark"] .adn-card__meta  { color: #94a3b8; }

[data-surface="dark"] .adn-field__label { color: #cbd5e1; }
[data-surface="dark"] .adn-field__input,
[data-surface="dark"] .adn-field__select,
[data-surface="dark"] .adn-field__textarea {
    background: #0f172a;
    border-color: rgba(255, 255, 255, 0.12);
    color: #f8fafc;
}

[data-surface="dark"] .adn-empty {
    background: rgba(15, 23, 42, 0.6);
    border-color: rgba(255, 255, 255, 0.12);
}
[data-surface="dark"] .adn-empty__title { color: #e2e8f0; }

[data-surface="dark"] .adn-btn--ghost { color: #cbd5e1; }
[data-surface="dark"] .adn-btn--ghost:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.06);
}
[data-surface="dark"] .adn-btn--secondary {
    color: #a5b4fc;
    border-color: rgba(165, 180, 252, 0.35);
}
[data-surface="dark"] .adn-btn--secondary:hover:not(:disabled) {
    background: rgba(99, 102, 241, 0.15);
}


/* ══════════════════════════════════════════════════════════════════
   INTERVIEW REVIEW - one student's practice, as a dashboard
   ══════════════════════════════════════════════════════════════════
   Read by a counsellor deciding whether to put someone in front of a
   real credibility interview, so the empty states carry as much weight
   as the numbers: a dash means nothing was measured, and it must not be
   mistaken for a low score. Tokens only - no new colours.
   ══════════════════════════════════════════════════════════════════ */

.ir-wrap{display:flex;flex-direction:column;gap:var(--gap-md);
    max-width:1100px}

.ir-head{display:flex;align-items:flex-start;justify-content:space-between;
    gap:var(--gap-md);flex-wrap:wrap}
.ir-name{margin:0 0 4px;font-size:1.15rem;font-weight:800;
    color:var(--text-strong)}
.ir-sub{margin:0;font-size:.8rem;color:var(--text-secondary)}
.ir-back{font-size:.78rem;font-weight:700;color:var(--info);
    min-height:44px;display:inline-flex;align-items:center}

/* headline numbers */
.ir-cards{display:grid;gap:var(--gap-sm);
    grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
.ir-card{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:14px}
.ir-card-k{display:block;font-size:.66rem;font-weight:800;letter-spacing:.7px;
    text-transform:uppercase;color:var(--text-secondary);margin-bottom:6px}
.ir-card-v{font-size:1.5rem;font-weight:900;color:var(--text-strong);
    font-variant-numeric:tabular-nums;line-height:1}
.ir-card-v small{font-size:.66rem;font-weight:700;color:var(--text-secondary);
    margin-left:5px;letter-spacing:.3px}

/* direction of travel, or the absence of one */
.ir-trend{display:flex;flex-direction:column;gap:3px;padding:13px 15px;
    border-radius:var(--radius-md);border-left:3px solid var(--text-secondary);
    background:var(--surface-3)}
.ir-trend strong{font-size:.86rem;color:var(--text-strong)}
.ir-trend span{font-size:.78rem;color:var(--text-body);line-height:1.55}
.ir-trend--improving{border-left-color:var(--ok)}
.ir-trend--declining{border-left-color:var(--danger)}
.ir-trend--flat{border-left-color:var(--info)}
/* "no trend yet" is not a bad result - it is an absent one */
.ir-trend--none{border-left-color:var(--border-strong)}

.ir-section{display:flex;flex-direction:column;gap:var(--gap-sm)}
.ir-h3{margin:0;font-size:.92rem;font-weight:800;color:var(--text-strong);
    display:flex;align-items:baseline;gap:8px}
.ir-h3 small{font-size:.7rem;font-weight:600;color:var(--text-secondary)}

/* per topic */
.ir-topics{display:grid;gap:var(--gap-sm);
    grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.ir-topic{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:12px}
.ir-topic-row{display:flex;justify-content:space-between;align-items:baseline;
    gap:10px;margin-bottom:7px}
.ir-topic-name{font-size:.79rem;font-weight:700;color:var(--text-strong)}
.ir-topic-val{font-size:.92rem;font-weight:900;color:var(--text-strong);
    font-variant-numeric:tabular-nums}
.ir-topic-track{height:5px;background:var(--border-subtle);
    border-radius:99px;overflow:hidden}
.ir-topic-fill{height:100%;background:var(--info);border-radius:99px}
.ir-topic-meta{margin-top:7px;font-size:.68rem;color:var(--text-secondary);
    line-height:1.5}
/* a topic barely tested reads as absent, never as weak */
.ir-topic.is-thin .ir-topic-val{color:var(--text-secondary)}
.ir-topic.is-thin .ir-topic-fill{background:var(--border-strong)}

/* what to do next */
.ir-recs{list-style:none;margin:0;padding:0;display:flex;
    flex-direction:column;gap:var(--gap-sm)}
.ir-recs li{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-left:3px solid var(--warn);border-radius:0 var(--radius-md) var(--radius-md) 0;
    padding:12px 14px;display:flex;flex-direction:column;gap:5px}
.ir-rec-t{font-size:.82rem;line-height:1.6;color:var(--text-strong)}
/* every line names the count it rests on */
.ir-rec-b{font-size:.68rem;color:var(--text-secondary)}

.ir-scroll{overflow-x:auto}
.ir-table{width:100%;border-collapse:collapse;font-size:.83rem}
.ir-table th{text-align:left;padding:10px;font-size:.7rem;font-weight:800;
    letter-spacing:.5px;text-transform:uppercase;color:var(--text-secondary);
    border-bottom:1px solid var(--border-subtle)}
.ir-table td{padding:11px 10px;border-bottom:1px solid var(--border-subtle);
    color:var(--text-body)}
.ir-empty{margin:0;padding:14px;border-radius:var(--radius-md);
    background:var(--surface-3);border:1px solid var(--border-subtle);
    font-size:.82rem;line-height:1.6;color:var(--text-body)}

/* filters on the list */
.ir-filters{display:flex;gap:var(--gap-sm);flex-wrap:wrap;align-items:flex-end}
.ir-filter{display:flex;flex-direction:column;gap:5px}
.ir-filter label{font-size:.66rem;font-weight:800;letter-spacing:.6px;
    text-transform:uppercase;color:var(--text-secondary)}
.ir-filter select{min-height:44px;padding:0 12px;border-radius:var(--radius-sm);
    border:1px solid var(--border-strong);background:#fff;
    font-size:16px;font-family:inherit;color:var(--text-strong)}
.ir-filter button{min-height:44px;padding:0 18px;border:none;
    border-radius:var(--radius-sm);background:var(--text-strong);color:#fff;
    font-size:.8rem;font-weight:800;cursor:pointer;font-family:inherit}

/* ── one answer, and everything the officer made of it ──────────────
   Each block is labelled, because "what was missing" and "a stronger
   answer" are different kinds of statement and running them together as
   prose is how a debrief becomes unreadable. */
.ir-turn{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:15px;margin-bottom:var(--gap-sm)}
.ir-turn-top{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
    margin-bottom:9px}
.ir-turn-n{font-size:.68rem;font-weight:900;letter-spacing:.6px;
    color:var(--text-secondary)}
.ir-turn-cat{font-size:.64rem;font-weight:800;letter-spacing:.5px;
    text-transform:uppercase;color:var(--info);
    background:rgba(96,165,250,.12);border-radius:99px;padding:3px 9px}
.ir-turn-score{margin-left:auto;font-size:.74rem;font-weight:900;
    font-variant-numeric:tabular-nums;color:var(--ok)}
.ir-turn-score.is-mid{color:#b45309}
.ir-turn-score.is-low{color:var(--danger)}
.ir-turn-q{margin:0 0 4px;font-size:.9rem;font-weight:700;line-height:1.5;
    color:var(--text-strong)}
.ir-turn-obj{margin:0 0 10px;font-size:.7rem;color:var(--text-secondary)}
.ir-turn-a{background:#fff;border:1px solid var(--border-subtle);
    border-radius:var(--radius-sm);padding:11px 13px;margin-bottom:9px}
.ir-turn-k{display:block;font-size:.62rem;font-weight:900;letter-spacing:.7px;
    text-transform:uppercase;color:var(--text-secondary);margin-bottom:5px}
.ir-turn-a p,.ir-turn-block p{margin:0;font-size:.82rem;line-height:1.6;
    color:var(--text-body)}
.ir-turn-meta{display:block;margin-top:7px;font-size:.67rem;
    color:var(--text-secondary)}
.ir-turn-block{border-left:3px solid var(--border-strong);
    border-radius:0 var(--radius-sm) var(--radius-sm) 0;
    padding:10px 13px;margin-bottom:8px;background:#fff}
.ir-turn-officer{border-left-color:var(--info)}
.ir-turn-good{border-left-color:var(--ok)}
.ir-turn-miss{border-left-color:var(--warn)}
.ir-turn-concern{border-left-color:var(--warn)}
.ir-turn-contra{border-left-color:var(--danger)}
.ir-turn-model{border-left-color:var(--ok);background:rgba(52,211,153,.07)}
.ir-turn-metrics{display:flex;gap:12px;flex-wrap:wrap;margin-top:10px;
    padding-top:9px;border-top:1px solid var(--border-subtle);
    font-size:.67rem;color:var(--text-secondary);text-transform:capitalize}
.ir-turn-metrics b{color:var(--text-strong);font-variant-numeric:tabular-nums}

/* A finding that recurs matters more than one that happened once. */
.ir-recur{margin-left:8px;font-size:.6rem;font-weight:800;letter-spacing:.4px;
    text-transform:uppercase;color:var(--text-secondary);
    background:var(--surface-3);border-radius:99px;padding:2px 8px}
.ir-rpt-limit-note{margin:12px 0 0;padding-top:11px;
    border-top:1px solid var(--border-subtle);font-size:.71rem;line-height:1.6;
    color:var(--text-secondary)}

/* "not evaluated" is an absence, not a bad score - it must not read red. */
.ir-turn-score.ir-turn-unscored{color:var(--text-secondary);font-weight:700;
    font-size:.68rem;text-transform:uppercase;letter-spacing:.5px}

/* ══════════════════════════════════════════════════════════════════
   INTERVIEW REVIEW on the dark shell
   ══════════════════════════════════════════════════════════════════
   The review was built with the light-surface tokens - --text-strong is
   documented in tokens.css as "headings on light" - and then rendered
   inside base_erp.html, which sets data-surface="dark". Anything with a
   card behind it survived, because the card carried --surface-3. Anything
   without one did not: the student's name was #0f172a on #0f172a, a
   contrast ratio of exactly 1.00, and so were the section headings.

   Overridden here rather than by forking the classes, which is the
   pattern the ERP already uses for .adn-card. The card fills move to the
   same #1e293b those use, so the review stops being white panels floating
   on a near-black shell.
   ══════════════════════════════════════════════════════════════════ */

[data-surface="dark"] .ir-name,
[data-surface="dark"] .ir-h3,
[data-surface="dark"] .ir-card-v,
[data-surface="dark"] .ir-topic-name,
[data-surface="dark"] .ir-topic-val,
[data-surface="dark"] .ir-trend strong,
[data-surface="dark"] .ir-rec-t,
[data-surface="dark"] .ir-turn-q,
[data-surface="dark"] .ir-turn-metrics b,
[data-surface="dark"] .ir-find-h { color: #f8fafc; }

[data-surface="dark"] .ir-sub,
[data-surface="dark"] .ir-card-k,
[data-surface="dark"] .ir-card-v small,
[data-surface="dark"] .ir-h3 small,
[data-surface="dark"] .ir-topic-meta,
[data-surface="dark"] .ir-rec-b,
[data-surface="dark"] .ir-turn-n,
[data-surface="dark"] .ir-turn-obj,
[data-surface="dark"] .ir-turn-k,
[data-surface="dark"] .ir-turn-meta,
[data-surface="dark"] .ir-turn-metrics,
[data-surface="dark"] .ir-table th,
[data-surface="dark"] .ir-filter label,
[data-surface="dark"] .ir-recur,
[data-surface="dark"] .ir-rpt-limit-note { color: #94a3b8; }

[data-surface="dark"] .ir-trend span,
[data-surface="dark"] .ir-table td,
[data-surface="dark"] .ir-empty,
[data-surface="dark"] .ir-turn-a p,
[data-surface="dark"] .ir-turn-block p { color: #cbd5e1; }

/* Panels: the same fill the ERP's own cards use on this shell. */
[data-surface="dark"] .ir-card,
[data-surface="dark"] .ir-topic,
[data-surface="dark"] .ir-trend,
[data-surface="dark"] .ir-turn,
[data-surface="dark"] .ir-empty,
[data-surface="dark"] .ir-recs li,
[data-surface="dark"] .ir-recur {
    background: #1e293b;
    border-color: rgba(255, 255, 255, 0.08);
}
/* Nested surfaces sit darker than the panel holding them, not lighter. */
[data-surface="dark"] .ir-turn-a,
[data-surface="dark"] .ir-turn-block,
[data-surface="dark"] .ir-filter select {
    background: #0f172a;
    border-color: rgba(255, 255, 255, 0.10);
    color: #f8fafc;
}
[data-surface="dark"] .ir-turn-model { background: rgba(52, 211, 153, 0.08); }
[data-surface="dark"] .ir-topic-track { background: rgba(255, 255, 255, 0.10); }
[data-surface="dark"] .ir-table th,
[data-surface="dark"] .ir-table td { border-bottom-color: rgba(255, 255, 255, 0.08); }
[data-surface="dark"] .ir-rpt-limit-note { border-top-color: rgba(255, 255, 255, 0.08); }
[data-surface="dark"] .ir-topic.is-thin .ir-topic-val { color: #94a3b8; }
/* is-mid measured 3.56:1 on this ground - amber-400 rather than amber-700. */
[data-surface="dark"] .ir-turn-score.is-mid { color: #fbbf24; }
[data-surface="dark"] .ir-turn-score.is-low { color: #fca5a5; }
[data-surface="dark"] .ir-turn-score.ir-turn-unscored { color: #94a3b8; }

/* .erp-tap is a tap-target helper in erp-mobile.css - min-height, min-width,
   inline-flex - and sets no colour at all. A link carrying only that class
   therefore falls back to the browser's default #0000EE, which on this
   near-black shell measures 1.9:1. Fourteen of the seventeen links on the
   review list were rendering that way, including every "View transcript".
   Scoped to these two tables rather than to every .erp-tap in the ERP,
   which is a wider question than this change. */
[data-surface="dark"] .ir-table a,
[data-surface="dark"] .erp-table--cards a { color: #60a5fa; }

/* ══════════════════════════════════════════════════════════════════
   VISA INTAKE QUESTIONNAIRE
   ══════════════════════════════════════════════════════════════════
   Read by a student answering under declaration, often on a phone, often
   in a second language. The UKVI wording leads and our shorter label is
   the caption, because the wording is the question they are actually
   answering.

   Light-surface tokens with a [data-surface="dark"] block below them -
   the ERP shell is dark, and the interview review shipped unreadable
   because that was forgotten.
   ══════════════════════════════════════════════════════════════════ */
.vq-wrap{display:flex;flex-direction:column;gap:var(--gap-md);max-width:820px}
.vq-title{margin:0 0 4px;font-size:1.15rem;font-weight:800;color:var(--text-strong)}
.vq-sub{margin:0 0 10px;font-size:.8rem;color:var(--text-secondary)}
.vq-intro{margin:0;font-size:.86rem;line-height:1.65;color:var(--text-body)}

.vq-progress{display:flex;align-items:center;gap:12px}
.vq-progress-track{flex:1;height:6px;background:var(--border-subtle);
    border-radius:99px;overflow:hidden}
.vq-progress-fill{height:100%;background:var(--ok);border-radius:99px;
    transition:width .4s ease}
.vq-progress-text{font-size:.72rem;font-weight:700;color:var(--text-secondary);
    font-variant-numeric:tabular-nums;flex:none}

.vq-section{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:16px}
.vq-section.is-declaration{border-left:3px solid var(--warn)}
.vq-section-title{margin:0 0 6px;font-size:.95rem;font-weight:800;
    color:var(--text-strong);display:flex;align-items:center;gap:10px;
    flex-wrap:wrap}
.vq-declaration-tag{font-size:.6rem;font-weight:900;letter-spacing:.6px;
    text-transform:uppercase;color:#b45309;background:rgba(251,191,36,.15);
    border-radius:99px;padding:3px 9px}
.vq-section-note{margin:0 0 14px;font-size:.79rem;line-height:1.65;
    color:var(--text-body)}

.vq-q,.vq-answer{padding:14px 0;border-top:1px solid var(--border-subtle)}
.vq-q:first-of-type,.vq-answer:first-of-type{border-top:none;padding-top:4px}
/* The portal's wording, at reading size. */
.vq-question{margin:0 0 4px;font-size:.9rem;line-height:1.6;font-weight:600;
    color:var(--text-strong)}
.vq-label{margin:0 0 8px;font-size:.72rem;color:var(--text-secondary)}
.vq-help{margin:0 0 10px;font-size:.75rem;line-height:1.6;
    color:var(--text-secondary)}

.vq-choices{display:flex;gap:8px;flex-wrap:wrap}
.vq-choice{display:inline-flex;align-items:center;gap:7px;min-height:44px;
    padding:0 14px;border:1px solid var(--border-strong);
    border-radius:var(--radius-sm);background:#fff;cursor:pointer;
    font-size:.82rem;color:var(--text-strong)}
.vq-choice input{margin:0}
.vq-input{width:100%;min-height:44px;padding:10px 12px;
    border:1px solid var(--border-strong);border-radius:var(--radius-sm);
    font-size:16px;font-family:inherit;line-height:1.55;
    color:var(--text-strong);background:#fff;resize:vertical}
.vq-input:focus-visible,.vq-choice:focus-within{outline:2px solid var(--info);
    outline-offset:2px}

.vq-state{min-height:18px;margin-top:6px}
.vq-saved{font-size:.7rem;font-weight:700;color:#047857}
.vq-error{font-size:.75rem;color:var(--danger)}

.vq-notice{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-left:3px solid var(--warn);border-radius:0 var(--radius-md) var(--radius-md) 0;
    padding:14px;font-size:.82rem;line-height:1.65;color:var(--text-body)}
.vq-unanswered{margin:10px 0 0;padding-left:18px}
.vq-unanswered li{margin-bottom:6px}
.vq-footer{margin:0;font-size:.76rem;line-height:1.65;color:var(--text-secondary)}

.vq-cards{display:grid;gap:var(--gap-sm);
    grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.vq-card{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:14px}
.vq-card-k{display:block;font-size:.64rem;font-weight:800;letter-spacing:.7px;
    text-transform:uppercase;color:var(--text-secondary);margin-bottom:6px}
.vq-card-v{font-size:1.4rem;font-weight:900;color:var(--text-strong);
    font-variant-numeric:tabular-nums}
.vq-card-v small{font-size:.62rem;font-weight:700;margin-left:6px;
    color:var(--text-secondary)}

.vq-given{margin:0 0 4px;font-size:.86rem;line-height:1.6;
    color:var(--text-strong);white-space:pre-wrap}
.vq-meta{margin:0;font-size:.68rem;color:var(--text-secondary)}
/* An absent declaration is a gap to chase, not a quiet nothing. */
.vq-unanswered-mark{margin:0;font-size:.78rem;font-weight:700;color:#b45309}

[data-surface="dark"] .vq-title,
[data-surface="dark"] .vq-section-title,
[data-surface="dark"] .vq-question,
[data-surface="dark"] .vq-card-v,
[data-surface="dark"] .vq-given{color:#f8fafc}
[data-surface="dark"] .vq-sub,
[data-surface="dark"] .vq-label,
[data-surface="dark"] .vq-help,
[data-surface="dark"] .vq-meta,
[data-surface="dark"] .vq-card-k,
[data-surface="dark"] .vq-card-v small,
[data-surface="dark"] .vq-footer,
[data-surface="dark"] .vq-progress-text{color:#94a3b8}
[data-surface="dark"] .vq-intro,
[data-surface="dark"] .vq-section-note,
[data-surface="dark"] .vq-notice{color:#cbd5e1}
[data-surface="dark"] .vq-section,
[data-surface="dark"] .vq-card,
[data-surface="dark"] .vq-notice{background:#1e293b;
    border-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vq-choice,
[data-surface="dark"] .vq-input{background:#0f172a;color:#f8fafc;
    border-color:rgba(255,255,255,.14)}
[data-surface="dark"] .vq-q,
[data-surface="dark"] .vq-answer{border-top-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vq-progress-track{background:rgba(255,255,255,.10)}
[data-surface="dark"] .vq-saved{color:#6ee7b7}
[data-surface="dark"] .vq-error{color:#fca5a5}
[data-surface="dark"] .vq-declaration-tag{color:#fcd34d}
[data-surface="dark"] .vq-unanswered-mark{color:#fcd34d}
[data-surface="dark"] .vq-notice a{color:#60a5fa}


/* ══════════════════════════════════════════════════════════════════
   VISA LODGEMENT ASSISTANT
   ══════════════════════════════════════════════════════════════════
   A three-column working surface on desktop, one column on a phone,
   with a sticky footer carrying the state and Export.

   The footer is `position:sticky` inside a grid whose ancestors must not
   set `overflow:hidden` - that has silently killed a sticky element on
   this codebase twice, once from .mi and once from .sim-shell. There is
   a test in visa/test_assistant_layout.py holding it.

   Light-surface tokens with a [data-surface="dark"] block below, since
   the ERP shell is dark.
   ══════════════════════════════════════════════════════════════════ */
.vl-shell{display:grid;gap:var(--gap-md);
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"nav" "main" "side" "foot"}
@media (min-width:1100px){
    .vl-shell{grid-template-columns:210px minmax(0,1fr) 320px;
        grid-template-areas:"nav main side" "foot foot foot";
        align-items:start}
}
.vl-nav{grid-area:nav}
.vl-main{grid-area:main;min-width:0;display:flex;flex-direction:column;
    gap:var(--gap-md)}
.vl-side{grid-area:side}
.vl-foot{grid-area:foot}

/* ── left rail ─────────────────────────────────────────────────── */
.vl-nav{display:flex;flex-direction:column;gap:2px;position:sticky;top:12px}
.vl-nav-head{margin:0 0 6px;font-size:.62rem;font-weight:900;
    letter-spacing:.8px;text-transform:uppercase;color:var(--text-secondary)}
.vl-nav-item{display:flex;align-items:center;justify-content:space-between;
    gap:8px;min-height:36px;padding:6px 10px;border-radius:var(--radius-sm);
    font-size:.78rem;color:var(--text-body);text-decoration:none}
.vl-nav-item:hover{background:var(--surface-3)}
.vl-nav-item.is-done .vl-nav-count{color:var(--ok);font-weight:800}
.vl-nav-label{min-width:0;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap}
.vl-nav-count{flex:none;font-size:.7rem;font-variant-numeric:tabular-nums;
    color:var(--text-secondary)}

/* ── header ────────────────────────────────────────────────────── */
.vl-head{display:flex;flex-direction:column;gap:2px}
.vl-title{margin:0;font-size:1.15rem;font-weight:800;color:var(--text-strong)}
.vl-sub{margin:0;font-size:.78rem;color:var(--text-secondary)}
.vl-readonly-note{margin:8px 0 0;font-size:.78rem;line-height:1.6;
    color:var(--text-body);background:var(--surface-3);
    border-left:3px solid var(--info);border-radius:0 var(--radius-sm) var(--radius-sm) 0;
    padding:10px 12px}

/* ── conflicts ─────────────────────────────────────────────────── */
.vl-conflicts{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-left:3px solid var(--warn);border-radius:var(--radius-md);
    padding:14px;display:flex;flex-direction:column;gap:12px}
.vl-conflict-head{margin:0;font-size:.9rem;font-weight:800;
    color:var(--text-strong)}
.vl-conflict-field{margin:0 0 4px;font-size:.8rem;font-weight:700}
.vl-conflict-field a{color:var(--info)}
.vl-conflict-list{margin:0;padding-left:18px;font-size:.8rem;line-height:1.7}
.vl-conflict-value{font-weight:700;color:var(--text-strong)}
.vl-conflict-where{color:var(--text-secondary)}
.vl-conflict-note{margin:6px 0 0;font-size:.75rem;color:var(--text-secondary)}

/* ── sections and fields ───────────────────────────────────────── */
.vl-section{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-radius:var(--radius-md);padding:14px;scroll-margin-top:16px}
.vl-section-head{display:flex;align-items:center;justify-content:space-between;
    gap:10px;flex-wrap:wrap;margin-bottom:6px}
.vl-section-title{margin:0;font-size:.95rem;font-weight:800;
    color:var(--text-strong)}
.vl-section-tools{display:flex;align-items:center;gap:8px}
.vl-section-count{font-size:.7rem;font-weight:700;color:var(--text-secondary);
    font-variant-numeric:tabular-nums}

.vl-field{padding:14px 0;border-top:1px solid var(--border-subtle);
    scroll-margin-top:16px}
.vl-field:first-of-type{border-top:none}
.vl-field.is-verified{border-left:2px solid var(--ok);padding-left:10px;
    margin-left:-12px}
.vl-field-head{display:flex;align-items:baseline;justify-content:space-between;
    gap:10px;flex-wrap:wrap;margin-bottom:4px}
.vl-field-label{font-size:.84rem;font-weight:700;color:var(--text-strong)}
.vl-req{font-size:.58rem;font-weight:900;letter-spacing:.5px;
    text-transform:uppercase;color:var(--danger);margin-left:6px}
.vl-ukvi{margin:0 0 4px;font-size:.78rem;line-height:1.6;
    color:var(--text-body)}
.vl-help{margin:0 0 8px;font-size:.73rem;line-height:1.6;
    color:var(--text-secondary)}

/* The chip names the document and the page, because "from a document"
   on its own does not tell a counsellor which one to open. */
.vl-chip{flex:none;font-size:.62rem;font-weight:800;letter-spacing:.3px;
    border-radius:99px;padding:3px 9px;background:var(--surface-2);
    color:var(--text-secondary);border:1px solid var(--border-subtle)}
.vl-chip--document{background:rgba(96,165,250,.14);color:#1d4ed8;
    border-color:rgba(96,165,250,.35)}
.vl-chip--intake{background:rgba(167,139,250,.14);color:#5b21b6;
    border-color:rgba(167,139,250,.35)}
.vl-chip--derived{background:rgba(45,212,191,.14);color:#0f766e;
    border-color:rgba(45,212,191,.35)}
.vl-chip--manual{background:var(--surface-2);color:var(--text-secondary)}
.vl-chip--empty{background:transparent;color:var(--text-secondary);
    border-style:dashed}
.vl-chip-pct{margin-left:5px;opacity:.75;font-variant-numeric:tabular-nums}

.vl-field-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.vl-input{flex:1;min-width:160px;min-height:44px;padding:10px 12px;
    border:1px solid var(--border-strong);border-radius:var(--radius-sm);
    font-size:16px;font-family:inherit;color:var(--text-strong);
    background:#fff}
.vl-input:focus-visible{outline:2px solid var(--info);outline-offset:2px}
.vl-given{flex:1;min-width:160px;margin:0;font-size:.86rem;line-height:1.6;
    color:var(--text-strong);white-space:pre-wrap}
.vl-blank{color:var(--text-secondary);font-style:italic}

.vl-field-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    margin-top:8px}
.vl-confirm{display:inline-flex;align-items:center;gap:7px;min-height:44px;
    font-size:.78rem;color:var(--text-body);cursor:pointer}
.vl-confirm input{margin:0;width:18px;height:18px}
.vl-confirm-by{font-size:.68rem;color:var(--text-secondary)}
.vl-note{flex:1;min-width:140px;min-height:36px;padding:6px 10px;
    border:1px solid var(--border-subtle);border-radius:var(--radius-sm);
    font-size:.78rem;font-family:inherit;color:var(--text-strong);
    background:#fff}

.vl-suggest{margin:8px 0 0;font-size:.76rem;line-height:1.6;
    color:var(--text-body);background:var(--surface-2);
    border-radius:var(--radius-sm);padding:8px 10px;
    display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.vl-suggest-from{color:var(--text-secondary);font-size:.7rem}

.vl-finding{margin:8px 0 0;font-size:.76rem;line-height:1.6;
    border-radius:var(--radius-sm);padding:9px 11px;
    display:flex;flex-direction:column;gap:3px}
.vl-finding--blocker{background:rgba(248,113,113,.12);
    border-left:3px solid var(--danger);color:var(--text-body)}
.vl-finding--warning{background:rgba(251,191,36,.14);
    border-left:3px solid var(--warn);color:var(--text-body)}
.vl-finding-why,.vl-finding-remedy{color:var(--text-secondary)}

.vl-state{display:inline-block;margin-top:6px;font-size:.72rem;
    font-weight:700;color:var(--ok)}
.vl-state.is-error{color:var(--danger)}

/* ── right rail ────────────────────────────────────────────────── */
.vl-side-inner{position:sticky;top:12px;display:flex;flex-direction:column;
    gap:8px}
.vl-side-head{margin:0;font-size:.62rem;font-weight:900;letter-spacing:.8px;
    text-transform:uppercase;color:var(--text-secondary)}
.vl-side-head--warn{margin-top:10px}
.vl-issue{border-radius:var(--radius-sm);padding:10px 12px;
    display:flex;flex-direction:column;gap:4px;font-size:.76rem;
    line-height:1.6}
.vl-issue--blocker{background:rgba(248,113,113,.12);
    border-left:3px solid var(--danger)}
.vl-issue--warning{background:rgba(251,191,36,.14);
    border-left:3px solid var(--warn)}
.vl-issue-msg{margin:0;font-weight:700;color:var(--text-strong)}
.vl-issue-why,.vl-issue-remedy{margin:0;color:var(--text-secondary)}
.vl-issue-link{font-size:.72rem;font-weight:700;color:var(--info)}
.vl-none{margin:0;font-size:.76rem;color:var(--text-secondary)}

/* ── sticky footer ─────────────────────────────────────────────── */
.vl-foot{position:sticky;bottom:0;z-index:5;display:flex;align-items:center;
    justify-content:space-between;gap:12px;flex-wrap:wrap;
    background:var(--surface-2);border-top:1px solid var(--border-subtle);
    border-radius:var(--radius-md) var(--radius-md) 0 0;padding:12px 14px}
.vl-foot-state{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    min-width:0}
.vl-foot-badge{font-size:.72rem;font-weight:900;letter-spacing:.4px;
    text-transform:uppercase;border-radius:99px;padding:5px 12px}
.vl-foot-badge.is-ready{background:rgba(52,211,153,.16);color:#065f46}
.vl-foot-badge.is-not{background:rgba(248,113,113,.16);color:#991b1b}
.vl-foot-detail{font-size:.74rem;color:var(--text-secondary);
    font-variant-numeric:tabular-nums}
.vl-foot-top{font-size:.74rem;font-weight:700;color:var(--danger);
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.vl-btn{min-height:44px;padding:0 14px;border-radius:var(--radius-sm);
    font-size:.78rem;font-weight:700;font-family:inherit;cursor:pointer;
    border:1px solid var(--border-strong);background:#fff;
    color:var(--text-strong)}
.vl-btn:disabled{opacity:.5;cursor:not-allowed}
.vl-btn-ghost{min-height:36px;padding:0 10px;font-size:.72rem;
    background:transparent}
.vl-btn-primary{background:var(--info);border-color:var(--info);color:#fff}

/* ── the ERP shell is dark ─────────────────────────────────────── */
[data-surface="dark"] .vl-title,
[data-surface="dark"] .vl-section-title,
[data-surface="dark"] .vl-conflict-head,
[data-surface="dark"] .vl-field-label,
[data-surface="dark"] .vl-conflict-value,
[data-surface="dark"] .vl-issue-msg,
[data-surface="dark"] .vl-given{color:#f8fafc}
[data-surface="dark"] .vl-sub,
[data-surface="dark"] .vl-help,
[data-surface="dark"] .vl-nav-head,
[data-surface="dark"] .vl-nav-count,
[data-surface="dark"] .vl-section-count,
[data-surface="dark"] .vl-confirm-by,
[data-surface="dark"] .vl-conflict-where,
[data-surface="dark"] .vl-conflict-note,
[data-surface="dark"] .vl-suggest-from,
[data-surface="dark"] .vl-side-head,
[data-surface="dark"] .vl-issue-why,
[data-surface="dark"] .vl-issue-remedy,
[data-surface="dark"] .vl-finding-why,
[data-surface="dark"] .vl-finding-remedy,
[data-surface="dark"] .vl-none,
[data-surface="dark"] .vl-blank,
[data-surface="dark"] .vl-foot-detail{color:#94a3b8}
[data-surface="dark"] .vl-ukvi,
[data-surface="dark"] .vl-nav-item,
[data-surface="dark"] .vl-readonly-note,
[data-surface="dark"] .vl-confirm,
[data-surface="dark"] .vl-suggest,
[data-surface="dark"] .vl-finding{color:#cbd5e1}
[data-surface="dark"] .vl-section,
[data-surface="dark"] .vl-conflicts,
[data-surface="dark"] .vl-readonly-note{background:#1e293b;
    border-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vl-suggest,
[data-surface="dark"] .vl-foot{background:#16243b;
    border-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vl-nav-item:hover{background:#1e293b}
[data-surface="dark"] .vl-field,
[data-surface="dark"] .vl-section-head{border-top-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vl-input,
[data-surface="dark"] .vl-note,
[data-surface="dark"] .vl-btn{background:#0f172a;color:#f8fafc;
    border-color:rgba(255,255,255,.14)}
[data-surface="dark"] .vl-btn-primary{background:#2563eb;border-color:#2563eb;
    color:#f8fafc}
[data-surface="dark"] .vl-chip{background:rgba(255,255,255,.06);
    color:#cbd5e1;border-color:rgba(255,255,255,.12)}
[data-surface="dark"] .vl-chip--document{color:#93c5fd}
[data-surface="dark"] .vl-chip--intake{color:#c4b5fd}
[data-surface="dark"] .vl-chip--derived{color:#5eead4}
[data-surface="dark"] .vl-chip--empty{background:transparent;color:#94a3b8}
[data-surface="dark"] .vl-req,
[data-surface="dark"] .vl-foot-top{color:#fca5a5}
[data-surface="dark"] .vl-state{color:#6ee7b7}
[data-surface="dark"] .vl-state.is-error{color:#fca5a5}
[data-surface="dark"] .vl-foot-badge.is-ready{background:rgba(52,211,153,.18);
    color:#6ee7b7}
[data-surface="dark"] .vl-foot-badge.is-not{background:rgba(248,113,113,.18);
    color:#fca5a5}
[data-surface="dark"] .vl-conflict-field a,
[data-surface="dark"] .vl-issue-link{color:#60a5fa}


/* ══════════════════════════════════════════════════════════════════
   VISA LODGEMENT - THE PRINTABLE SHEET
   ══════════════════════════════════════════════════════════════════
   No PDF library. The browser's own print pipeline produces the file,
   which is why the @media print block below is the actual deliverable
   rather than decoration: it drops the ERP chrome, forces black on
   white, and keeps a field's question with its answer across a page
   break.

   The document itself is deliberately light even on the dark shell -
   it is a piece of paper, and it is about to be one.
   ══════════════════════════════════════════════════════════════════ */
.vs-page{display:flex;flex-direction:column;gap:var(--gap-md);
    max-width:900px}

.vs-toolbar{display:flex;align-items:center;justify-content:flex-end;
    gap:8px;flex-wrap:wrap}

.vs-blocked{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-left:3px solid var(--danger);border-radius:var(--radius-md);
    padding:18px;display:flex;flex-direction:column;gap:12px;
    align-items:flex-start}
.vs-blocked-title{margin:0;font-size:1.05rem;font-weight:800;
    color:var(--text-strong)}
.vs-blocked-lede{margin:0;font-size:.85rem;line-height:1.65;
    color:var(--text-body)}
.vs-blocker{width:100%;background:rgba(248,113,113,.10);
    border-radius:var(--radius-sm);padding:10px 12px;
    display:flex;flex-direction:column;gap:3px}
.vs-blocker-msg{margin:0;font-size:.82rem;font-weight:700;
    color:var(--text-strong)}
.vs-blocker-why,.vs-blocker-remedy{margin:0;font-size:.76rem;line-height:1.6;
    color:var(--text-secondary)}

/* ── the document ──────────────────────────────────────────────── */
.vs-doc{background:#ffffff;color:#0f172a;border-radius:var(--radius-md);
    padding:28px;border:1px solid var(--border-subtle)}
.vs-head{border-bottom:2px solid #0f172a;padding-bottom:12px;
    margin-bottom:18px}
.vs-title{margin:0 0 10px;font-size:1.15rem;font-weight:800;color:#0f172a}
.vs-meta{display:grid;gap:6px 18px;margin:0;
    grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
.vs-meta div{display:flex;gap:6px;font-size:.78rem;min-width:0}
.vs-meta dt{font-weight:700;color:#475569;flex:none}
.vs-meta dd{margin:0;color:#0f172a;min-width:0;overflow-wrap:anywhere}

.vs-section{margin-bottom:18px;break-inside:auto}
.vs-section-title{margin:0 0 6px;font-size:.9rem;font-weight:800;
    color:#0f172a;border-bottom:1px solid #cbd5e1;padding-bottom:4px;
    display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;
    break-after:avoid}
.vs-section-count{font-size:.68rem;font-weight:700;color:#64748b;
    font-variant-numeric:tabular-nums}

.vs-table{width:100%;border-collapse:collapse}
.vs-table tr{border-bottom:1px solid #e2e8f0;break-inside:avoid}
.vs-table th{text-align:left;vertical-align:top;padding:7px 10px 7px 0;
    font-size:.78rem;font-weight:700;color:#0f172a;width:42%}
.vs-table td{vertical-align:top;padding:7px 0;font-size:.8rem;color:#0f172a}
/* An unconfirmed row is marked on the paper too, because the printout
   is what gets carried to the portal. */
.vs-table tr.is-unconfirmed th{border-left:3px solid #b45309;
    padding-left:8px}
.vs-q{display:block;margin-top:3px;font-size:.7rem;font-weight:400;
    line-height:1.5;color:#475569}
.vs-value{display:block;overflow-wrap:anywhere}
.vs-flags{display:block;margin-top:2px;font-size:.66rem;color:#64748b}
.vs-note{display:block;margin-top:3px;font-size:.7rem;color:#475569;
    font-style:italic}

.vs-foot{margin-top:20px;border-top:1px solid #cbd5e1;padding-top:10px}
.vs-foot p{margin:0;font-size:.7rem;line-height:1.6;color:#475569}

/* ── the ERP shell is dark; the document is not ────────────────── */
[data-surface="dark"] .vs-blocked-title{color:#f8fafc}
[data-surface="dark"] .vs-blocker-msg{color:#f8fafc}
[data-surface="dark"] .vs-blocked-lede{color:#cbd5e1}
[data-surface="dark"] .vs-blocker-why,
[data-surface="dark"] .vs-blocker-remedy{color:#94a3b8}
[data-surface="dark"] .vs-blocked{background:#1e293b;
    border-color:rgba(255,255,255,.08)}

/* ══════════════════════════════════════════════════════════════════
   PRINT - this is the export
   ══════════════════════════════════════════════════════════════════ */
@media print {
    /* The ERP chrome has no business on the paper. Hidden by role
       rather than by a print-only class on each one, so a sidebar
       added later does not silently start printing. */
    .sidebar, .top-navbar, .vs-toolbar, .erp-sidebar,
    .menu-toggle-btn, .vl-foot { display: none !important; }

    .main-wrapper, .content-body { margin: 0 !important;
        padding: 0 !important; }

    /* Forced, not inherited: the shell paints itself near-black, and a
       page printed white-on-black empties a toner cartridge and is
       unreadable besides. */
    html, body { background: #ffffff !important; color: #000000 !important; }

    .vs-page { max-width: none; gap: 0; }
    .vs-doc { border: none; border-radius: 0; padding: 0;
        background: #ffffff !important; color: #000000 !important; }

    .vs-table th, .vs-table td, .vs-title, .vs-section-title,
    .vs-meta dd { color: #000000 !important; }
    .vs-q, .vs-flags, .vs-note, .vs-meta dt, .vs-foot p,
    .vs-section-count { color: #333333 !important; }

    /* A question separated from its answer by a page break is a
       transcription error waiting to happen. */
    .vs-table tr { break-inside: avoid; page-break-inside: avoid; }
    .vs-section-title { break-after: avoid; page-break-after: avoid; }

    /* The disclaimer prints on the last page, and the header block
       repeats at the top of every one - a loose sheet needs to say whose
       it is. */
    .vs-head { break-after: avoid; }

    @page { margin: 14mm; }
}

/* ── Visa Lodgement, on the Student Master page ─────────────────
   That page is dark and hardcodes its own palette inline, but both
   bases it renders under set data-surface="dark", so tokens plus a
   dark block behave the same as everywhere else here. */
.vlt-list{display:flex;flex-direction:column;gap:10px;margin-top:12px}
.vlt-card{background:var(--surface-3);border:1px solid var(--border-subtle);
    border-left:3px solid var(--border-strong);border-radius:var(--radius-sm);
    padding:12px;display:flex;flex-direction:column;gap:7px}
.vlt-card.is-ready{border-left-color:var(--ok)}
.vlt-card.is-not{border-left-color:var(--danger)}
.vlt-row{display:flex;align-items:center;justify-content:space-between;
    gap:10px;flex-wrap:wrap}
.vlt-state{font-size:.68rem;font-weight:900;letter-spacing:.5px;
    text-transform:uppercase;color:var(--text-strong)}
.vlt-when{font-size:.72rem;color:var(--text-secondary)}
.vlt-bar{height:6px;background:var(--border-subtle);border-radius:99px;
    overflow:hidden}
.vlt-bar-fill{height:100%;background:var(--ok);border-radius:99px}
.vlt-figures{margin:0;font-size:.74rem;color:var(--text-secondary);
    font-variant-numeric:tabular-nums}
.vlt-top{margin:0;font-size:.76rem;font-weight:700;color:var(--danger);
    line-height:1.5}
.vlt-links{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.vlt-links a{font-size:.74rem;font-weight:700;color:var(--info);
    min-height:44px;display:inline-flex;align-items:center}
.vlt-disabled{font-size:.74rem;font-weight:700;color:var(--text-secondary);
    min-height:44px;display:inline-flex;align-items:center;cursor:not-allowed}
.vlt-empty{padding:14px;border-radius:var(--radius-sm);
    background:var(--surface-3);font-size:.8rem;line-height:1.6;
    color:var(--text-secondary)}
.vlt-start{min-height:44px;padding:0 12px;border-radius:var(--radius-sm);
    font-size:.74rem;font-weight:700;font-family:inherit;cursor:pointer;
    border:1px solid var(--border-strong);background:#fff;
    color:var(--text-strong)}

[data-surface="dark"] .vlt-state{color:#f8fafc}
[data-surface="dark"] .vlt-when,
[data-surface="dark"] .vlt-figures,
[data-surface="dark"] .vlt-empty,
[data-surface="dark"] .vlt-disabled{color:#94a3b8}
[data-surface="dark"] .vlt-top{color:#fca5a5}
[data-surface="dark"] .vlt-links a{color:#60a5fa}
[data-surface="dark"] .vlt-card,
[data-surface="dark"] .vlt-empty{background:#1e293b;
    border-color:rgba(255,255,255,.08)}
[data-surface="dark"] .vlt-bar{background:rgba(255,255,255,.10)}
[data-surface="dark"] .vlt-start{background:#0f172a;color:#f8fafc;
    border-color:rgba(255,255,255,.14)}

/* ── Header links on the visa screens ───────────────────────────
   These carry no colour of their own until told to. A bare <a> on the
   ERP's near-black shell falls back to the browser default #0000EE,
   which measures 1.9:1 - the same fault that made fourteen links on the
   interview review unreadable, shipped again here and caught by
   test_intake_contrast rather than by eye. */
.vq-head-links,.vl-head-links{display:flex;gap:14px;flex-wrap:wrap;
    align-items:center;margin:6px 0 0}
.vq-head-links a,.vl-head-links a{font-size:.76rem;font-weight:700;
    color:var(--info);min-height:44px;display:inline-flex;
    align-items:center}
.vq-head-note{margin:6px 0 0;font-size:.74rem;line-height:1.6;
    color:var(--text-secondary)}
.vq-head-note a{color:var(--info);font-weight:700}
.vq-notice a{color:var(--info);font-weight:700}
.vq-copy-link{min-height:44px;padding:0 12px;border-radius:var(--radius-sm);
    font-size:.74rem;font-weight:700;font-family:inherit;cursor:pointer;
    border:1px solid var(--border-strong);background:#fff;
    color:var(--text-strong)}

/* .vq-notice a is deliberately absent: the intake block above already
   colours it on the dark shell. Listing it here too made two identical
   rules, and deleting either one changed nothing - which is how the
   mutation run announced the duplicate. */
[data-surface="dark"] .vq-head-links a,
[data-surface="dark"] .vl-head-links a,
[data-surface="dark"] .vq-head-note a{color:#60a5fa}
[data-surface="dark"] .vq-head-note{color:#94a3b8}
[data-surface="dark"] .vq-copy-link{background:#0f172a;color:#f8fafc;
    border-color:rgba(255,255,255,.14)}


/* ---- Authentication pages --------------------------------------------
 *
 * Sign in, register, reset, confirm, change. One journey, so it should
 * look like one thing - it did not: different card treatments, two
 * different indigos on the primary button, an icon badge on some pages
 * and not others, and cards vertically centred so a phone showed 430px
 * of empty space before the form began.
 *
 * These pages render their fields with {{ field }}, which emits Django's
 * widget and gives a template no way to put classes on the input. Hence a
 * scoped rule rather than utility classes: .adn-auth on the card, and the
 * fields inside it inherit the same shape as the hand-written ones on the
 * login page.
 *
 * 52px and 16px are not arbitrary. Under 16px iOS zooms the page when a
 * field takes focus and does not zoom back out, which on a reset form
 * leaves somebody scrolling sideways to find the button.
 */
.adn-auth input[type="text"],
.adn-auth input[type="email"],
.adn-auth input[type="password"] {
    width: 100%;
    height: 52px;
    padding: 0 16px;
    border: 1px solid #cbd5e1;
    border-radius: 16px;
    background: #ffffff;
    color: #0f172a;
    font-family: inherit;
    font-size: 16px;
    transition: border-color 0.15s;
}

/* Room for the reveal button, which is a 44px target sitting inside. */
.adn-auth .adn-auth-field--password input[type="password"],
.adn-auth .adn-auth-field--password input[type="text"] {
    padding-right: 56px;
}

.adn-auth input::placeholder { color: #94a3b8; }

.adn-auth input[type="text"]:focus,
.adn-auth input[type="email"]:focus,
.adn-auth input[type="password"]:focus {
    border-color: #4f46e5;
}

/* Django renders help text and errors as lists; they should read as prose. */
.adn-auth .helptext,
.adn-auth ul.errorlist {
    display: block;
    margin-top: 6px;
    padding: 0;
    list-style: none;
    font-size: 0.75rem;
    line-height: 1.5;
}
.adn-auth .helptext { color: #64748b; }
.adn-auth ul.errorlist li { color: #be123c; font-weight: 700; }

/* A field with a leading icon needs room for it. Without this the shared
 * 16px padding puts the placeholder underneath the icon - which is what
 * happened the moment these fields started sharing a rule. */
.adn-auth .adn-auth-field--icon input[type="text"],
.adn-auth .adn-auth-field--icon input[type="email"],
.adn-auth .adn-auth-field--icon input[type="password"] {
    padding-left: 46px;
}

/* ---------------------------------------------------------------------------
   File field
   ---------------------------------------------------------------------------
   A bare <input type="file"> renders as the browser's own "Choose File / No
   file chosen" control: a grey button in a system font, unaffected by the
   padding and radius on the element around it, and about 24px tall on a
   phone. It is the one control on the category form that looked unfinished.

   Styled through ::file-selector-button rather than by hiding the input
   behind a label, so the control keeps its own keyboard behaviour and its
   own accessible name. Tailwind's file: variants would do the same thing,
   but only once the theme is rebuilt - these rules ship with the stylesheet.
--------------------------------------------------------------------------- */
/* File field
   ---------------------------------------------------------------------------
   Only the preview lives here. The control itself is styled with Tailwind
   utilities and its `file:` variants, in the template.

   That is deliberate, and it was not the first attempt. @tailwindcss/forms
   resets [type='file'] - background, border, radius, padding - so a bespoke
   component class has to win a specificity tie that stylesheet order decides,
   and a theme rebuild can flip that order. Two rounds of trying to out-specify
   it (a scoped `input.adn-filefield`, then a wrapper element) both left the
   colours unapplied while the geometry took, which is not a fight worth
   winning twice. Tailwind's own `file:` variants emit the same
   ::file-selector-button rules through the machinery the reset expects, and
   the text input beside it already proves that path works on this page. */
.adn-filepreview {
    margin-top: 10px;
    width: 100%;
    max-width: 220px;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    border-radius: 12px;
    border: 1px solid #e2e8f0;
    background-color: #f1f5f9;
}
