/* ═══════════════════════════════════════════════════════════════════════
   ADMITTED — parent portal at meritparity.org
   ═══════════════════════════════════════════════════════════════════════
   Standalone. Portal pages deliberately do NOT load /static/style.css:
   that file is the Votersaurus voter-tool chrome (Inter, blue primary,
   white ground) and a parent paying for a college-fit report should never
   see another company's product furniture.

   Palette and type are lifted from the public MeritParity pages in
   app/static/admit-the-truth/ — khaki ground, ink header, gold kicker,
   Georgia headlines — so the portal reads as the same site the parent
   already knows.

   Contrast note: the house "faint" khaki (#8d8571) is 3.2:1 on the khaki
   ground, which fails AA for body text. It is used here only for rules,
   placeholders and separators; every piece of real text uses --rec-ink,
   --rec-ink-2 (7.4:1) or --rec-ink-3 (4.7:1).
   ═══════════════════════════════════════════════════════════════════════ */

:root {
    --rec-ground: #f4f0e6;
    --rec-ground-2: #ece5d4;   /* hover / table head wash */
    --rec-surface: #fbf8f1;
    --rec-ink: #2b2b2b;
    --rec-ink-2: #514c40;
    --rec-ink-3: #6f6a5e;
    --rec-faint: #8d8571;      /* decorative only — see note above */
    --rec-rule: #e2dac8;
    --rec-rule-2: #cfc7b3;
    --rec-gold: #BE8A2F;
    --rec-gold-deep: #9A6A1F;
    --rec-green: #2F6B5E;
    --rec-green-deep: #24544a;
    --rec-error: #a4442e;
    --rec-radius: 4px;
    --rec-serif: Georgia, 'Times New Roman', serif;
    --rec-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                'Helvetica Neue', Arial, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--rec-sans);
    background: var(--rec-ground);
    color: var(--rec-ink);
    font-size: 16px;
    line-height: 1.55;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* ── Focus. Visible on every interactive thing, gold when it lands on the
      dark header where green would disappear. ── */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid var(--rec-green);
    outline-offset: 2px;
}
.portal-head a:focus-visible,
.portal-head button:focus-visible,
.portal-impersonation button:focus-visible {
    outline-color: var(--rec-gold);
}

.portal-skip {
    position: absolute; left: -9999px; top: 0; z-index: 100;
    background: var(--rec-surface); color: var(--rec-ink);
    padding: 10px 16px; border: 2px solid var(--rec-green);
    border-radius: 0 0 var(--rec-radius) 0; font-size: 14px; font-weight: 600;
    text-decoration: none;
}
.portal-skip:focus { left: 0; }

/* ═══ Chrome ═══ */

.portal-impersonation {
    background: var(--rec-gold); color: #2b2b2b;
    font-size: 13px; padding: 7px 20px; text-align: center;
}
.portal-impersonation form { display: inline; margin-left: 12px; }
.portal-impersonation button {
    font: inherit; font-weight: 600; cursor: pointer;
    background: rgba(43, 43, 43, 0.12); color: inherit;
    border: 1px solid rgba(43, 43, 43, 0.4); border-radius: 3px;
    padding: 2px 10px;
}

