/**
 * Ink & Ledger - the shared Campus design system.
 * Spec + principles: docs/Design-System-Ink-and-Ledger.md  (ask for it by name)
 *
 * WHY THIS FILE EXISTS
 * Two pages (Academics Dashboard, Admission Form Templates) independently arrived
 * at the same visual language. Rather than let a third page copy-paste it again,
 * the shared parts live here: change a token here and every page that links this
 * file updates.
 *
 * THE RULES (violate these and the system stops working)
 *  1. Ground before cards. A white card on a white body is invisible - every page
 *     needs .il-workbench (or a paper background) behind its panels.
 *  2. ONE interactive accent. --il-accent means "an action or the active state"
 *     and nothing else. Never a heading, a group name, a count, or decoration.
 *  3. Colour is semantic. Green approved/valid, amber in-progress/advisory,
 *     red blocking, grey locked. Never colour for emphasis alone.
 *  4. One state, one control. Never render two verdicts about the same fact.
 *     Prefer folding state into the control it concerns; absence is a signal.
 *  5. Chrome hides until needed. Row tools live behind .il-tools + .il-hover.
 *  6. No webfonts. Identity comes from role discipline, not new families.
 *
 * HOW TO USE
 *   <link href="~/Content/css/ink-ledger.css?v=1_0" rel="stylesheet" />
 * then add only genuinely page-specific rules in the page's own <style>.
 *
 * Linked per-page on purpose, not from _layout - this is a legacy app and the
 * blast radius of a global stylesheet is the whole product. Promote it to the
 * layout only when most pages use it.
 *
 * NOTE ON PREFIXES: Academics/dashboard.css still uses its own `--ad-` tokens
 * with near-identical values. Do NOT renumber it in place; migrate it the next
 * time that page is reworked. See the spec, section 3.2.
 */

/* ============================================================ tokens */
:root {
    /* Ink */
    --il-ink: #1d2939;          /* primary text - never pure black */
    --il-muted: #667085;        /* secondary text, labels, meta */
    --il-faint: #98a2b3;        /* disabled, placeholders */

    /* Surfaces */
    --il-canvas: #f2f4f7;       /* the ground behind work panels */
    --il-surface: #ffffff;      /* panels, rows, chips */
    --il-head: #f8f9fb;         /* panel + section header strips */
    --il-border: #e4e7ec;       /* every hairline */
    --il-border-soft: #f1f3f5;  /* internal dividers */

    /* Interactive - one colour, used for nothing else */
    --il-accent: #1f5eff;
    --il-accent-ink: #1849c6;   /* hover / pressed */
    --il-accent-soft: #eef4ff;  /* selected row tint */
    --il-focus: rgba(31, 94, 255, .25);

    /* Semantic status */
    --il-ok: #067647;
    --il-ok-soft: #ecfdf3;
    --il-warn: #b54708;
    --il-warn-soft: #fffaeb;
    --il-warn-line: #fedf89;
    --il-danger: #d92d20;
    --il-danger-soft: #fef3f2;
    --il-danger-line: #fecdca;
    --il-locked: #98a2b3;

    /* Shape + depth */
    --il-radius: 8px;           /* panels, cards, modals */
    --il-radius-ctl: 6px;       /* buttons, inputs, chips */
    --il-shadow: 0 1px 2px rgba(16, 24, 40, .06);
    --il-shadow-pop: 0 6px 20px rgba(16, 24, 40, .14);

    /* Type */
    --il-mono: Consolas, "Cascadia Mono", Menlo, "Courier New", monospace;
}

/* ============================================================ layout */

/* The ground. Everything that is "work" sits on this. */
.il-workbench {
    background: var(--il-canvas);
    border: 1px solid var(--il-border);
    border-radius: 12px;
    padding: 12px;
}

.il-panel {
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow);
}

/* The uppercase eyebrow that names a region. Put the region's own counts and
   buttons in here, right-aligned - not floating above the panel. */
.il-panel-head {
    background: var(--il-head);
    border-bottom: 1px solid var(--il-border);
    padding: 7px 12px;
    border-radius: var(--il-radius) var(--il-radius) 0 0;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--il-muted);
}

/* Normal-case content inside an eyebrow (counts, buttons). */
.il-panel-head .il-plain {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
}

/* ============================================================ command bar */
.il-bar {
    position: sticky;
    top: 0;
    z-index: 40;
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .06);
    padding: 9px 14px;
    margin-bottom: 12px;
}

/* An editable page title: chrome only on hover/focus. */
.il-name-input {
    border: 0;
    border-bottom: 1px solid transparent;
    background: transparent;
    font-size: .95rem;
    font-weight: 600;
    color: var(--il-ink);
    padding: 3px 2px;
    width: 100%;
}
.il-name-input:hover { border-bottom-color: var(--il-border); }
.il-name-input:focus { border-bottom-color: var(--il-accent); outline: none; }

.il-divider { width: 1px; height: 22px; background: var(--il-border); }

