/* ════════════════════════════════════════════════════════════════════════════
   auth.css — /login · /register · /forgot-password · /reset-password
   Session 8 · Phase 1 · Agent P2

   ── WHY A NEW NAMESPACE (`kp-`) ─────────────────────────────────────────────
   The old shell was `.k-auth`, and polish.css section 6 sets eight `.k-auth …`
   rules at (0,2,0) — the exact specificity anything written here would have.
   Rewriting in place would have meant either a load-order race or !important.
   `kp-` (korva parent-auth) shares no selector with polish.css, style.css or
   desktop.css, so there is nothing to contend with and nothing to un-pick when
   the rest of the site adopts the type scale.

   ⚑ DEAD CODE THIS LEAVES BEHIND, listed so the next agent does not have to
   find it: no template references `.k-auth*` any more (style.css section 10
   at ~3012-3042 and the KORVA v3 AUTH block at ~3396-3465, plus polish.css
   section 6 at ~330-397), and `templates/_auth_nav.html` is now referenced by
   nothing. The GENERIC classes those blocks qualify — .k-btn, .k-input,
   .k-label, .k-field — are still live on /subscribe and /dashboard, so the
   sheets cannot simply be deleted wholesale. Removing the `.k-auth`-prefixed
   rules is a safe follow-up; doing it from a login task would have put three
   shared stylesheets into a merge for no functional gain.

   ── WHY IT LOADS LAST (base.html `head_last`) ───────────────────────────────
   Nothing here needs to beat a `.k-auth` rule any more. What it does need to
   beat is polish.css's ELEMENT-level guarantees — the global
   `a:focus-visible / button:focus-visible` ring and the reduced-motion
   transform neutraliser — which it can only do from a later position without
   inflating selectors. Everything else in this file is namespaced and would be
   safe anywhere.

   ── THE GUTTER, MEASURED ────────────────────────────────────────────────────
   The reported defect was a wide band of white between the form and the
   editorial panel. Measured in Chromium at f24da1b, /login, and again after:

                        white LEFT of the rail    white RIGHT of the rail
       viewport         before      after         before      after
       1440             297.6px  →  100.0px        57.6px  →  100.0px
       1920             304.0px  →  208.0px       276.0px  →  208.0px
       2560             304.0px  →  248.5px       580.8px  →  248.5px

   The right-hand void grew without limit because the rail was LEFT-anchored in
   a percentage column, so every extra pixel of viewport landed in one place:
   `240 + 0.476 x (W - 240) - 764`. That formula gives 276 at 1920 and 581 at
   2560, and it passes through 415 at a window width of about 2210 — which is
   where the reported figure comes from. It is now symmetric at every width and
   bounded above 2100.

   Two independent causes, and the second one was the big one:

   1. THE SPLIT WAS NEVER 45/55. `grid-template-columns: 1fr 1.1fr` above
      1440 puts the form in the WIDER-than-half column at every width below
      that and 47.6% above it, so the rail floated in a column it could never
      fill. It is now literal percentages — 50/50 from 900, 45/55 from 1200 —
      so "true 45/55" is readable in the computed style rather than inferred
      from two fr units.

   2. ⚑ THE AUTH PAGES WERE RENDERING THE 240px APPLICATION RAIL.
      desktop.css gates the fixed logged-in sidebar on
      `body:has(> .knav:not(.knav--test))`, which excludes test mode and
      NOTHING ELSE — so `.knav--auth`, the two-item top bar on /login, matched
      it. Above 1024 the login page therefore shipped a 240px white fixed
      sidebar containing a wordmark and a "Start free" button, plus
      `padding-left: 240px` on <body> that shoved the entire split right. That
      is where most of the reported white came from.

      FIXED BY DELETING THE NAV, not by patching the selector. These four
      templates now override `{% block nav %}` with nothing at all, so there is
      no `body > .knav` for the `:has()` to match and the rail cannot apply.
      desktop.css is untouched. The wordmark moved into the cream panel, which
      is where the brief wanted it and which also removes the old 28.8px
      brand-vs-form-rail disagreement by construction: there is now exactly one
      left margin on the page and the logo, the heading and the fields all sit
      on it.

      ⚑ REPORTED SEPARATELY, NOT FIXED HERE: the same selector also matches
      `.knav--public`, so /, /pricing and /how-it-works ALSO render the
      marketing nav as a 240px fixed sidebar above 1024px. That is a live
      site-wide layout decision, not an auth bug, and changing it would
      redesign the marketing pages from inside a login task.
   ════════════════════════════════════════════════════════════════════════════ */