.portal-head { background: var(--rec-ink); color: var(--rec-ground); }
.portal-head-inner {
    max-width: 1060px; margin: 0 auto; padding: 16px 20px;
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px; flex-wrap: wrap;
}
.portal-brand { text-decoration: none; color: inherit; display: block; }
.portal-kicker {
    display: block; font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 1.6px; color: var(--rec-gold);
}
.portal-wordmark {
    display: block; font-family: var(--rec-serif); font-size: 25px;
    font-weight: 400; letter-spacing: 0.2px; line-height: 1.15;
}
.portal-head-right {
    display: flex; align-items: center; gap: 14px; font-size: 13px;
}
.portal-who {
    color: rgba(244, 240, 230, 0.75); max-width: 230px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.portal-signout {
    color: var(--rec-ground); text-decoration: none; font-size: 13px;
    border: 1px solid rgba(244, 240, 230, 0.4); border-radius: 3px;
    padding: 7px 13px; white-space: nowrap;
}
.portal-signout:hover { background: rgba(244, 240, 230, 0.14); }

.portal-main {
    flex: 1; width: 100%; max-width: 1060px; margin: 0 auto;
    padding: 24px 20px 56px;
}

.portal-foot {
    border-top: 1px solid var(--rec-rule);
    background: var(--rec-ground);
}
.portal-foot-inner {
    max-width: 1060px; margin: 0 auto; padding: 16px 20px 28px;
    display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
    font-size: 12.5px; color: var(--rec-ink-3);
}
.portal-foot-links { display: flex; gap: 16px; flex-wrap: wrap; }
.portal-foot a { color: var(--rec-green); text-decoration: none; }
.portal-foot a:hover { text-decoration: underline; }

/* ═══ Page head ═══ */

.portal-header {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.portal-header > .portal-btn { margin-top: 12px; }
.portal-eyebrow {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 1.6px; color: var(--rec-gold-deep); margin-bottom: 3px;
}
.portal-title {
    font-family: var(--rec-serif); font-size: 31px; font-weight: 400;
    line-height: 1.15; letter-spacing: 0.2px; margin: 0;
}
.portal-sub {
    color: var(--rec-ink-2); font-size: 15px; margin: 6px 0 0; max-width: 58ch;
}

/* ═══ Buttons ═══ */

.portal-btn {
    display: inline-block; background: var(--rec-green); color: #f4f0e6;
    border: 1px solid var(--rec-green); border-radius: 3px;
    padding: 11px 20px; font-family: var(--rec-sans); font-size: 15px;
    font-weight: 600; line-height: 1.2; text-decoration: none; cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.portal-btn:hover { background: var(--rec-green-deep); border-color: var(--rec-green-deep); }
.portal-btn-sm { padding: 7px 13px; font-size: 13px; }
.portal-btn-ghost {
    background: var(--rec-surface); color: var(--rec-green);
    border-color: var(--rec-rule-2);
}
.portal-btn-ghost:hover {
    background: var(--rec-ground-2); border-color: var(--rec-green);
    color: var(--rec-green-deep);
}
.portal-btn-wide { width: 100%; text-align: center; }

/* ═══ Two-pane layout ═══ */

/* The detail pane was a fixed 420px when it held a dozen facts. It now holds
   the whole product — a course table off a transcript, six sliders, a
   conversation — so it takes whatever is left over the list, up to 660px,
   which is the width the course table needs before it starts scrolling
   sideways. The list keeps its four columns; it is 1-3 rows for most families
   and does not need the room. */
.portal-layout {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(430px, 660px);
    gap: 20px; align-items: start;
}
.portal-pane {
    min-width: 0; background: var(--rec-surface);
    border: 1px solid var(--rec-rule); border-radius: var(--rec-radius);
    box-shadow: 0 1px 2px rgba(43, 43, 43, 0.08); overflow: hidden;
}
.portal-detail {
    background: var(--rec-surface);
    border: 1px solid var(--rec-rule); border-top: 4px solid var(--rec-gold);
    border-radius: var(--rec-radius);
    box-shadow: 0 1px 2px rgba(43, 43, 43, 0.08);
}
.portal-detail-inner { padding: 18px 20px 24px; }
.portal-detail-head {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 12px; margin-bottom: 14px;
}
.portal-detail-name {
    font-family: var(--rec-serif); font-size: 21px; font-weight: 400;
    line-height: 1.2; margin: 0;
}
.portal-detail-meta { font-size: 13px; color: var(--rec-ink-3); margin-top: 3px; }

/* ═══ Student list ═══
   Rows are real <button> elements, so Enter and Space work, they land in the
   tab order once each, and a screen reader announces them as buttons.

   The four-column grid this list used to have is gone. The detail pane now
   takes up to 660px of a 1020px content column, which leaves the list about
   340px at every desktop width — and four columns in 340px means "11th …"
   and "Martin Lut…", which is worse than no columns at all. The name gets its
   own line and the rest runs in below it, dot-separated: the same shape the
   phone already used, now everywhere, so there is one row design rather than
   two that disagree about which one you are looking at. ═══ */

.portal-row {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px;
    width: 100%; text-align: left; padding: 13px 16px;
    border: 0; border-bottom: 1px solid var(--rec-rule);
    background: transparent; font: inherit; color: inherit;
}
button.portal-row { cursor: pointer; }
button.portal-row:hover { background: var(--rec-ground-2); }
button.portal-row:last-child { border-bottom: 0; }
.portal-row-name {
    flex: 0 0 100%; margin-bottom: 1px;
    font-family: var(--rec-serif); font-size: 17.5px; font-weight: 400;
}
.portal-row-meta:not(:last-child)::after {
    content: "·"; margin-left: 8px; color: var(--rec-faint);
}
button.portal-row:hover .portal-row-name { color: var(--rec-green); }
.portal-row-meta {
    font-size: 13.5px; color: var(--rec-ink-3);
}

/* ═══ Read view ═══ */

.portal-facts {
    display: grid; grid-template-columns: auto minmax(0, 1fr);
    gap: 7px 16px; font-size: 14.5px; margin: 0;
}
.portal-facts dt {
    color: var(--rec-ink-3); font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.9px; padding-top: 3px;
}
.portal-facts dd { margin: 0; }

.portal-block {
    border-top: 1px solid var(--rec-rule); padding-top: 14px; margin-top: 16px;
}
.portal-block h3 {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 1.2px; color: var(--rec-gold-deep); margin: 0 0 7px;
}
.portal-longtext { font-size: 14.5px; white-space: pre-wrap; }
.portal-soon {
    background: var(--rec-ground); border: 1px solid var(--rec-rule);
    border-left: 4px solid var(--rec-green); border-top: 0;
    border-radius: 3px; padding: 12px 15px; margin-top: 18px;
}
.portal-soon h3 { color: var(--rec-green); }
.portal-note { font-size: 14px; color: var(--rec-ink-2); line-height: 1.55; margin: 5px 0; }
.portal-meta-line { font-size: 12px; color: var(--rec-ink-3); margin-top: 18px; }
.portal-hint {
    font-weight: 400; text-transform: none; letter-spacing: 0;
    color: var(--rec-ink-3);
}

.portal-empty {
    padding: 26px 20px; text-align: center;
    font-size: 14.5px; color: var(--rec-ink-2);
}
.portal-empty strong {
    display: block; font-family: var(--rec-serif); font-weight: 400;
    font-size: 19px; color: var(--rec-ink); margin-bottom: 4px;
}

/* ═══ Form ═══ */

.portal-form { display: flex; flex-direction: column; gap: 14px; }
.portal-form label {
    display: flex; flex-direction: column; gap: 5px;
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.9px; color: var(--rec-ink-2);
}
.portal-form input,
.portal-form select,
.portal-form textarea {
    width: 100%; border: 1px solid var(--rec-rule-2); border-radius: 3px;
    padding: 10px 11px; font-family: var(--rec-sans); font-size: 15px;
    font-weight: 400; text-transform: none; letter-spacing: normal;
    color: var(--rec-ink); background: #fff;
}
/* --rec-faint would be 3.7:1 on the white field; ink-3 is 5.4:1. */
.portal-form input::placeholder,
.portal-form textarea::placeholder { color: var(--rec-ink-3); }
.portal-form textarea { resize: vertical; line-height: 1.5; }
.portal-form-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.portal-form-pair > label > input,
.portal-form-pair > label > select { margin-top: auto; }
.portal-form button { align-self: flex-start; margin-top: 4px; }

/* A label plus explanatory copy under the input. The note sits outside the
   <label> so it doesn't get read out as part of the field's name — it's tied
   on with aria-describedby instead — and needs its own reset because
   .portal-form label's uppercase letterspacing is unreadable at sentence
   length. ink-2 is 7.4:1 on the pane, so this stays body copy, not fine print. */
.portal-field { display: flex; flex-direction: column; gap: 6px; }
.portal-field-note {
    margin: 0; max-width: 62ch;
    font-size: 13px; line-height: 1.55; color: var(--rec-ink-2);
    font-weight: 400; text-transform: none; letter-spacing: normal;
}

/* ═══ Net price calculators ═══
   A family's own quote against our published average. The list reads as
   record rows (name, money, verdict) with the comparison run underneath in
   smaller type, because the comparison is the argument and the number is the
   fact. The three verdict pills reuse the report's own colour logic: green
   for affordable, gold for a stretch, red-brown for out of reach. */

.portal-npc-list { list-style: none; margin: 14px 0 4px; padding: 0; }
.portal-npc-item {
    background: var(--rec-ground); border: 1px solid var(--rec-rule);
    border-left: 4px solid var(--rec-rule-2); border-radius: 3px;
    padding: 11px 14px; margin-bottom: 8px;
}
/* The row being edited, so the form below it is obviously about this one. */
.portal-npc-item.is-editing { border-left-color: var(--rec-gold); background: var(--rec-surface); }

.portal-npc-head {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
}
.portal-npc-college {
    font-family: var(--rec-serif); font-size: 17px; color: var(--rec-ink);
    flex: 1 1 auto; min-width: 0;
}
.portal-npc-amount { font-size: 15px; font-weight: 700; color: var(--rec-ink); }
.portal-npc-pill {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.7px; border-radius: 2px; padding: 3px 7px;
    border: 1px solid var(--rec-rule-2); color: var(--rec-ink-2);
    background: var(--rec-surface); white-space: nowrap;
}
.portal-npc-good { border-color: #b6cdbe; background: #e7f0ea; color: #1f5044; }
.portal-npc-thin { border-color: #e3d3a9; background: #f6efdd; color: #6d4d13; }
.portal-npc-none { border-color: #e0bcb1; background: #f7e7e2; color: #7d3323; }

.portal-npc-compare { font-size: 13px; color: var(--rec-ink-2); margin-top: 3px; }
.portal-npc-note {
    font-size: 13.5px; color: var(--rec-ink-2); margin: 6px 0 0;
    font-style: italic;
}
.portal-npc-actions { display: flex; gap: 8px; margin-top: 9px; }

.portal-npc-empty { margin: 12px 0 4px; }

.portal-npc-form {
    background: var(--rec-surface); border: 1px solid var(--rec-rule);
    border-top: 3px solid var(--rec-gold); border-radius: 3px;
    padding: 14px 15px 16px; margin-top: 14px; gap: 12px;
}
.portal-npc-formtitle {
    font-family: var(--rec-serif); font-size: 17px; font-weight: 400;
    color: var(--rec-ink); margin: 0;
}
/* A standalone <label for> rather than a wrapping one, because the
   suggestion list has to sit outside the label to stay out of its accessible
   name. Same look as .portal-form label. */
.portal-npc-label {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.9px; color: var(--rec-ink-2);
}
.portal-npc-collegefield { position: relative; gap: 5px; }
.portal-npc-formactions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.portal-npc-formactions .portal-btn { margin-top: 0; }

/* The type-ahead. Absolute so it covers the hint underneath rather than
   shoving the rest of the form down a line on every keystroke. */
.portal-sug {
    position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
    margin-top: 2px; max-height: 244px; overflow-y: auto;
    background: #fff; border: 1px solid var(--rec-rule-2); border-radius: 3px;
    box-shadow: 0 4px 14px rgba(43, 43, 43, 0.16);
}
.portal-sug[hidden] { display: none; }
.portal-sug div {
    padding: 9px 12px; font-size: 14.5px; cursor: pointer;
    border-bottom: 1px solid var(--rec-rule);
    text-transform: none; letter-spacing: normal; font-weight: 400;
    color: var(--rec-ink);
}
.portal-sug div:last-child { border-bottom: 0; }
.portal-sug div:hover, .portal-sug div.on { background: var(--rec-ground-2); }
.portal-sug small {
    display: block; color: var(--rec-ink-3); font-size: 12px; margin-top: 1px;
}

/* ═══ Gate / auth ═══ */

.portal-gate {
    max-width: 620px; margin: 40px auto;
    background: var(--rec-surface); border: 1px solid var(--rec-rule);
    border-top: 4px solid var(--rec-gold); border-radius: var(--rec-radius);
    box-shadow: 0 1px 3px rgba(43, 43, 43, 0.09);
    padding: 30px 32px 34px; text-align: center;
}
.portal-gate .portal-title { font-size: 26px; margin-bottom: 12px; }
.portal-gate a { color: var(--rec-green); font-weight: 600; }

.portal-auth {
    max-width: 430px; margin: 34px auto 12px;
    background: var(--rec-surface); border: 1px solid var(--rec-rule);
    border-top: 4px solid var(--rec-gold); border-radius: var(--rec-radius);
    box-shadow: 0 1px 3px rgba(43, 43, 43, 0.09);
    padding: 28px 30px 32px;
}
.portal-auth .portal-title { font-size: 26px; }
.portal-auth .portal-sub { margin-bottom: 20px; }
.portal-auth .portal-form label { font-size: 11.5px; }
.portal-auth .portal-form button { align-self: stretch; margin-top: 8px; }
.portal-auth-foot {
    max-width: 430px; margin: 0 auto; text-align: center;
    font-size: 13.5px; color: var(--rec-ink-2);
}
.portal-auth-foot a { color: var(--rec-green); font-weight: 600; }

/* The signup door. Wider than sign-in because it has to make the case as well
   as take the fields — a stranger arriving from an ad has never seen any of
   this before. */
.portal-auth-wide { max-width: 560px; }
.portal-auth-wide .portal-title { font-size: 28px; line-height: 1.2; }
.portal-start-list {
    list-style: none; margin: 4px 0 22px; padding: 0;
    border-top: 1px solid var(--rec-rule);
}
.portal-start-list li {
    border-bottom: 1px solid var(--rec-rule);
    padding: 11px 0 11px 22px; position: relative;
    font-size: 14.5px; line-height: 1.55; color: var(--rec-ink-2);
}
.portal-start-list li:before {
    content: ""; position: absolute; left: 2px; top: 18px;
    width: 7px; height: 7px; border-radius: 50%; background: var(--rec-gold);
}
.portal-start-list li b { color: var(--rec-ink); font-weight: 700; }
.portal-optional {
    font-weight: 400; text-transform: none; letter-spacing: 0;
    color: var(--rec-ink-3); font-size: 11.5px;
}
.portal-hint {
    display: block; margin-top: 5px; font-weight: 400;
    text-transform: none; letter-spacing: 0;
    font-size: 12px; color: var(--rec-ink-3);
}
/* Off-screen rather than display:none — a bot reading the DOM fills what it
   can see in the markup, and a screen reader is told to skip the wrapper. */
.portal-hp {
    position: absolute; left: -9999px; width: 1px; height: 1px;
    overflow: hidden;
}
.portal-start-fine {
    margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--rec-rule);
    font-size: 13px; line-height: 1.55; color: var(--rec-ink-3);
}
.portal-start-fine b { color: var(--rec-ink-2); font-weight: 700; }
.portal-note-fine { font-size: 13px; color: var(--rec-ink-3); line-height: 1.55; }
/* Assent, at the moment assent matters. Terms nobody was shown are terms a
   California court will not enforce, and the clauses that matter most are
   exactly the ones a browsewrap loses. */
.portal-assent {
    font-size: 12.5px; line-height: 1.55; color: var(--rec-ink-3);
    margin: 2px 0 0; padding-top: 12px; border-top: 1px solid var(--rec-rule);
}
.portal-assent b { color: var(--rec-ink-2); }
.portal-assent a { color: var(--rec-green); font-weight: 600; }
.portal-legal-foot { max-width: 560px; margin: 26px auto 0; padding-top: 14px;
    border-top: 1px solid var(--rec-rule); }
.portal-legal-foot nav { display: flex; flex-wrap: wrap; gap: 5px 16px; margin-bottom: 9px; }
.portal-legal-foot nav a { font-size: 12px; color: var(--rec-ink-3); text-decoration: none; }
.portal-legal-foot nav a:hover { color: var(--rec-ink); text-decoration: underline; }
.portal-legal-foot p { font-size: 11px; line-height: 1.55; color: var(--rec-faint); margin: 0; }

.portal-alert {
    border-radius: 3px; padding: 11px 14px; margin-bottom: 16px;
    font-size: 14px; line-height: 1.45;
}
.portal-alert-error {
    background: #f7e7e2; border: 1px solid #e0bcb1;
    border-left: 4px solid var(--rec-error); color: #7d3323;
}
.portal-alert-warn {
    background: #f6efdd; border: 1px solid #e3d3a9;
    border-left: 4px solid var(--rec-gold); color: #6d4d13;
}

/* ═══ Toasts ═══ */

#toast-container {
    position: fixed; right: 16px; bottom: 16px; z-index: 90;
    display: flex; flex-direction: column; gap: 8px;
    max-width: calc(100vw - 32px);
}
.portal-toast {
    background: var(--rec-ink); color: var(--rec-ground);
    border-left: 4px solid var(--rec-green); border-radius: 3px;
    box-shadow: 0 3px 12px rgba(43, 43, 43, 0.28);
    padding: 11px 14px; font-size: 14px;
    display: flex; align-items: center; gap: 12px;
    opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s;
}
.portal-toast.is-shown { opacity: 1; transform: none; }
.portal-toast-warning, .portal-toast-error { border-left-color: var(--rec-gold); }
.portal-toast button {
    background: none; border: 0; color: inherit; font-size: 18px;
    line-height: 1; cursor: pointer; opacity: 0.7; padding: 0 2px;
}
.portal-toast button:hover { opacity: 1; }

/* ═══ Screen-reader-only ═══ */

.portal-sr, .portal-sr-label > span:first-child {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.portal-sr-label { display: flex; flex-direction: column; gap: 5px; }

/* ═══ Grouped form ═══
   The student form runs to twenty-odd boxes and gets filled in over several
   sittings. A wall of inputs does not get filled in, so it is cut into
   sections a parent has in front of them at one moment — the transcript, the
   sports, the money — with a rule and a gold legend so the seams are visible
   while scrolling a phone. */

.portal-fieldset {
    border: 0; border-top: 1px solid var(--rec-rule); margin: 0;
    padding: 16px 0 4px; display: flex; flex-direction: column; gap: 14px;
    /* A <fieldset> defaults to min-inline-size: min-content, so the 560px
       course table inside one pushes it — and the whole page — wider than a
       390px phone. Both properties, because the shorthand is what older Safari
       reads and the logical one is what Chrome respects. */
    min-width: 0; min-inline-size: 0;
}
.portal-fieldset:first-of-type { border-top: 0; padding-top: 0; }
.portal-fieldset > legend {
    padding: 0 8px 0 0; font-family: var(--rec-serif); font-size: 17px;
    color: var(--rec-ink); font-weight: 400;
}
.portal-form-actions {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    border-top: 1px solid var(--rec-rule); padding-top: 16px;
}
.portal-form-actions .portal-btn { margin-top: 0; }
.portal-draft-note { font-size: 12.5px; color: var(--rec-ink-3); }
.portal-draft-bar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.portal-draft-bar .portal-btn { margin-top: 0; }

/* "What you wrote here before" — the free-text GPA and score boxes this form
   used to have. Folded away, never removed: dropping a parent's own sentence
   to tidy the table would be the worst kind of cleanup. */
.portal-asbefore { border-left: 3px solid var(--rec-rule-2); padding-left: 12px; }
.portal-asbefore > summary {
    cursor: pointer; font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.9px; color: var(--rec-ink-2); padding: 3px 0;
}
.portal-asbefore > * + * { margin-top: 10px; }

/* ═══ Outside the classroom ═══ */

.portal-extra {
    border-top: 1px dashed var(--rec-rule); padding-top: 12px;
    display: flex; flex-direction: column; gap: 6px;
}
.portal-extras > .portal-extra:first-of-type { border-top: 0; padding-top: 0; }
.portal-check {
    flex-direction: row !important; align-items: center; gap: 10px;
    text-transform: none !important; letter-spacing: normal !important;
    font-size: 15px !important; font-weight: 400 !important;
    color: var(--rec-ink) !important; min-height: 44px;
}
.portal-check input[type=checkbox] { width: 20px; height: 20px; flex: 0 0 auto; }
.portal-extra-count { max-width: 320px; }
.portal-extra-count input { max-width: 90px; }
.portal-extra-detail input { font-size: 14px; }

.portal-credits { list-style: none; margin: 8px 0 0; padding: 0; }
.portal-credits li {
    padding: 7px 0; border-bottom: 1px solid var(--rec-rule);
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
}
.portal-credits li:last-child { border-bottom: 0; }
.portal-credit-label { font-size: 14.5px; color: var(--rec-ink); }
.portal-credit-count {
    font-size: 12px; font-weight: 700; color: var(--rec-gold-deep);
}
.portal-credit-detail { font-size: 13px; color: var(--rec-ink-2); }
.portal-confirmed { color: var(--rec-green-deep); }

/* ═══ Section jump ═══
   Plain anchors, not tabs. Tabs would hide four of the six sections, and this
   record is filled in over many sittings — seeing what is still empty is worth
   more than a tidy first screen. */

.portal-jump {
    display: flex; flex-wrap: wrap; gap: 6px;
    margin: 0 0 18px; padding-bottom: 14px;
    border-bottom: 1px solid var(--rec-rule);
}
.portal-jump a {
    font-size: 12px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.7px; text-decoration: none; color: var(--rec-green);
    border: 1px solid var(--rec-rule-2); border-radius: var(--rec-radius);
    padding: 8px 11px; background: var(--rec-ground);
}
.portal-jump a:hover { background: var(--rec-ground-2); }

/* ═══ What matters most ═══
   Six sliders that are about each other, not about a hundred. The share
   readout beside each one is the only honest way to draw a normalised weight:
   the raw number means nothing on its own. */

.portal-priorities-unset { color: var(--rec-gold-deep); font-weight: 600; }
.portal-preset-row { display: flex; flex-wrap: wrap; gap: 8px; }
.portal-preset {
    flex: 1 1 210px; text-align: left; cursor: pointer;
    background: var(--rec-ground); border: 1px solid var(--rec-rule-2);
    border-radius: var(--rec-radius); padding: 11px 12px;
    display: flex; flex-direction: column; gap: 4px; min-height: 44px;
    font-family: var(--rec-sans);
}
.portal-preset:hover { background: var(--rec-ground-2); }
.portal-preset.is-on {
    border-color: var(--rec-green); background: #eaf1ee;
    box-shadow: inset 3px 0 0 var(--rec-green);
}
.portal-preset-name { font-size: 14px; font-weight: 700; color: var(--rec-ink); }
.portal-preset-note { font-size: 12.5px; line-height: 1.45; color: var(--rec-ink-2); }

.portal-pillar { display: flex; flex-direction: column; gap: 5px; }
.portal-pillar-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.portal-pillar-head label {
    font-size: 14.5px; font-weight: 600; text-transform: none;
    letter-spacing: normal; color: var(--rec-ink);
}
.portal-pillar-share {
    font-size: 12px; font-weight: 700; color: var(--rec-gold-deep);
    white-space: nowrap;
}
.portal-priorities input[type=range] {
    width: 100%; padding: 0; border: 0; background: transparent;
    accent-color: var(--rec-green); height: 28px;
}
.portal-zero-note { color: var(--rec-ink-3); }

.portal-emphasis { border-top: 1px solid var(--rec-rule); padding-top: 14px; }
.portal-emphasis h4, .portal-docs-history h4, .portal-proposals h4 {
    font-family: var(--rec-serif); font-size: 15px; font-weight: 400;
    margin: 0 0 8px; color: var(--rec-ink);
}
.portal-emphasis-list { list-style: none; margin: 0; padding: 0; }
.portal-emphasis-list li {
    display: grid; grid-template-columns: minmax(120px, 250px) minmax(0, 1fr) 42px;
    align-items: center; gap: 10px; padding: 4px 0; font-size: 13.5px;
}
.portal-emphasis-list li.is-zero { color: var(--rec-ink-3); }
.portal-emphasis-label { color: var(--rec-ink-2); }
.portal-emphasis-bar {
    display: block; height: 9px; background: var(--rec-ground-2);
    border: 1px solid var(--rec-rule); border-radius: 2px; overflow: hidden;
}
.portal-emphasis-bar > span {
    display: block; height: 100%; background: var(--rec-gold);
}
.portal-emphasis-share { text-align: right; font-weight: 700; font-size: 12.5px; }

/* ═══ Generated lists ═══ */

.portal-stale {
    border-left: 3px solid var(--rec-gold); padding-left: 11px;
    color: var(--rec-gold-deep);
}
.portal-report-list { list-style: none; margin: 14px 0 4px; padding: 0; }
.portal-report-item {
    background: var(--rec-ground); border: 1px solid var(--rec-rule);
    border-left: 3px solid var(--rec-green); border-radius: var(--rec-radius);
    padding: 12px 14px; margin-bottom: 10px;
}
.portal-report-item.is-failed { border-left-color: var(--rec-error); }
.portal-report-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap;
}
.portal-report-when { font-size: 14.5px; font-weight: 700; color: var(--rec-ink); }
.portal-report-gone { font-size: 13px; color: var(--rec-error); }
.portal-report-weights { font-size: 13px; color: var(--rec-ink-2); margin-top: 5px; }
.portal-report-preset {
    display: inline-block; margin-right: 6px; padding: 2px 7px;
    border: 1px solid var(--rec-rule-2); border-radius: 999px;
    background: #fff; font-size: 11.5px; font-weight: 700;
    color: var(--rec-gold-deep);
}
.portal-report-detail { margin-top: 8px; }
.portal-report-detail > summary {
    cursor: pointer; font-size: 12px; color: var(--rec-green); padding: 4px 0;
}
.portal-report-build {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin-top: 12px;
}
.portal-report-wait { font-size: 13px; color: var(--rec-ink-2); }
.portal-reports-empty { text-align: left; }
.portal-reports-empty .portal-note { margin-top: 8px; }

/* htmx injects its own opacity rule for this class; these two make the
   waiting line take no room at all when it is not waiting. */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { display: inline; }

/* ═══ Transcript ═══
   The confirm screen is the point of the section: nothing read off a document
   reaches the record until a parent has looked at it. Flagged rows are marked
   in gold, and every field carries where its value came from. */

.portal-docs-lead { color: var(--rec-ink); }
.portal-docs-working { display: flex; gap: 12px; align-items: flex-start; margin: 12px 0; }
.portal-docs-working strong { font-size: 15px; }
.portal-spinner {
    flex: 0 0 auto; width: 18px; height: 18px; margin-top: 3px;
    border: 2px solid var(--rec-rule-2); border-top-color: var(--rec-green);
    border-radius: 50%; animation: portal-spin 0.9s linear infinite;
}
@keyframes portal-spin { to { transform: rotate(360deg); } }

.portal-conf {
    display: inline-block; margin-left: 8px; padding: 1px 7px;
    border-radius: 999px; border: 1px solid var(--rec-rule-2);
    font-size: 10.5px; font-weight: 700; letter-spacing: 0.4px;
    text-transform: uppercase; background: #fff; color: var(--rec-ink-2);
}
.portal-conf-high { border-color: #b6cdbe; background: #e7f0ea; color: #1f5044; }
.portal-conf-medium { border-color: #e3d3a9; background: #f6efdd; color: #6d4d13; }
.portal-conf-low { border-color: #e0bcb1; background: #f7e7e2; color: #7d3323; }
.portal-conf-not_found { border-color: var(--rec-rule-2); color: var(--rec-ink-3); }

.portal-review-field { padding-bottom: 4px; }
/* The label and its confidence chip sit on one line. .portal-form label is a
   column, which would otherwise stack the chip full-width above the box and
   make every field look like it had a banner over it. The input is a sibling
   of the label (tied on with for/id), so only the label itself flips. */
.portal-review-field > label {
    flex-direction: row; align-items: center; flex-wrap: wrap; gap: 4px 8px;
}
.portal-review-field > label .portal-conf { margin-left: 0; }
.portal-docs-unreadable { padding-left: 18px; }
.portal-course-scroll {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    max-width: 100%; min-width: 0;
}
.portal-course-table { border-collapse: collapse; width: 100%; min-width: 640px; }
.portal-course-table th {
    text-align: left; font-size: 10.5px; text-transform: uppercase;
    letter-spacing: 0.8px; color: var(--rec-ink-2); font-weight: 700;
    padding: 6px 6px; border-bottom: 1px solid var(--rec-rule-2);
    background: var(--rec-ground-2);
}
.portal-course-table td {
    padding: 6px; border-bottom: 1px solid var(--rec-rule); vertical-align: top;
}
.portal-course-table tr.is-flagged { background: #faf4e4; }
.portal-course-table input[type=checkbox] { width: 20px; height: 20px; }
.portal-course-table input, .portal-course-table select { font-size: 14px; padding: 7px 8px; }
.portal-cell-xs { max-width: 60px; }
.portal-cell-sm { max-width: 110px; }
.portal-course-flag {
    display: block; margin-top: 3px; font-size: 11.5px; color: var(--rec-gold-deep);
}
.portal-docs-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.portal-docs-actions .portal-btn { margin-top: 0; }
.portal-docs-upload input[type=file] {
    padding: 9px; background: #fff; font-size: 14px;
}
.portal-docs-history { border-top: 1px solid var(--rec-rule); margin-top: 16px; padding-top: 12px; }
.portal-docs-history ul { list-style: none; margin: 0 0 8px; padding: 0; }
.portal-docs-history li {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; padding: 7px 0; font-size: 13.5px;
    color: var(--rec-ink-2); border-bottom: 1px solid var(--rec-rule);
}
.portal-docs-history li:last-child { border-bottom: 0; }

/* ═══ The assistant ═══
   Its writes are proposals and they look like proposals: what the record says
   now, what it would say, and a button the parent has to press. */

.portal-chat-log { list-style: none; margin: 14px 0; padding: 0; }
.portal-chat-turn {
    padding: 10px 12px; margin-bottom: 8px; border-radius: var(--rec-radius);
    border: 1px solid var(--rec-rule); background: var(--rec-ground);
}
.portal-chat-user { background: #fff; border-left: 3px solid var(--rec-rule-2); }
.portal-chat-assistant { border-left: 3px solid var(--rec-green); }
.portal-chat-who {
    display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.8px; color: var(--rec-ink-3); margin-bottom: 4px;
}
.portal-chat-text { font-size: 14.5px; line-height: 1.6; white-space: pre-wrap; }
.portal-chat-empty { margin: 12px 0; }
.portal-chat-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.portal-chat-actions .portal-btn { margin-top: 0; }

.portal-proposals {
    border: 1px solid var(--rec-gold); border-top-width: 3px;
    border-radius: var(--rec-radius); padding: 13px 14px; margin: 14px 0;
    background: var(--rec-surface);
}
.portal-proposal { border-top: 1px solid var(--rec-rule); padding-top: 11px; margin-top: 11px; }
.portal-proposals > .portal-proposal:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
.portal-proposal-what { font-size: 15px; color: var(--rec-ink); }
.portal-proposal-new { color: var(--rec-green-deep); }
.portal-proposal-now, .portal-proposal-why {
    font-size: 13px; color: var(--rec-ink-2); margin-top: 4px; line-height: 1.5;
}
.portal-proposal-actions {
    display: flex; gap: 8px; margin-top: 9px; flex-wrap: wrap;
}
.portal-proposal-actions .portal-btn { margin-top: 0; }

/* ═══════════════════════════════════════════════════════════
   Phone. A parent opens this on a phone at the kitchen table:
   the two panes stack, the list rows become a name over a
   run-in meta line, and every tap target clears 44px.
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 860px) {
    .portal-main { padding: 18px 14px 44px; }

    .portal-layout { grid-template-columns: minmax(0, 1fr); }

    .portal-header { align-items: flex-start; gap: 14px; }
    .portal-title { font-size: 26px; }
    .portal-header > .portal-btn { width: 100%; text-align: center; margin-top: 0; }

    /* Same stacked row, one size up for a thumb. */
    .portal-row { padding: 14px 16px; }
    .portal-row-name { font-size: 18px; }

    .portal-form-pair { grid-template-columns: 1fr; }
    /* Money and verdict drop under the college name rather than squeezing
       a 17px serif name into what is left of a 390px row. */
    .portal-npc-college { flex: 0 0 100%; }
    .portal-npc-actions .portal-btn { flex: 1; text-align: center; }
    .portal-sug { max-height: 200px; }
    .portal-detail-inner { padding: 16px 16px 22px; }
    .portal-gate, .portal-auth { padding: 24px 20px 28px; margin-top: 20px; }
    .portal-gate .portal-title, .portal-auth .portal-title { font-size: 23px; }
    .portal-facts { grid-template-columns: minmax(0, 1fr); gap: 2px; }
    .portal-facts dd { margin-bottom: 9px; }

    #toast-container { left: 16px; right: 16px; }

    /* The jump links become a scrollable strip rather than four wrapped rows
       eating the top of a 390px screen. */
    .portal-jump { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 12px; }
    .portal-jump a { white-space: nowrap; }

    .portal-preset { flex: 1 1 100%; }
    .portal-emphasis-list li { grid-template-columns: minmax(0, 1fr) 68px 38px; }
    .portal-pillar-head { flex-wrap: wrap; gap: 2px 10px; }

    .portal-report-head { align-items: flex-start; }
    .portal-report-head .portal-btn { width: 100%; text-align: center; }
    .portal-report-build .portal-btn { width: 100%; text-align: center; }
    .portal-docs-actions .portal-btn,
    .portal-form-actions .portal-btn { width: 100%; text-align: center; }
    .portal-docs-history li .portal-btn { width: 100%; text-align: center; }
    .portal-proposal-actions .portal-btn { flex: 1; text-align: center; }
    .portal-chat-actions .portal-btn { flex: 1 1 100%; text-align: center; }

    /* The course table stays a table and scrolls sideways inside its own box.
       Stacking eight columns per course turns a 40-row transcript into 320
       rows, and the whole job here is checking it against a printed page. */
    .portal-course-table { min-width: 560px; }
}

@media (max-width: 560px) {
    .portal-head-inner { padding: 13px 14px; }
    .portal-head-right { width: 100%; justify-content: space-between; }
    .portal-who { max-width: none; flex: 1; }
    .portal-foot-inner { padding: 14px 14px 24px; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* Brand lockup: the squared attribution quote beside the wordmark. The mark is
   gold on the ink bar; the wordmark stays light, so they are separate colours
   on purpose rather than one tint applied to both. */
.portal-brand { display: flex; align-items: center; gap: 10px; }
.portal-brand-text { display: flex; flex-direction: column; }
.portal-mark { flex: 0 0 auto; color: var(--rec-gold); display: block; }
@media (max-width: 480px) { .portal-mark { width: 18px; height: 13px; } }