/* ============================================================ segmented control */
/* For 2-4 way view switching. NEVER a solid primary button beside plain text -
   that reads as a button next to a link. */
.il-seg {
    display: inline-flex;
    background: #eef0f3;
    border-radius: var(--il-radius);
    padding: 2px;
}
.il-seg a {
    padding: 4px 14px;
    border-radius: var(--il-radius-ctl);
    font-size: .82rem;
    font-weight: 600;
    color: var(--il-muted);
    text-decoration: none;
    white-space: nowrap;
}
.il-seg a:hover { color: var(--il-ink); }
.il-seg a.active {
    background: #fff;
    color: var(--il-ink);
    box-shadow: var(--il-shadow);
}

/* ============================================================ status */

/* One dot + one sentence beats three columns the reader has to join up. */
.il-dot {
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: middle;
}
.il-dot.ok { background: var(--il-ok); }
.il-dot.warn { background: var(--il-warn); }
.il-dot.idle { background: var(--il-locked); }
.il-dot.danger { background: var(--il-danger); }

/* Quiet count/meta pill. Grey on purpose - counts are never accent-coloured. */
.il-count {
    background: var(--il-canvas);
    color: var(--il-muted);
    border-radius: 10px;
    padding: 1px 7px;
    font-size: .68rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Attention chip for a problem/warning summary. */
/* A message, and messages WRAP.
   
   This was born as a one-line status pill - inline-block, white-space: nowrap - and then
   got used for whole sentences, which then ran off the edge of whatever contained them.
   The publish dialog's "3 applications have already been filled in..." was clipped mid-word
   by the dialog border. 14 of its 17 call sites had already bolted `d-block` on to fight the
   inline default, which is the clearest possible sign the default was wrong; none of them
   could fight `nowrap`, because no utility class overrides it.
   
   `overflow-wrap: anywhere` because these messages quote things that have no spaces in them -
   application keys, field keys, URLs - and a single long token would otherwise still escape. */
.il-alert {
    border-radius: var(--il-radius-ctl);
    padding: 6px 10px;
    font-size: .78rem;
    font-weight: 600;
    line-height: 1.5;
    text-decoration: none;
    display: block;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* The original one-line pill, now opt-in. For the few places this really is a compact status
   badge sitting in a toolbar row rather than a sentence - where wrapping would stretch a
   header or break a two-word label across lines. */
.il-alert.pill {
    display: inline-block;
    width: auto;
    padding: 3px 10px;
    white-space: nowrap;
    overflow-wrap: normal;
}
.il-alert.err { background: var(--il-danger-soft); color: var(--il-danger); border: 1px solid var(--il-danger-line); }
.il-alert.warn { background: var(--il-warn-soft); color: var(--il-warn); border: 1px solid var(--il-warn-line); }
.il-alert.ok { background: var(--il-ok-soft); color: var(--il-ok); border: 1px solid #abefc6; }

/* ============================================================ cards */
.il-card {
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow);
    height: 100%;
    transition: border-color .12s, box-shadow .12s;
}
.il-card.clickable { cursor: pointer; }
.il-card.clickable:hover {
    border-color: var(--il-accent);
    box-shadow: 0 2px 10px rgba(31, 94, 255, .10);
}

/* Dashed "add another" placeholder. */
.il-ghost {
    border: 1px dashed #cbd2dc;
    border-radius: var(--il-radius-ctl);
    min-height: 54px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--il-muted);
    font-size: .8rem;
    cursor: pointer;
    height: 100%;
}
.il-ghost:hover { border-color: var(--il-accent); color: var(--il-accent); }

/* ============================================================ hover-revealed chrome */
/* A row with twelve fields should show zero buttons at rest, not thirty-six.
   Put .il-hover on the container and .il-tools on the button group. */
.il-tools { visibility: hidden; }
.il-hover:hover .il-tools,
.il-hover.is-active .il-tools { visibility: visible; }

.il-tools a { color: var(--il-muted); padding: 0 3px; font-size: .78rem; }
.il-tools a:hover { color: var(--il-accent); }
.il-tools a.del:hover { color: var(--il-danger); }

/* ============================================================ disclosure groups */
/* Caret LEFT of the title, summary right - so a closed group still reports its
   value ("Classes - 3 classes", "Student record - mapped"). */
.il-prop-group { border-bottom: 1px solid var(--il-border-soft); }
.il-prop-head {
    cursor: pointer;
    padding: 8px 0;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--il-ink);
}
.il-prop-head:hover { color: var(--il-accent); }
.il-prop-head .caret { color: var(--il-muted); width: 10px; text-align: center; }
.il-prop-head .sum {
    margin-left: auto;
    font-size: .74rem;
    font-weight: 400;
    color: var(--il-muted);
}
.il-prop-body { padding-bottom: 10px; }

/* ============================================================ popovers + menus */
/* Bootstrap's JS is not loaded on every page - these are hand-rolled with v-if
   plus a document click listener. Never rely on data-bs-toggle. */