/* ── 1. Shell and split ─────────────────────────────────────────────────── */

.kp-auth {
  /* No nav on these pages, so the shell owns the full viewport. */
  min-height: 100vh;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  font-family: var(--font-geist);
  font-size: var(--font-body);
  line-height: var(--lh-body);
  color: #1A1128;
}

@media (min-width: 900px) {
  /* 50/50 through the tablet-landscape band: below 1200 a 45% column is too
     narrow to hold a 448px rail plus breathing room, and the fix for a gutter
     must not create a pinched form. */
  .kp-auth { grid-template-columns: 50% 50%; }
}

@media (min-width: 1200px) {
  /* The 45/55 the brief asked for. The panel takes the extra because it is the
     side carrying a real question, and a question needs the measure. */
  .kp-auth { grid-template-columns: 45% 55%; }
}

@media (min-width: 2100px) {
  /* ⚑ THE CAP. A percentage split keeps growing for ever: at 2560 a 45%
     column is 1152px holding a 448px rail, and the dead space is back. Above
     2100 the form column stops growing and the panel absorbs everything else,
     so the white beside the form is bounded at (945 − 448) / 2 = 248px and
     does not scale with the monitor. 945 is 45% of 2100 — the cap is the
     continuation of the ratio, not a new number. */
  .kp-auth { grid-template-columns: 945px 1fr; }
}


/* ── 2. The cream panel ─────────────────────────────────────────────────── */