.il-pop {
    position: absolute;
    z-index: 50;
    top: 34px;
    left: 0;
    width: 340px;
    background: #fff;
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow-pop);
    padding: 12px;
}
.il-pop.right { left: auto; right: 0; }
.il-pop.wide { width: 460px; max-height: 60vh; overflow-y: auto; padding: 10px 12px; }

.il-menu {
    position: absolute;
    right: 8px;
    top: 34px;
    z-index: 20;
    min-width: 170px;
    background: #fff;
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow-pop);
    padding: 4px 0;
}
.il-menu a { display: block; padding: 6px 14px; font-size: .82rem; color: var(--il-ink); text-decoration: none; }
.il-menu a:hover { background: var(--il-canvas); }
.il-menu a.danger { color: var(--il-danger); }
.il-menu a.disabled { color: var(--il-faint); cursor: not-allowed; }

/* ============================================================ modals */
.il-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(16, 24, 40, .5);
    z-index: 1050;
    overflow-y: auto;
    padding: 40px 15px;
}
.il-modal {
    background: #fff;
    border-radius: 12px;
    max-width: 900px;
    margin: 0 auto;
    box-shadow: 0 12px 44px rgba(16, 24, 40, .28);
}
.il-modal.sm { max-width: 520px; }
.il-modal.lg { max-width: 1100px; }

/* ============================================================ misc */

/* The "registry" voice: codes, keys, counts, percentages - never prose. */
.il-code { font-family: var(--il-mono); font-size: .68rem; }
.il-code.sm { font-size: .78rem; }

/* Every inner scroll region. Default scrollbars look untuned. */
.il-scroll { scrollbar-width: thin; scrollbar-color: #d0d5dd transparent; }
.il-scroll::-webkit-scrollbar { width: 6px; height: 6px; }
.il-scroll::-webkit-scrollbar-thumb { background: #d0d5dd; border-radius: 3px; }

/* Form labels inside dense panels. */
.il-dense .form-label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--il-muted);
    margin-bottom: 3px;
}

/* Accessibility floor - see the spec, section 5. Colour is never the only
   carrier of meaning, and every interactive element shows focus. */
.il-seg a:focus-visible,
.il-menu a:focus-visible,
.il-card.clickable:focus-visible,
.il-prop-head:focus-visible,
.il-alert:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--il-focus);
    border-radius: var(--il-radius-ctl);
}

/* ============================================================ activity timeline

   One rendering for every history surface in the module: the template's
   History tab, the campaign's, the application timeline, and the Activity
   feed. A single rail with a dot per entry - the eye follows the rail, and
   the entries that matter are the ones whose dot is coloured.

   Tone is deliberately restrained: most entries are routine and stay grey.
   Only ok / warn / err are tinted, so a red dot in a hundred grey ones is
   findable without reading a word. */

.il-tl { position: relative; padding-left: 22px; }

/* the rail */
.il-tl:before {
    content: "";
    position: absolute;
    left: 6px;
    top: 4px;
    bottom: 4px;
    width: 1px;
    background: var(--il-border);
}

.il-tl-item { position: relative; padding: 0 0 11px 0; }
.il-tl-item:last-child { padding-bottom: 2px; }

.il-tl-dot {
    position: absolute;
    left: -22px;
    top: 2px;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid var(--il-border);
    text-align: center;
    line-height: 9px;
}

.il-tl-item.ok   .il-tl-dot { border-color: var(--il-ok); }
.il-tl-item.warn .il-tl-dot { border-color: var(--il-warn); }
.il-tl-item.err  .il-tl-dot { border-color: var(--il-danger); }

.il-tl-line { font-size: .82rem; color: var(--il-ink); line-height: 1.5; }
.il-tl-item.err .il-tl-line { color: var(--il-danger); }

.il-tl-meta {
    font-size: .72rem;
    color: var(--il-muted);
    margin-top: 1px;
}

/* the actor chip - who, in one glance, without reading the sentence */
.il-tl-who { font-weight: 600; color: var(--il-muted); }
.il-tl-who.sys { font-style: italic; }

.il-tl-icon { color: var(--il-muted); width: 14px; text-align: center; }

/* The time carries the row; the date lives in the day heading above it, so it
   is not repeated on eight entries that all happened in the same minute. */
.il-tl-time { font-variant-numeric: tabular-nums; }

/* Entity chip - tells a campaign history that this row is about a stage, without
   shouting it on every line. */
.il-tl-kind {
    display: inline-block;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--il-muted);
    background: var(--il-head);
    border: 1px solid var(--il-border);
    border-radius: 3px;
    padding: 0 4px;
    margin-left: 6px;
    vertical-align: 1px;
}

/* day separator inside a long feed */
.il-tl-day {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--il-muted);
    margin: 16px 0 10px -22px;
    padding: 0 0 4px 22px;
    border-bottom: 1px solid var(--il-border-soft);
    background: var(--il-surface);
}
.il-tl-day:first-child { margin-top: 0; }

/* expandable detail - the diff behind the sentence */
.il-tl-more {
    font-size: .72rem;
    color: var(--il-accent);
    cursor: pointer;
    text-decoration: none;
}
.il-tl-more:hover { text-decoration: underline; }

.il-tl-detail {
    margin-top: 6px;
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius-ctl);
    background: var(--il-head);
    padding: 8px 10px;
    font-size: .76rem;
}

/* A diff, not a form. Label left, value right, one row per change, with the
   label narrow enough that the values line up and can be scanned down. */
.il-tl-detail dl {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(90px, 26%) 1fr;
    gap: 0;
}
.il-tl-detail dt,
.il-tl-detail dd {
    padding: 3px 0;
    border-top: 1px solid var(--il-border-soft);
    font-size: .76rem;
    line-height: 1.4;
}
.il-tl-detail dl > dt:first-of-type,
.il-tl-detail dl > dt:first-of-type + dd { border-top: 0; }

.il-tl-detail dt {
    color: var(--il-muted);
    font-weight: 600;
    padding-right: 12px;
}
.il-tl-detail dd { margin: 0; color: var(--il-ink); word-break: break-word; }

/* a was -> now pair inside the detail */
.il-tl-was { color: var(--il-muted); text-decoration: line-through; }
.il-tl-now { color: var(--il-ink); font-weight: 600; }

/* the destructive schema changes - never collapsed away */
.il-tl-danger { color: var(--il-danger); font-weight: 600; }

.il-tl-empty {
    font-size: .82rem;
    color: var(--il-muted);
    padding: 18px 0;
    text-align: center;
}

/* ============================================================ timeline: major + filters

   Two additions to .il-tl: entries worth spotting, and a way to narrow a long
   history to one subject.

   "Major" is deliberately restrained - a filled dot, a heavier line and a hair
   of background. It must survive being one row in fifty without shouting, and
   it must NOT use the accent colour, which means action-or-active everywhere
   else in this system. */

.il-tl-item.major .il-tl-dot {
    background: var(--il-muted);
    border-color: var(--il-muted);
}
.il-tl-item.major.ok   .il-tl-dot { background: var(--il-ok);     border-color: var(--il-ok); }
.il-tl-item.major.warn .il-tl-dot { background: var(--il-warn);   border-color: var(--il-warn); }
.il-tl-item.major.err  .il-tl-dot { background: var(--il-danger); border-color: var(--il-danger); }

.il-tl-item.major .il-tl-line {
    font-weight: 600;
    background: var(--il-head);
    border-radius: var(--il-radius-ctl);
    padding: 3px 8px;
    margin-left: -8px;
}

/* The filter row. Chips, not a dropdown: the whole point is seeing at a glance
   which subjects this history even contains, and how much of each. */
.il-tl-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--il-border);
}

.il-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .76rem;
    color: var(--il-ink);
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: 999px;
    padding: 3px 11px;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.il-chip:hover { border-color: var(--il-muted); color: var(--il-ink); }

/* Active state IS an active state, so the accent is correct here. */
.il-chip.active {
    background: var(--il-accent);
    border-color: var(--il-accent);
    color: #fff;
    font-weight: 600;
}
.il-chip.active .il-chip-n { color: rgba(255, 255, 255, .85); }

.il-chip-n { color: var(--il-muted); font-variant-numeric: tabular-nums; }

/* The "major only" chip reads as a toggle, not another subject. */
.il-chip.toggle { margin-left: auto; }
.il-chip.toggle.active { background: var(--il-warn); border-color: var(--il-warn); }

/* ============================================================ copyable tokens

   A placeholder like #StudentName is a piece of CODE the admin pastes into
   wording. Bootstrap's solid dark badge shouts, crowds its neighbours and says
   "status", which is the wrong idea entirely - these are quiet, clickable
   fragments. Monospace, hairline border, and a hover that says "you can take
   this". */

.il-token {
    display: inline-block;
    font-family: var(--il-mono);
    font-size: .72rem;
    line-height: 1.6;
    color: var(--il-ink);
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius-ctl);
    padding: 1px 7px;
    margin: 0 4px 4px 0;
    cursor: pointer;
    user-select: all;
    white-space: nowrap;
}

.il-token:hover {
    border-color: var(--il-accent);
    color: var(--il-accent);
    background: var(--il-accent-soft);
}

/* Confirms the click did something - the whole point of a copy chip. */
.il-token.copied {
    border-color: var(--il-ok);
    color: var(--il-ok);
    background: var(--il-ok-soft);
}

.il-token-row { display: flex; flex-wrap: wrap; align-items: center; }