.kp-auth__form {
  /* ⚑ Subtle warm gradient. Both ends are declared here because the contrast
     checker cannot read a gradient out of getComputedStyle — every text colour
     on this panel is measured against #F4EDE4, the DARKEST end, not against an
     average. 155deg puts the warm end bottom-right, under the button, so the
     lightest part of the panel is behind the headline. */
  background: linear-gradient(155deg, #FFFDFB 0%, #FAF4EC 48%, #F4EDE4 100%);
  padding-inline: clamp(24px, 5vw, 72px);
  padding-block: clamp(36px, 6vh, 72px);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

@media (min-width: 900px) {
  .kp-auth__form { justify-content: center; }
}

.kp-auth__rail {
  width: 100%;
  max-width: 448px;
  /* Centred in its own column, so the white to the left of the form and the
     white to its right are equal by construction rather than by a magic
     number. The old rail was margin-inline: 0 auto — left-anchored — which is
     what turned the leftover column width into a one-sided hole. */
  margin-inline: auto;
}

@media (min-width: 900px) {
  /* ⚑ OPTICAL, NOT MATHEMATICAL, VERTICAL CENTRING — AND THE DIRECTION WAS
     MEASURED, NOT ASSUMED.

     The intuition is that a page with a 42px headline at the top is top-heavy
     and wants pushing down. The measurement says the opposite. The ink-centroid
     probe in scratch_agent_p2/measure.py weights every text node by
     width x font-size x contrast and every filled surface by area x darkness,
     and on /login at 1440x900 the centre of mass of a geometrically centred
     rail sits 51.5px BELOW the viewport centre line. The headline is large but
     it is thin, single-colour and only two lines; the lower half carries the
     white fields, the SOLID CERULEAN BUTTON (the darkest object on the panel by
     a wide margin) and the filled note block. The block is bottom-heavy.

     So the bias lifts. margin-bottom is what gets centred along with the box,
     so the rail rises by half the margin: 103px of margin, 51.5px of lift, and
     the measured centroid lands on the centre line — offset +51.5px becomes
     -1.2px. Expressed in vh so it tracks the viewport rather than assuming
     900px, and clamped so a short window gets no bias at all rather than a
     rail jammed against the top. */
  .kp-auth__rail { margin-bottom: clamp(0px, 11.5vh, 104px); }
}


/* ── 3. Wordmark, inside the panel, on the form's own left margin ───────── */

.kp-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: #1A1128;
  font-family: var(--font-geist);
  font-size: var(--font-lg);
  font-weight: 600;
  letter-spacing: var(--ls-head);
  line-height: var(--lh-head);
  margin-bottom: clamp(28px, 5vh, 44px);
  border-radius: 10px;
}
.kp-logo .brand-mark {
  /* Geometry and colour both come from the shared brand rules (style.css:2771
     for the box, theme.css:268 for the cerulean); nothing is restated here, so
     the auth wordmark cannot drift away from the nav one. */
  flex: none;
}
.kp-logo:hover { color: #005F82; }


/* ── 4. Headline block ──────────────────────────────────────────────────── */

.kp-eyebrow {
  font-family: var(--font-geist);
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #005F82;                                   /* 6.11 on #F4EDE4       */
  margin: 0 0 12px;
  line-height: 1.3;
}

.kp-h1 {
  font-family: var(--font-geist);
  /* ⚑ THE SERIF HEADLINE IS GONE. It was Fraunces at a computed 56px, which
     is --font-xxl plus a third, in a display serif that shares nothing with
     the form beneath it. The brief asked for 40-44px in Geist; this clamps
     between --font-xl (32) at 375px and 42px from about 1230px up, so the
     token is the floor of the ramp rather than a value nobody uses. */
  font-size: clamp(var(--font-xl), 2.2rem + 0.8vw, 42px);
  font-weight: 600;
  line-height: var(--lh-head);
  letter-spacing: var(--ls-head);
  color: #1A1128;                                   /* 15.66 on #F4EDE4      */
  margin: 0 0 10px;
}

.kp-sub {
  font-family: var(--font-geist);
  font-size: var(--font-body);
  line-height: var(--lh-body);
  /* ⚑ MEASURED. This is the "grey subtitle on cream" the brief called out.
     #6B6580 on the gradient's darkest end is 4.76:1 — over 4.5 with room to
     spare, and 5.45 at the light end. The supporting-text token was used as
     given; no lightening for taste. */
  color: #6B6580;
  margin: 0 0 30px;
  max-width: 38ch;
}


/* ── 5. Fields ──────────────────────────────────────────────────────────── */

.kp-field { margin-bottom: 18px; }

.kp-label {
  display: block;
  font-family: var(--font-geist);
  font-size: var(--font-xs);
  font-weight: 500;
  /* ⚑ MEASURED SUBSTITUTION, DELIBERATE. The brief asked for labels at about
     60% opacity. Ink #1A1128 at 60% composites to #716973 on the gradient's
     dark end, which measures 4.55:1 — it PASSES, by 0.05. This repo has
     shipped three contrast regressions that each began as a value passing by
     a hair (--ink-mute at 3.34, the focus ring at 3.17, the footer at 2.34),
     so the shipped value is 66% — #645C68, 5.52:1 — which reads as the same
     de-emphasis and leaves the gradient room to be retuned without silently
     re-failing. It is a solid colour rather than an opacity so that the
     measurement is of the thing that actually paints. */
  color: #645C68;
  letter-spacing: .01em;
  margin-bottom: 7px;
}

.kp-input {
  display: block;
  width: 100%;
  font-family: var(--font-geist);
  font-size: var(--font-body);
  line-height: 1.4;
  color: #1A1128;                                   /* 18.19 on white        */
  /* ⚑ WHITE FILL, NO BORDER — not both. The old field was a white fill AND a
     1px line AND a shadow, three ways of saying the same edge. On a warm
     cream gradient a plain white plane separates on its own. The only stroke
     this control ever draws is the focus ring. */
  background: #FFFFFF;
  border: 0;
  border-radius: 12px;
  padding: 15px 16px;
  /* 15 + 15 + 17×1.4 ≈ 53.8px — comfortably over the 44px minimum target. */
  min-height: 52px;
  transition: box-shadow 200ms ease, background 200ms ease;
  -webkit-appearance: none;
  appearance: none;
}
.kp-input::placeholder { color: #767089; }          /* 4.72 on white          */
.kp-input:hover { background: #FFFFFF; }

/* Password field + show/hide toggle share a positioning context. */
.kp-input-wrap { position: relative; }
.kp-input-wrap .kp-input { padding-right: 84px; }

.kp-reveal {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  /* 44×44 minimum tap target. The label is two short words so the visible
     text is small; the hit area is not. */
  min-width: 68px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
  font-family: var(--font-geist);
  font-size: var(--font-xs);
  font-weight: 600;
  color: #005F82;                                   /* 7.10 on white          */
  transition: background 200ms ease, color 200ms ease;
}
.kp-reveal:hover { background: #EAF2F6; color: #004A66; }

.kp-field__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 7px;
}
.kp-field__row .kp-label { margin-bottom: 0; }


/* ── 6. Buttons and links ───────────────────────────────────────────────── */

.kp-btn {
  display: block;
  width: 100%;
  font-family: var(--font-geist);
  font-size: var(--font-body);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  /* Deep Cerulean carries white text at 7.10:1. The 3.17:1 brand blue is not
     used anywhere on this page, as a surface or otherwise — a CTA is exactly
     the control that would tempt someone to put white on it. */
  background: #005F82;
  color: #FFFFFF;
  /* Unified with the fields at 12px. The old CTA was a 999px pill next to
     8px fields, which is two radii on one form. */
  border: 0;
  border-radius: 12px;
  padding: 16px 24px;
  min-height: 52px;
  cursor: pointer;
  margin-top: 8px;
  /* The 200ms ease the brief asked for, on the two properties that move. */
  transition: background 200ms ease, box-shadow 200ms ease;
}
.kp-btn:hover { background: #004A66; box-shadow: 0 4px 14px rgba(0, 95, 130, .24); }
.kp-btn:active { background: #003F58; box-shadow: none; }

.kp-btn--ghost {
  background: transparent;
  color: #005F82;
  box-shadow: inset 0 0 0 1px rgba(0, 95, 130, .35);
}
.kp-btn--ghost:hover { background: #EAF2F6; box-shadow: inset 0 0 0 1px rgba(0, 95, 130, .55); }

.kp-link {
  color: #005F82;                                   /* 6.11 on #F4EDE4        */
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  border-radius: 4px;
  transition: color 200ms ease;
}
.kp-link:hover { color: #004A66; }

.kp-link--quiet {
  font-size: var(--font-xs);
  font-weight: 600;
  text-decoration: none;
  /* ⚑ REAL BOX, NOT A PSEUDO-ELEMENT. "Forgot password?" is a standalone
     control, not a link inside a sentence, so it owes a 44px target — and the
     first version bought that with an absolutely positioned ::after. Measured,
     that failed: the anchor's own border box stayed 112x29, which is what a
     pointer-target audit and every assistive technology reads, and the focus
     ring drew around 29px too. Padding grows the real box to 45px and an equal
     negative margin gives the space straight back to the layout, so the label
     row is unmoved and the target is genuinely there. */
  display: inline-block;
  padding: 12px 8px;
  margin: -12px -8px;
}
.kp-link--quiet:hover { text-decoration: underline; text-underline-offset: 3px; }

.kp-alt {
  font-size: var(--font-sm);
  line-height: var(--lh-body);
  color: #6B6580;                                   /* 4.76 on #F4EDE4        */
  margin: 26px 0 0;
}

/* The persona note. Korva has no child login and this is the surface where a
   parent would assume otherwise, so the distinction is stated in words rather
   than implied by a link that does not exist. */
.kp-note {
  margin: 22px 0 0;
  padding: 14px 16px;
  border-radius: 12px;
  background: rgba(0, 95, 130, .055);
  font-size: var(--font-sm);
  line-height: var(--lh-body);
  color: #4A4458;                                   /* 7.55 on #F4EDE4        */
}
.kp-note strong { font-weight: 600; color: #1A1128; }

/* Guardian consent (register only). B7 requires this to be an explicit,
   unticked checkbox; the whole block is a label so the hit area is the text as
   well as the box, which on a phone is the difference between a required field
   and a dead end. */
.kp-consent {
  margin: 6px 0 4px;
  padding: 15px 17px;
  border-radius: 12px;
  background: rgba(0, 95, 130, .055);
}
.kp-consent__label {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  cursor: pointer;
  font-size: var(--font-sm);
  line-height: var(--lh-body);
  color: #4A4458;                                   /* 7.55 on #F4EDE4        */
  min-height: 44px;
}
.kp-consent__label strong { font-weight: 600; color: #1A1128; }
.kp-consent input[type="checkbox"] {
  flex: none;
  margin-top: 2px;
  /* 24, not the 17 it was and not the 20 the first pass here used: 24x24 is
     the WCAG 2.5.8 minimum and the box is what takes focus, so the label being
     clickable does not cover it. Measured at 20 and raised. */
  width: 24px; height: 24px;
  accent-color: #005F82;
  cursor: pointer;
}

.kp-error {
  margin: 0 0 20px;
  padding: 13px 16px;
  border-radius: 12px;
  background: #FCEDEA;
  color: #8C2F1C;                                   /* 7.11 on #FCEDEA        */
  font-size: var(--font-sm);
  line-height: var(--lh-body);
  box-shadow: inset 0 0 0 1px #F0CFC7;
}
.kp-ok {
  margin: 0 0 20px;
  padding: 13px 16px;
  border-radius: 12px;
  background: #E9F3F7;
  color: #00495F;                                   /* 8.98 on #E9F3F7        */
  font-size: var(--font-sm);
  line-height: var(--lh-body);
  box-shadow: inset 0 0 0 1px #C3DDE7;
}


/* ── 7. Focus — visible, and the same ring everywhere ───────────────────── */

/* ⚑ WAS DEEP PURPLE #7e3df4, AND ITS REASON HAS EXPIRED (Q4, Session 9). The note
   here read "deep purple, not the brand blue: #7e3df4 is 4.68 on the cream panel
   and 5.44 on a white field; #4f91ee is 3.17 and would be a downgrade." That was
   correct against the OLD accent. The accent is now one teal scale, and its deepest
   step --teal-900 (#0A2B39) measures 14.81:1 on white and 13.86:1 on the warm
   panel — roughly three times the purple's headroom — so keeping a purple here
   would leave the last non-teal accent in the product on the two screens every
   parent sees first, and buy nothing for it. Matched to theme.css's global ring so
   the auth pages and the app ring identically. `outline` rather than a shadow so
   Windows High Contrast keeps it. */
.kp-auth a:focus-visible,
.kp-auth button:focus-visible,
.kp-auth input:focus-visible,
.kp-auth .kp-btn:focus-visible {
  outline: 3px solid var(--teal-900, #0A2B39);
  outline-offset: 2px;
}
.kp-input:focus-visible,
.kp-input:focus {
  outline: 3px solid var(--teal-900, #0A2B39);
  outline-offset: 2px;
  box-shadow: none;
}
/* On the cerulean panel the purple ring would drop to 1.6:1, so the panel's
   own links ring in white instead — 7.10:1 there. */
.kp-panel a:focus-visible { outline: 3px solid #FFFFFF; outline-offset: 2px; }


/* ── 8. The editorial panel ─────────────────────────────────────────────── */

/* ⚑ THE PANEL NOW RENDERS AT EVERY WIDTH — Session 11, V1 item 1.
   It was `display: none` below 900px from Session 8 until now, and that was a
   DESIGN decision rather than an oversight: at desktop the panel carries the
   wordmark, so hiding it narrow meant the rail's own wordmark was the single
   brand and the single link back to the marketing site on a phone. Making the
   panel visible narrow does NOT change that — the one-logo rule below still
   hides the PANEL's copy under 900px, so the rail copy is still the only
   wordmark there and the link back survives untouched. What changes is that a
   phone now gets the real bank question and Fo's first rung under the form
   instead of a bare field pair.

   ⚑ AND IT IS ALSO WHY THE REPORTED "NO PANEL AT 1024px" WAS NOT A CSS BUG.
   Measured against production at 375/768/1024/1440/1920 (scratch_agent_v1/
   shoot_auth.py): the panel painted #005F82 at full column width at 1024 and
   above, and production's auth.css was byte-identical to this file. The only
   widths at which it was ever invisible were below 900 CSS px — which a PC
   reaches through browser zoom (125% in a 1024px window is 819 CSS px),
   Windows display scaling, or a window that is not maximised. This block
   removes that whole class of report rather than the one instance.

   The DESKTOP form is preserved exactly: the media query below restates the
   padding shorthand and the 100vh floor it always had. Narrow gets its own
   padding, because the panel there is a stacked band under the form and not a
   full-height column, and 100vh narrow would cost a phone a second screen of
   scroll for one card. */
.kp-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: #005F82;
  color: #CFE4EC;                                   /* 5.39 on cerulean       */
  /* Matches .kp-auth__form's own inline padding, so the form copy above and
     the panel copy below sit on ONE left margin when they are stacked. */
  padding-inline: clamp(24px, 5vw, 72px);
  padding-block: clamp(32px, 7vw, 64px);
}

@media (min-width: 900px) {
  .kp-panel {
    padding: clamp(40px, 5vw, 88px);
    min-height: 100vh;
  }
}

.kp-panel__inner { width: 100%; max-width: 520px; }

.kp-panel .kp-eyebrow { color: #CFE4EC; }           /* 5.39                   */

.kp-panel__quote {
  font-family: var(--font-geist);
  font-size: clamp(var(--font-lg), 1.1rem + 0.9vw, 30px);
  font-weight: 600;
  line-height: var(--lh-head);
  letter-spacing: var(--ls-head);
  color: #FFFFFF;                                   /* 7.10                   */
  margin: 0 0 30px;
}

/* ── The real fragment. Content provenance is in the template comment and in
      app.py's _auth_panel_sample(); this is only its surface. The card sits on
      a darkened wash of the panel so it reads as lifted without introducing a
      second hue. */
.kp-frag {
  background: #00506E;
  border-radius: 14px;
  padding: 22px 24px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}
.kp-frag__tag {
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #BFDCE7;                                   /* measured in the sweep  */
  margin: 0 0 12px;
}
.kp-frag__stem {
  font-size: var(--font-body);
  line-height: var(--lh-body);
  color: #FFFFFF;
  margin: 0 0 18px;
}
.kp-frag__row {
  display: flex;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid rgba(255, 255, 255, .18);
  font-size: var(--font-sm);
  line-height: var(--lh-body);
}
.kp-frag__k {
  flex: none;
  width: 92px;
  font-weight: 600;
  color: #BFDCE7;
}
.kp-frag__v { color: #FFFFFF; margin: 0; }
.kp-frag__v em { font-style: italic; }
.kp-frag__caption {
  margin: 18px 0 0;
  font-size: var(--font-xs);
  line-height: var(--lh-body);
  color: #CFE4EC;                                   /* 5.39                   */
}

/* The bullets that used to be on /login. They belong on the page where
   somebody is deciding whether to sign up, not on the page where they have
   already decided and only want in. */
.kp-points { list-style: none; padding: 0; margin: 0; }
.kp-points li {
  position: relative;
  padding: 11px 0 11px 26px;
  font-size: var(--font-body);
  line-height: var(--lh-body);
  color: #CFE4EC;                                   /* 5.39                   */
}
.kp-points li::before {
  content: '';
  position: absolute;
  left: 0; top: 21px;
  width: 12px; height: 2px;
  background: #CFE4EC;
  border-radius: 2px;
}

.kp-rule {
  border: 0;
  height: 1px;
  background: rgba(255, 255, 255, .22);
  margin: 30px 0;
}

/* ── Fo's first hint rung, under the question fragment (Q5) ───────────────
   The panel carried one card and then ~170px of flat cerulean to the fold.
   This adds the other half of what the child actually gets — the question AND
   the coaching — without a second hue: the same #00506E wash as .kp-frag, one
   step in from it, so the two read as one column rather than two widgets.
   Provenance is in the template: the quoted line is FO_HINT_FALLBACK[0]
   rendered from app.py, never typed.
   Measured on #00506E: white 8.85, #BFDCE7 6.16, #CFE4EC 7.36.            */
.kp-hint {
  background: #00506E;
  border-radius: 14px;
  padding: 18px 22px 19px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}
.kp-hint__who {
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #BFDCE7;                                   /* 6.16 on #00506E        */
  margin: 0 0 9px;
}
.kp-hint__say {
  font-size: var(--font-body);
  line-height: var(--lh-body);
  color: #FFFFFF;                                   /* 8.85                   */
  margin: 0 0 10px;
}
.kp-hint__note {
  font-size: var(--font-xs);
  line-height: var(--lh-body);
  color: #CFE4EC;                                   /* 7.36                   */
  margin: 0;
}


/* ── 9. Small screens ───────────────────────────────────────────────────── */

@media (max-width: 899px) {
  .kp-auth { min-height: 0; }
  .kp-auth__form { padding-block: clamp(28px, 7vw, 56px) clamp(48px, 12vw, 80px); }
  .kp-auth__rail { max-width: 460px; }

  /* ⚑ THE PANEL GOES ABOVE THE FORM HERE, AND THIS IS THE BUG THAT SURVIVED
     THREE SESSIONS. Every previous pass read the stylesheet, found
     `background: #005F82` with no media query gating it, and concluded the
     panel was fine — which it was, as CSS. Measured in a browser it was not:
     stacked BELOW the form it began at y=783 (768px wide) and y=741 (375px),
     leaving 116px and 39px of cerulean on a first screen of a page 1786px and
     2005px tall. Loading /login showed an all-white screen and the brand only
     appeared if you scrolled. A PC at 125% zoom or Windows display scaling
     lands in exactly this range, which is why it was reported as "still white
     on a PC at 1024px+" while the desktop CSS was genuinely correct.

     `order: -1` puts the cerulean first, so the brand is on the first screen at
     every width. It stays a BAND rather than a column — a full-height panel
     narrow would cost a phone a whole screen of scrolling before the form. */
  .kp-panel {
    order: -1;
    padding-block: clamp(22px, 5vw, 34px);
    min-height: 0;
  }
  /* ⚑ A BAND IS THE LOGO AND ONE LINE — NOT THE WHOLE PANEL STACKED. Moving the
     panel above the form was not enough on its own: it still carried the quote,
     the points, the fragments and the hint, so it measured 788px tall at 768px
     wide. The form's autofocus then scrolled it straight back off the top
     (measured at y=-669), and the first screen was white again for the same
     reason in the opposite direction. Cutting the long copy leaves a real
     brand band that fits above the form on one screen. The copy is not lost —
     it is the desktop panel's job, and it is all still there at 900px and up. */
  /* What the band keeps is the promise; what it drops is the evidence for it.
     `.kp-panel__quote` is one sentence and is the reason a parent is here at
     all. The live sample fragment underneath is provenance — good on a desktop
     column, 600px of scrolling on a phone. */
  .kp-panel .kp-frag,
  .kp-panel .kp-frag__caption,
  .kp-panel .kp-points,
  .kp-panel .kp-hint { display: none; }

  .kp-panel__inner { max-width: 560px; }
  .kp-panel .kp-eyebrow { margin: 0 0 6px; }
  .kp-panel__quote { font-size: 1.02rem; line-height: 1.45; margin: 0; }
}

/* Respect the system setting. polish.css collapses durations globally but
   leaves declared transitions in place; naming them here means the 200ms
   hover genuinely stops rather than becoming a 1ms one. */
@media (prefers-reduced-motion: reduce) {
  .kp-btn, .kp-input, .kp-reveal, .kp-link { transition: none; }
}


/* ════════════════════════════════════════════════════════════════════════════
   10. THE DEEP CERULEAN PANEL — Session 10b, Agent U3

   ── WHAT CHANGED, AND WHAT DID NOT ──────────────────────────────────────────
   The panel ground was ALREADY #005F82 before this pass; it is restated below
   as a token-free literal for the same reason the gradient above is — the
   contrast checker cannot read a value it has to inherit, and every ratio in
   this block was measured against this exact hex.

   ── THE MARK: WHITE TILE, DEEP CERULEAN "K" ─────────────────────────────────
   ⚑ MEASURED, AND THE MEASUREMENT IS WHY IT IS A FILLED WHITE TILE RATHER THAN
   A HOLLOW OUTLINE. A rounded square stroked in white with a TRANSPARENT
   interior would show the panel through it, and a Deep Cerulean "K" drawn on
   Deep Cerulean is #005F82 on #005F82 = 1.00:1 — an invisible letter. The
   knockout is the only arrangement in which the K is genuinely the panel's own
   colour AND legible:

       #FFFFFF tile on #005F82 panel .............. 7.10:1
       #005F82 "K"  on #FFFFFF tile  .............. 7.10:1
       (the hollow-outline reading, for the record)  1.00:1  — not shipped

   The tile keeps theme.css's optical-centring padding (the "K" here is the TEXT
   GLYPH mark, `<span class="brand-mark">K</span>`, not the drawn path in
   static/favicon.svg — those are two different pieces of artwork and only the
   glyph is touched here). Its drop shadow is dropped: a shadow under a white
   tile on a saturated ground reads as dirt, and the 7.10:1 edge needs no help.

   ── ONE LOGO, EVER ──────────────────────────────────────────────────────────
   ⚑ The rail copy is HIDDEN at >= 900px and the panel copy is hidden below it,
   so exactly one is visible at every width and the two can never be on screen
   together. Below 900px the rail copy is the ONLY brand and the only link back
   to the marketing site — which is why the include was added to the panel
   rather than moved into it.

   ⚑ CORRECTED (Session 11, V1): the sentence here used to read "below 900px
   `.kp-panel` is display:none". That is no longer true — see section 8, the
   panel now renders at every width. Nothing about the one-logo rule changed:
   it never depended on the panel being absent, only on the two `display: none`
   rules directly below this comment, and both are untouched.

   The Session 8 "one left margin" note above still holds: the eyebrow, the
   headline and the fields are still the rail's own first children on that one
   margin. The rail simply has one fewer element sitting on it at desktop.

   ── PANEL TEXT IS WHITE ─────────────────────────────────────────────────────
   The supporting copy was #CFE4EC (5.39 on the panel, 6.73 on the card wash)
   and #BFDCE7 (6.16 on the card wash). Both PASSED; they are raised to white
   because the brief asked for white text on this ground and white measures
   better, not because either was failing:

       #FFFFFF on #005F82 (panel) ................. 7.10:1
       #FFFFFF on #00506E (card wash) ............. 8.85:1

   ⚑ THE ONE EXCEPTION IS DELIBERATE AND IT IS THE EYEBROW/KEY LABELS INSIDE
   THE CARD. `.kp-frag__k` ("Answer", "Why not A") is the KEY half of a
   key/value pair and `.kp-frag__v` is the value; if both are pure white the
   only thing separating them is a 92px column, and the card loses the one
   signal that says which half is the label. They stay one measured step down
   at #DCEBF2 — 7.25:1 on the card wash, i.e. HIGHER than the value text on the
   panel — so the de-emphasis is typographic, not a contrast concession.
   ════════════════════════════════════════════════════════════════════════════ */

@media (min-width: 900px) {
  /* One logo, and it is the panel's. See the note above. */
  .kp-auth__rail .kp-logo { display: none; }
}
@media (max-width: 899px) {
  .kp-panel__inner > .kp-logo { display: none; }
}

.kp-panel__inner > .kp-logo {
  color: #FFFFFF;                                   /* 7.10 on #005F82        */
  margin-bottom: clamp(26px, 4vh, 40px);
}
.kp-panel__inner > .kp-logo:hover { color: #DCEBF2; }
.kp-panel__inner > .kp-logo .brand-mark {
  background: #FFFFFF;
  background-image: none;
  color: #005F82;                                   /* 7.10 on #FFFFFF        */
  box-shadow: none;
  border: 0;
}

/* Everything on the panel that was a tinted near-white is now white. */
.kp-panel .kp-eyebrow,
.kp-panel .kp-frag__caption,
.kp-panel .kp-points li,
.kp-panel .kp-hint__note {
  color: #FFFFFF;                                   /* 7.10 / 8.85            */
}
.kp-panel .kp-points li::before { background: #FFFFFF; }

/* The key half of the card's key/value rows, and the card's own tag line.
   One step down from white so a label still reads as a label. */
.kp-frag__tag,
.kp-frag__k,
.kp-hint__who {
  color: #DCEBF2;                                   /* 7.25 on #00506E        */
}

/* ── CTAs: white text, one recipe ────────────────────────────────────────────
   ⚑ `.kp-btn` was already #FFFFFF on #005F82 and is unchanged. What was NOT
   consistent is the GHOST variant, which put cerulean ink on the cream panel
   and would be 1.00:1 if it were ever placed on the panel. It is given an
   explicit panel form here so the two grounds cannot diverge silently. */
.kp-panel .kp-btn,
.kp-panel .kp-btn--ghost {
  background: transparent;
  color: #FFFFFF;                                   /* 7.10 on #005F82        */
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .70);
}
.kp-panel .kp-btn:hover,
.kp-panel .kp-btn--ghost:hover {
  background: rgba(255, 255, 255, .12);
  box-shadow: inset 0 0 0 1.5px #FFFFFF;
}
.kp-panel .kp-link { color: #FFFFFF; }


/* ── Spacing floor: text never sits 14px from the edge of its own card.
      Session 10b, U3, workstream 6. Both blocks measured at 14px vertical. */
.kp-note { padding: 16px; }
.kp-consent { padding: 16px 17px; }