/* ============================================================ admission portal (.ap-)

   The parent-facing skin of Ink & Ledger. Same tokens, one accent, softer:
   more whitespace and larger type, because a parent reads this once, on a
   phone, and often anxiously.

   EVERY selector below is scoped under .ap-portal (set on <body> by
   _layout_admission_portal.cshtml) or an .ap-* class used only there. This
   file is shared with four live admin pages - zero bleed is the rule. */

.ap-portal {
    background: var(--il-canvas);
    color: var(--il-ink);
    -webkit-font-smoothing: antialiased;
}

/* Stops raw {{ }} showing before Vue mounts. */
.ap-portal [v-cloak] { display: none; }

/* ---------------------------------------------------------------- header */

.ap-header {
    background: var(--il-surface);
    border-bottom: 1px solid var(--il-border);
}

.ap-header-logo { max-height: 44px; width: auto; }

/* Not uppercase: a school name is a proper noun, and long ones wrap badly
   in caps on a phone. */
.ap-header-name {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--il-ink);
    line-height: 1.3;
}

.ap-signout {
    color: var(--il-muted);
    font-size: .82rem;
    text-decoration: none;
    white-space: nowrap;
}
.ap-signout:hover { color: var(--il-accent); }

/* ---------------------------------------------------------------- footer */

.ap-footer {
    text-align: center;
    color: var(--il-muted);
    font-size: .82rem;
    padding: 28px 16px 8px;
}

.ap-footer-school { font-weight: 600; color: var(--il-ink); }

.ap-footer-meta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 16px;
    margin-top: 4px;
}
.ap-footer-meta .fa { opacity: .75; margin-right: 4px; }

/* The receipt prints; its chrome does not. */
@media print {
    .ap-footer { display: none; }
}

/* ---------------------------------------------------------------- cards

   These also skin the SHARED form renderer, which emits one .card per section.
   Styling its output from here is how the portal gets panels without the
   renderer being touched - it is frozen, shared with the admin pipeline. */

.ap-portal .card {
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow);
}

.ap-portal .card-body { padding: 1rem; }

@media (min-width: 768px) {
    .ap-portal .card-body { padding: 1.25rem 1.5rem; }
}

.ap-portal .card-title {
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--il-ink);
}
.ap-portal h5.card-title { margin-bottom: .75rem; }

/* ---------------------------------------------------------------- accent

   One rule retires the cyan btn-info the portal used as its primary, without
   touching a single button in the markup. */

.ap-portal .btn {
    padding: .5rem 1rem;
    border-radius: var(--il-radius-ctl);
}
.ap-portal .btn-sm { padding: .25rem .6rem; }

.ap-portal .btn-info {
    background: var(--il-accent);
    border-color: var(--il-accent);
    color: #fff;
}
.ap-portal .btn-info:hover,
.ap-portal .btn-info:active,
.ap-portal .btn-info:focus {
    background: var(--il-accent-ink);
    border-color: var(--il-accent-ink);
    color: #fff;
}
.ap-portal .btn-info:focus-visible {
    box-shadow: 0 0 0 3px var(--il-focus);
}

/* Also catches the renderer's repeater "Add row" button. */
.ap-portal .btn-outline-info {
    color: var(--il-accent);
    border-color: var(--il-accent);
    background: transparent;
}
.ap-portal .btn-outline-info:hover {
    background: var(--il-accent-soft);
    color: var(--il-accent-ink);
    border-color: var(--il-accent);
}

.ap-portal .btn-outline-secondary {
    color: var(--il-ink);
    border-color: var(--il-border);
    background: var(--il-surface);
}
.ap-portal .btn-outline-secondary:hover {
    background: var(--il-canvas);
    color: var(--il-ink);
    border-color: var(--il-muted);
}

/* ---------------------------------------------------------------- form controls */

.ap-portal .form-control,
.ap-portal .form-select {
    border-color: var(--il-border);
    border-radius: var(--il-radius-ctl);
    padding: .55rem .8rem;
    color: var(--il-ink);
}

.ap-portal .form-control:focus,
.ap-portal .form-select:focus {
    border-color: var(--il-accent);
    box-shadow: 0 0 0 3px var(--il-focus);
}

.ap-portal .form-label {
    font-size: .86rem;
    font-weight: 600;
    color: var(--il-ink);
    margin-bottom: 4px;
}

/* Said at the field, not in a modal. */
.ap-field-error {
    font-size: .8rem;
    color: var(--il-danger);
    margin-top: 4px;
}

/* ---------------------------------------------------------------- landing */

.ap-hero { text-align: center; margin-bottom: 24px; }

.ap-hero h1 {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--il-ink);
    margin-bottom: 6px;
}

.ap-hero-tagline {
    color: var(--il-muted);
    font-size: .9rem;
    max-width: 46ch;
    margin: 0 auto;
}

/* A class on offer. Deliberately NOT .il-chip - that one is a control and
   carries cursor:pointer; these are read, not clicked. */
.ap-chip {
    display: inline-block;
    font-size: .8rem;
    color: var(--il-ink);
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: 999px;
    padding: 3px 11px;
    margin: 0 6px 6px 0;
}
.ap-chip .ap-chip-medium { color: var(--il-muted); }
.ap-chip .ap-chip-fee { color: var(--il-muted); }

.ap-closes {
    font-size: .8rem;
    color: var(--il-muted);
}
.ap-closes.soon {
    color: var(--il-warn);
    font-weight: 600;
}

.ap-login { max-width: 460px; margin: 0 auto; }

.ap-otp {
    font-size: 1.5rem;
    letter-spacing: .5em;
    text-align: center;
    font-family: var(--il-mono);
    padding-left: .5em;
}

/* ---------------------------------------------------------------- empty states */

.ap-empty {
    border: 1px dashed #cbd2dc;
    border-radius: var(--il-radius);
    background: var(--il-surface);
    padding: 32px 16px;
    text-align: center;
    color: var(--il-muted);
    font-size: .88rem;
}
.ap-empty .fa {
    font-size: 1.6rem;
    display: block;
    margin-bottom: 8px;
    opacity: .5;
}

/* ---------------------------------------------------------------- dashboard */

.ap-page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.ap-page-head h1 {
    font-size: 1.35rem;
    font-weight: 700;
    margin: 0;
    color: var(--il-ink);
}

/* Keeps the server-sent StageColor as its inline background. */
.ap-portal .badge.ap-stage {
    border-radius: 999px;
    padding: .35em .9em;
    font-weight: 600;
    font-size: .74rem;
}

.ap-feeline { font-size: .85rem; margin-top: 2px; }
.ap-feeline.due { color: var(--il-danger); }
.ap-feeline.paid { color: var(--il-ok); }

/* ---------------------------------------------------------------- apply */

.ap-form { margin-bottom: 16px; }

/* Always in reach, however long the form runs. */
.ap-actionbar {
    position: sticky;
    bottom: 0;
    z-index: 30;
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-bottom: 0;
    border-radius: var(--il-radius) var(--il-radius) 0 0;
    box-shadow: 0 -4px 16px rgba(16, 24, 40, .08);
    padding: 12px 16px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    justify-content: space-between;
}

.ap-actionbar-meta {
    font-size: .8rem;
    color: var(--il-muted);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
}

.ap-secpill {
    font-size: .75rem;
    background: var(--il-canvas);
    border-radius: 999px;
    padding: 2px 10px;
    color: var(--il-muted);
}

.ap-secnav {
    position: sticky;
    top: 16px;
    font-size: .84rem;
}

.ap-secnav-head {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--il-muted);
    margin-bottom: 8px;
    padding-left: 12px;
}

.ap-secnav a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-left: 2px solid transparent;
    color: var(--il-muted);
    text-decoration: none;
    cursor: pointer;
}
.ap-secnav a:hover { color: var(--il-ink); background: var(--il-head); }

.ap-secnav a.active {
    border-left-color: var(--il-accent);
    color: var(--il-ink);
    font-weight: 600;
}
.ap-secnav a.done .ap-secnav-ic { color: var(--il-ok); }
.ap-secnav a.err { color: var(--il-danger); }
.ap-secnav a.err .ap-secnav-ic { color: var(--il-danger); }

.ap-secnav-ic { width: 14px; text-align: center; opacity: .8; }
.ap-secnav-label { flex: 1 1 auto; }

.ap-secnav-n {
    font-size: .7rem;
    font-weight: 700;
    color: var(--il-danger);
    background: var(--il-danger-soft);
    border-radius: 999px;
    padding: 0 6px;
}

/* ---------------------------------------------------------------- readonly view

   The shared renderer implements readonly as :disabled, so a submitted
   application arrives as a grey dead form. This makes it read as a document
   instead - without touching the renderer. */

.ap-flat .form-control:disabled,
.ap-flat .form-select:disabled {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    padding-left: 0;
    color: var(--il-ink);
    /* iOS Safari greys disabled text whatever `color` says. */
    -webkit-text-fill-color: var(--il-ink);
    opacity: 1;
    appearance: none;
    -webkit-appearance: none;
    background-image: none;   /* kills the select chevron */
    cursor: default;
}

.ap-flat textarea.form-control:disabled { resize: none; }

.ap-flat .form-label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--il-muted);
    margin-bottom: 2px;
}

/* Radios and checkboxes cannot become plain text without losing WHICH option
   was chosen, so they stay visible and the unchosen ones dim instead. */
.ap-flat .form-check-input:disabled,
.ap-flat .form-check-input:disabled ~ .form-check-label {
    opacity: 1;
    cursor: default;
}
.ap-flat .form-check-input:disabled:not(:checked),
.ap-flat .form-check-input:disabled:not(:checked) ~ .form-check-label {
    opacity: .45;
}

.ap-portal .table > :not(caption) > * > * { border-color: var(--il-border-soft); }

/* ---------------------------------------------------------------- receipt */

.ap-receipt-logo {
    max-height: 60px;
    width: auto;
    margin-bottom: 8px;
}

/* ---------------------------------------------------------------- focus floor */

.ap-signout:focus-visible,
.ap-secnav a:focus-visible,
.ap-chip:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--il-focus);
    border-radius: var(--il-radius-ctl);
}


/* ---------------------------------------------------------------- photograph cropper

   A plain overlay, deliberately not a Bootstrap modal: the portal ships no Bootstrap JS and
   this must not be the reason it comes back. Jcrop supplies its own .jcrop-* chrome inside
   .ap-cropper-stage; everything here is the frame around it.                              */

.ap-cropper {
    position: fixed;
    inset: 0;
    z-index: 1080;
    background: rgba(15, 23, 42, .62);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    overflow-y: auto;
}

.ap-cropper-box {
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: 0 24px 64px rgba(15, 23, 42, .28);
    width: 100%;
    max-width: 760px;
    max-height: calc(100vh - 32px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.ap-cropper-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 18px;
    border-bottom: 1px solid var(--il-border-soft);
}

.ap-cropper-title {
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--il-ink);
}

.ap-cropper-sub {
    font-size: .85rem;
    color: var(--il-muted);
    margin-top: 2px;
}

.ap-cropper-x {
    margin-left: auto;
    color: var(--il-muted);
    text-decoration: none;
    font-size: 1.1rem;
    line-height: 1;
    padding: 4px 6px;
    border-radius: var(--il-radius-ctl);
}

.ap-cropper-x:hover { color: var(--il-ink); background: var(--il-head); }

.ap-cropper-body {
    display: flex;
    gap: 18px;
    padding: 18px;
    overflow-y: auto;
}

/* Jcrop measures this element to size the image, so it must have a real width before init. */
.ap-cropper-stage {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

.ap-cropper-stage img { display: block; }

.ap-cropper-side {
    flex: 0 0 auto;
    width: 148px;
    text-align: center;
}

.ap-cropper-preview-label {
    font-size: .72rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--il-muted);
    margin-bottom: 6px;
}

/* The preview img is oversized and offset by inline styles; this clips it to the crop. */
.ap-cropper-preview {
    overflow: hidden;
    margin: 0 auto;
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius-ctl);
    background: var(--il-head);
    width: 132px;
    height: 158px;
}

.ap-cropper-preview img { display: block; max-width: none; }

.ap-cropper-note {
    font-size: .74rem;
    color: var(--il-muted);
    margin-top: 8px;
}

.ap-cropper-foot {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-top: 1px solid var(--il-border-soft);
    background: var(--il-head);
}

.ap-cropper-err {
    color: var(--il-danger);
    font-size: .85rem;
}

/* Below md the preview column costs more room than it earns - the crop box itself is the
   preview at that size. */
@media (max-width: 767.98px) {
    .ap-cropper { padding: 0; align-items: stretch; }
    .ap-cropper-box { max-width: none; border-radius: 0; border: 0; max-height: 100vh; }
    .ap-cropper-body { flex-direction: column; padding: 12px; }
    .ap-cropper-side { width: auto; }
    .ap-cropper-foot { position: sticky; bottom: 0; }
}


/* ---------------------------------------------------------------- read-only application view

   The photograph, the empty-field dash and the payment chips. `.adm-file-thumb` is the one
   selector here that is NOT .ap- prefixed: it belongs to the shared renderer's file field, which
   is also mounted by the admin pipeline, so it deliberately applies in both places.            */

.ap-idphoto {
    flex: 0 0 auto;
    display: block;
    width: 64px;
    height: 77px;                        /* 5:6 - the ratio the cropper stores */
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius-ctl);
    overflow: hidden;
    background: var(--il-head);
    text-decoration: none;
}

.ap-idphoto img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* No photograph, or a SAS link that died while the page sat open. */
.ap-idphoto-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.75rem;
    font-weight: 600;
    color: var(--il-faint);
    user-select: none;
}

/* An empty disabled control is still a full-height box, and a rows="3" textarea is three
   blank lines. Collapsed to one quiet dash - the dash itself is a placeholder set by
   ViewApplication.js, because CSS cannot ask whether an input is empty. */
.ap-flat .ap-empty {
    height: calc(1.5em + 8px);
    min-height: 0;
}

.ap-flat .ap-empty::placeholder {
    color: var(--il-faint);
    opacity: 1;
}

/* Required markers mean nothing where nothing can be edited. Errors never render in
   readonly mode, so this class has no other use inside a flat form. */
.ap-flat .form-label .text-danger { display: none; }

/* ---------------------------------------------------------------- payment status chips */

.ap-paychip {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}

.ap-paychip.ok   { color: var(--il-ok);     background: var(--il-ok-soft); }
.ap-paychip.warn { color: var(--il-warn);   background: var(--il-warn-soft); }
.ap-paychip.bad  { color: var(--il-danger); background: var(--il-danger-soft); }

/* ---------------------------------------------------------------- file field thumbnail

   Shared-renderer selector, intentionally un-prefixed: the admin pipeline's Form tab mounts
   the same component and should show the same thumbnail. */

.adm-file-thumb {
    display: inline-block;
    width: 56px;
    height: 67px;
    margin-bottom: 4px;
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius-ctl);
    overflow: hidden;
    background: var(--il-head);
}

.adm-file-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ---------------------------------------------------------------- identity panel

   Who this is, where it stands, what is owed, and what can be done about it - in ONE
   panel. It used to be a bare header block plus a separate status card: two stacked
   boxes doing one job, which cost most of a screen before the form even began.        */

.ap-backlink {
    display: inline-block;
    margin-bottom: 10px;
    font-size: .85rem;
    color: var(--il-muted);
    text-decoration: none;
}

.ap-backlink:hover { color: var(--il-accent); }

.ap-idcard {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    background: var(--il-surface);
    border: 1px solid var(--il-border);
    border-radius: var(--il-radius);
    box-shadow: var(--il-shadow);
    padding: 14px 16px;
    margin-bottom: 14px;
}

.ap-idmain {
    flex: 1 1 auto;
    min-width: 0;
}

.ap-idtop {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 2px;
}

.ap-idname {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--il-ink);
    margin: 0;
    line-height: 1.25;
}

.ap-idmeta {
    font-size: .84rem;
    color: var(--il-muted);
    line-height: 1.5;
}

.ap-idactions {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.ap-receiptlink {
    font-size: .8rem;
    text-decoration: none;
    white-space: nowrap;
}

/* ---------------------------------------------------------------- read-only density

   A submitted application is a document to be read, not a form to be worked through, so
   it gets tighter than the editable version: the reader wants the whole of a section on
   screen at once. Scoped to .ap-flat, so Apply is untouched.                            */

.ap-flat .card { margin-bottom: 12px; }
.ap-flat .card-body { padding: 14px 16px; }

.ap-flat .card-title,
.ap-flat h5 {
    font-size: .95rem;
    font-weight: 700;
    color: var(--il-ink);
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--il-border-soft);
}

/* Bootstrap's mb-3 on every field is spacing for touch targets. Nothing here is a
   target. */
.ap-flat .row > [class*="col-"] { margin-bottom: 0 !important; padding-bottom: 10px; }

.ap-flat .form-control:disabled,
.ap-flat .form-select:disabled {
    min-height: 0;
    height: auto;
    padding-top: 0;
    padding-bottom: 0;
    font-size: .9rem;
}

@media (max-width: 575.98px) {
    .ap-idphoto { width: 56px; height: 67px; }
    .ap-idphoto-empty { font-size: 1.35rem; }
    .ap-idcard { flex-wrap: wrap; gap: 12px; }
    .ap-idactions { width: 100%; justify-content: flex-start; }
    .ap-idname { font-size: 1.15rem; }
}


/* ---------------------------------------------------------------- browser print

   Printing proper is a server-composed PDF now (AdmApplicationPdf, reached from the Print
   button) - a browser's output depends on the viewer's page size, margins and
   "print backgrounds" setting, so no two copies of one application matched.

   These rules remain for the person who hits Ctrl+P anyway: they keep the site header,
   the action buttons and the footer off the paper, and force ink-black text. The
   letterhead and signature blocks that used to live here went with the markup that
   carried them - the PDF has its own.                                                   */

@media print {

    @page { margin: 14mm 12mm; }

    header,
    .ap-footer,
    .ap-backlink,
    .adm-no-print { display: none !important; }

    .ap-idactions { display: none !important; }

    body,
    .ap-portal { background: #fff !important; }

    /* The layout centres content in a Bootstrap .container and the page caps itself at
       900px - both screen ergonomics. @page already sets the margin; anything else here
       is margin inside a margin. #app carries an inline max-width, hence !important. */
    .ap-portal .container {
        max-width: none !important;
        width: 100% !important;
        padding: 0 !important;
    }

    .ap-portal #app {
        max-width: none !important;
        margin: 0 !important;
    }

    /* Ink, not brand colour - a photocopy of a grey form is unreadable. */
    .ap-portal,
    .ap-portal .text-muted,
    .ap-flat .form-label { color: #000 !important; }

    .ap-flat .form-control:disabled,
    .ap-flat .form-select:disabled {
        color: #000 !important;
        -webkit-text-fill-color: #000 !important;
        border-bottom: 1px dotted #999 !important;
        border-radius: 0 !important;
    }

    .ap-portal .card {
        border: 0 !important;
        box-shadow: none !important;
        page-break-inside: avoid;
    }

    .ap-flat .card-title,
    .ap-flat h5 {
        border-bottom: 1px solid #000 !important;
        page-break-after: avoid;
    }

    /* A single field must never be split across a page. */
    .ap-flat .row > [class*="col-"] { page-break-inside: avoid; }

    .ap-receiptlink { display: none !important; }
}
