/* The parent portal.
 *
 * A working tool behind a sign in, not a marketing page: the site's crest,
 * palette and type, laid out the way the school's own design draws it. Two
 * shapes live here.
 *
 *   .pauth   the centred card a parent meets before they are signed in
 *   .pshell  the sidebar and canvas they meet afterwards
 *
 * Headings keep --font-display, the serif, so a parent who clicks in from the
 * website is plainly still at the same school. Every control keeps --font-ui,
 * because a serif on a button reads as decoration rather than as something to
 * press. That split is the site's, and the portal does not get its own.
 *
 * This file is loaded ONLY by portal screens. The front-end budget measures
 * the largest stylesheet rather than the sum, precisely so that splitting a
 * screen's rules out of site.css is rewarded and not punished.
 */

/* -------------------------------------------------------------------------
 * 1. Shared furniture
 * ---------------------------------------------------------------------- */

.portal-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(20px, 4vw, 32px);
  /* Declared, never inherited from a band. Text on a light card stating its
     own colour is a rule this site learned three times: a parent band that
     whitens its children has shipped white-on-white here before. */
  color: var(--ink);
}

.portal-card h1,
.portal-card h2,
.portal-card h3 {
  color: var(--brand-deep);
  margin-top: 0;
}

/* A form screen's headline is a label for the work, not a masthead. At the
 * site's display size "Let's create your parent account" ran to four lines and
 * 134px on a phone, pushing the first field most of the way down the screen.
 * The serif stays, because that is what says this is still the same school;
 * only the size comes down. */
.portal-card h1 {
  font-size: var(--step-2);
  line-height: 1.15;
  margin-bottom: 10px;
}

.portal-eyebrow {
  font-family: var(--font-ui);
  /* The same size as .eyebrow on the public site. It had drifted to 0.78rem,
     which is smaller for no reason anybody chose and is the way a type scale
     ends up with paragraphs at eight sizes. */
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--brand-primary);
  margin: 0 0 8px;
}

.portal-note {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: color-mix(in srgb, var(--brand-tint) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--brand-tint) 25%, #fff);
  border-radius: var(--radius);
  padding: 14px 16px;
  color: var(--ink);
  font-size: 0.95rem;
}

.portal-note--warn {
  background: color-mix(in srgb, var(--brand-gold) 16%, #fff);
  border-color: color-mix(in srgb, var(--brand-gold) 50%, #fff);
}

.portal-note__icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--brand-primary);
}

.portal-error,
.portal-notice {
  border-radius: var(--radius);
  padding: 12px 16px;
  margin: 0 0 18px;
  font-size: 0.95rem;
}

.portal-error {
  background: #FDECEC;
  border: 1px solid #E9B7B7;
  color: #7A1F1F;
}

.portal-notice {
  background: color-mix(in srgb, var(--success) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--success) 35%, #fff);
  color: #17532B;
}

/* -------------------------------------------------------------------------
 * 2. Fields
 * ---------------------------------------------------------------------- */

.pfield {
  margin: 0 0 18px;
}

.pfield > label {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--ink);
  margin-bottom: 6px;
}

.pfield input,
.pfield select {
  width: 100%;
  font-family: var(--font-ui);
  /* 16px on a phone, always. Anything smaller makes iOS zoom the page on
     focus and the parent then has to pinch back out to reach the button. */
  font-size: 16px;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
}

.pfield input:focus-visible,
.pfield select:focus-visible {
  outline: 3px solid var(--brand-tint);
  outline-offset: 1px;
}

.pfield__help {
  display: block;
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--ink-muted);
}

/* The number field: a fixed dialling code beside the input.
 *
 * EVERY child is placed explicitly. The first version placed only the label
 * and let the rest fall where auto-placement put them, which dropped the help
 * sentence into column one — and because that column is `auto`, the sentence's
 * max-content then sized it. The dialling code box came out 271px wide and the
 * input a 30px sliver on a phone. Auto-placement in a two-column grid is not a
 * convenience; it is a rule waiting to be got wrong by the next person who
 * adds a child here.
 */
.pfield--phone {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 8px;
  align-items: center;
}

.pfield--phone > label,
.pfield--phone > .pfield__help {
  grid-column: 1 / -1;
}

.pfield--phone > .pfield__prefix {
  grid-column: 1;
}

.pfield--phone > input {
  grid-column: 2;
}

.pfield__prefix {
  font-family: var(--font-ui);
  font-size: 16px;
  padding: 12px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink-muted);
  white-space: nowrap;
}

/* The one-time code. One input, not six boxes.
 *
 * Six boxes look like the design and break the thing that actually matters on
 * a phone: autocomplete="one-time-code" offers the code straight from the
 * notification, and it can only fill a single field. Six boxes would also need
 * script to move focus between them, on a site whose own tests refuse script
 * on anything a parent has to read. So it is one field, set wide and spaced
 * so it still reads as a code rather than as a name. */
.pcode {
  width: 100%;
  font-family: var(--font-ui);
  font-size: clamp(1.6rem, 6vw, 2.1rem);
  font-weight: 700;
  letter-spacing: 0.4em;
  text-align: center;
  text-indent: 0.4em; /* letter-spacing pads the right; this re-centres it */
  color: var(--brand-deep);
  background: #fff;
  border: 2px solid var(--line);
  border-radius: 14px;
  padding: 14px 10px;
}

.pcode:focus-visible {
  outline: 3px solid var(--brand-tint);
  outline-offset: 2px;
  border-color: var(--brand-primary);
}

/* -------------------------------------------------------------------------
 * 3. Buttons
 * ---------------------------------------------------------------------- */

.pbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  padding: 13px 22px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  /* Dark on light is the DEFAULT and white is the exception, deliberately.
     The opposite arrangement needed an author to remember a modifier on every
     light ground, and the one they forgot rendered white on white. */
  background: var(--brand-primary);
  color: var(--on-brand);
}

.pbtn--wide {
  width: 100%;
}

.pbtn--gold {
  background: var(--brand-gold);
  color: var(--brand-deep);
}

.pbtn--ghost {
  background: #fff;
  color: var(--brand-primary);
  border-color: color-mix(in srgb, var(--brand-primary) 35%, #fff);
}

.pbtn--link {
  background: none;
  border: 0;
  /* It looks like a link and it is a real control: "Send another code" sends a
     WhatsApp message. At 142x19 on a phone it was a finger's worth of guess
     next to the sentence it sits in. The vertical padding gives it a target
     without turning it into a second gold button competing with "Verify my
     number", which is the one a parent should press. */
  padding: 12px 4px;
  margin: -12px 0;
  color: var(--brand-primary);
  text-decoration: underline;
  font-weight: 600;
}

.pbtn:focus-visible {
  outline: 3px solid var(--brand-tint);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
 * 4. The pre-sign-in screens
 * ---------------------------------------------------------------------- */

.pauth {
  max-width: 34rem;
  margin: clamp(24px, 6vw, 56px) auto;
  padding: 0 var(--gutter);
}

.pauth__lede {
  color: var(--ink-muted);
  margin: 0 0 24px;
}

.pauth__alt {
  margin: 18px 0 0;
  text-align: center;
  font-family: var(--font-ui);
  font-size: 0.95rem;
  color: var(--ink-muted);
}

/* The five-step rail across the top of the school's design. It is a
   description of where the parent is, so it is an ordered list and the
   current step is marked with aria-current, not with colour alone. */
.psteps {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  list-style: none;
  margin: 0 0 28px;
  padding: 0;
  font-family: var(--font-ui);
  font-size: 0.82rem;
  color: var(--ink-muted);
}

.psteps li {
  display: flex;
  align-items: center;
  gap: 7px;
}

.psteps__num {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: #fff;
  font-weight: 700;
  color: var(--ink-muted);
}

.psteps li[aria-current="step"] .psteps__num {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--on-brand);
}

.psteps li[aria-current="step"] {
  color: var(--brand-deep);
  font-weight: 600;
}

.psteps li[data-done="yes"] .psteps__num {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

/* Why we verify on WhatsApp. Four reasons, as a list, because a list of four
   things is a list and four white boxes only make a reader hunt for the
   difference between them. */
.preasons {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  gap: 2px;
}

.preasons li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px;
  align-items: baseline;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
}

.preasons b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.preasons span {
  grid-column: 2;
  color: var(--ink-muted);
  font-size: 0.92rem;
}

.preasons__mark {
  grid-row: span 2;
  width: 20px;
  height: 20px;
  color: var(--brand-primary);
}

/* -------------------------------------------------------------------------
 * 5. The signed-in shell
 * ---------------------------------------------------------------------- */

.pshell {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 24px var(--gutter) 56px;
  display: grid;
  gap: 24px;
  /* minmax(0, 1fr), NOT 1fr.
   *
   * A bare 1fr is minmax(AUTO, 1fr), and an auto minimum is the track's
   * min-content, which here is the sidebar's scrolling row of eight links laid
   * out flat: 826px of it. So the track grew to fit content it was supposed to
   * be clipping, and the whole page scrolled sideways at 874px on a 390px
   * phone. `overflow-x: auto` on the row inside cannot help while the box
   * around it is free to grow.
   *
   * Every screen in the portal was doing this, which is the tell: a finding on
   * every screen is one shared element, never a coincidence. */
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 60rem) {
  .pshell {
    grid-template-columns: 250px minmax(0, 1fr);
    align-items: start;
  }
  /* On a wide screen the sidebar goes back to the left and spans both rows,
     with the heading above the content beside it. The markup order stays
     phone-first: heading, nav, content. */
  .pmain__head {
    grid-column: 2;
    grid-row: 1;
  }
  .pnav {
    grid-column: 1;
    grid-row: 1 / span 2;
  }
  .pmain {
    grid-column: 2;
    grid-row: 2;
  }
}

/* THE SIDEBAR IS TWO DIFFERENT THINGS.
 *
 * On a wide screen it is a column of chrome down the left, and deep purple is
 * right for that: it frames the page.
 *
 * On a phone it is a row above the content, and deep purple there put a second
 * dark block directly above the next-action card, which is also deep purple.
 * Two of them stacked read as one purple mass and the card that is supposed to
 * be the single thing to do stopped being the loudest thing on the screen.
 * So on a handset the nav is a light surface and the action keeps the dark.
 * One dark block per screen, and it is the one that matters.
 */
.pnav {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  /* Tighter on a phone, where this is a row and not a column. It was 18px all
     round, which on a handset is padding around a single line of links. */
  padding: 6px;
  color: var(--ink);
  /* Belt and braces with the track above: a grid ITEM also defaults to an
     auto minimum, so both have to be told they may be narrower than their
     contents before the row inside will scroll rather than push. */
  min-width: 0;
}

/* EVERY DESTINATION IS ON THE SCREEN. NONE OF THEM MOVES.
 *
 * This was a horizontally scrolling row with a fade at its right edge. At
 * 390px it measured 772px of chips inside a 336px rail, so a parent saw
 * "Dashboard, Applicants, Entrance test" and nothing else: Payments,
 * Documents, Messages, Profile and Help were off the screen with no control
 * pointing at them. A fade is not an affordance. A grandmother does not
 * horizontally swipe a strip of tabs to discover a page she has no reason to
 * believe exists, and the brief for this portal is that she will not scroll
 * to find a button she does not know is there.
 *
 * Wrapping costs about seventy pixels on a handset and shows all eight. It
 * also retires the `order: -1` trick that pulled the current page to the
 * front of the row: with everything visible there is nothing to pull forward,
 * and moving the menu around underneath somebody meant the menu was never
 * twice in the same place. Second-worst thing after a hidden control is one
 * that moves.
 */
.pnav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  /* Nothing scrolls any more, so nothing may be clipped either. */
  overflow: visible;
}

.pnav__rail {
  position: relative;
}

@media (min-width: 60rem) {
  /* Back to a column of chrome down the left, where deep purple frames the
     page instead of competing with the card beside it. */
  .pnav {
    background: var(--brand-deep);
    border-color: var(--brand-deep);
    padding: 18px 14px;
  }
  .pnav a {
    color: #EDE9F7;
  }
  .pnav a:hover {
    background: color-mix(in srgb, #fff 12%, transparent);
    color: #fff;
  }
  .pnav a[aria-current="page"] {
    background: #fff;
    color: var(--brand-deep);
  }
  .pnav__origin {
    background: color-mix(in srgb, #fff 10%, transparent);
    border-color: transparent;
    color: #EDE9F7;
    margin: 16px 0 0;
  }
  .pnav__origin b {
    color: #fff;
  }
  .psignout {
    margin: 16px 0 0;
    padding-top: 14px;
    border-top-color: color-mix(in srgb, #fff 18%, transparent);
  }
  .psignout button {
    color: #EDE9F7;
  }
  .pnav ul {
    display: grid;
    gap: 2px;
    overflow: visible;
  }
}

.pnav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-radius: 10px;
  font-family: var(--font-ui);
  font-size: 0.94rem;
  font-weight: 600;
  /* Stated, never inherited. White-on-white has shipped on this site three
     times from a parent band whitening its children, so every colour in this
     component names itself. */
  color: var(--ink-muted);
  text-decoration: none;
  white-space: nowrap;
}

.pnav a:hover {
  background: var(--surface);
  color: var(--brand-deep);
}

.pnav a[aria-current="page"] {
  background: var(--brand-primary);
  color: var(--on-brand);
}

.pnav__icon {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

.pnav__count {
  margin-left: auto;
  background: var(--brand-gold);
  color: var(--brand-deep);
  font-size: 0.75rem;
  font-weight: 700;
  border-radius: 999px;
  padding: 1px 8px;
}

/* The panel that says who made this account. It is only rendered for an
   account the school created at the desk, and it exists because "why do I
   already have a login I never made" is a question a parent is entitled to an
   answer to before they type anything into it. */
.pnav__origin {
  margin: 10px 6px 4px;
  padding: 12px 14px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-muted);
}

.pnav__origin b {
  display: block;
  color: var(--brand-deep);
  margin-bottom: 4px;
}

.pverified {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  padding: 5px 10px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--success) 80%, #000);
  color: #fff;
  font-weight: 600;
  font-size: 0.76rem;
}

.psignout {
  margin: 4px 14px 0;
  padding-top: 6px;
  border-top: 1px solid var(--rule);
}

@media (min-width: 60rem) {
  .psignout {
    margin-top: 16px;
    padding-top: 14px;
  }
}

.psignout button {
  font-family: var(--font-ui);
  background: none;
  border: 0;
  color: var(--ink-muted);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  /* 44px tall, because that is the smallest thing a thumb reliably finds.
     This was 35px, which is a miss on a phone and a miss on the one control
     that has to work when somebody is finished. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0;
  text-decoration: underline;
}

.pmain {
  display: grid;
  gap: 20px;
  /* Without this a long table or a wide rail makes the whole page scroll
     sideways instead of scrolling inside its own box. */
  min-width: 0;
}

/* And the same again for everything INSIDE it, which is the half that was
   missing. A grid item's automatic minimum size is its min-content width, so
   a card holding a table of `white-space: nowrap` cells refuses to be narrower
   than that table: the documents page measured 937px of card inside 350px of
   column, and every other card on the page stretched to match. `.pmain` having
   min-width:0 protected `.pmain` from `.pshell` and nothing from `.pmain`.
   **A grid item never gets to decide how wide the page is.** The scroller
   inside it does the scrolling. */
.pmain > * {
  min-width: 0;
}

.pmain__head h1 {
  margin: 0;
  font-size: var(--step-3);
  color: var(--brand-deep);
}

.pmain__head p {
  margin: 4px 0 0;
  color: var(--ink-muted);
}

/* -------------------------------------------------------------------------
 * 6. The dashboard's own components
 * ---------------------------------------------------------------------- */

.pcolumns {
  display: grid;
  gap: 20px;
}

@media (min-width: 48rem) {
  .pcolumns {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  }
}

/* The next action. Gold, because it is the one thing on the page to do, and
 * the site's gold is the crest's own. */
.pnext {
  background: var(--brand-deep);
  border-color: var(--brand-deep);
  /* Stated on the panel AND on the heading below. A deep ground whitening its
     children is exactly the rule that has shipped near-black on purple here
     before: it styled h2, h3 and h4 and not h1. */
  color: #fff;
}

.pnext h2,
.pnext h3 {
  color: #fff;
}

.pnext .portal-eyebrow {
  color: var(--brand-gold);
}

.pnext p {
  color: #E9E4F5;
}

/* Nothing to do is a real state and gets a quiet panel, not a gold one. */
.pnext--final {
  background: #fff;
  border-color: var(--line);
  color: var(--ink);
}

.pnext--final h2 {
  color: var(--brand-deep);
}

.pnext--final p {
  color: var(--ink-muted);
}

.pnext--final .portal-eyebrow {
  color: var(--brand-primary);
}

/* The eight-step rail. A list of eight things is a list. */
.pprogress__of {
  float: right;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-muted);
}

.pprogress__rail {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 0;
}

.pprogress__rail li {
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 4px 12px;
  align-items: baseline;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
}

.pprogress__rail li:first-child {
  border-top: 0;
}

.pprogress__rail b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.pprogress__rail span:last-child {
  grid-column: 2;
  color: var(--ink-muted);
  font-size: 0.9rem;
}

.pprogress__num {
  grid-row: span 2;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.85rem;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-muted);
}

.pprogress__rail li[data-state="done"] .pprogress__num {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.pprogress__rail li[data-state="now"] .pprogress__num {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: #fff;
}

.pprogress__rail li[data-state="now"] b {
  font-weight: 700;
}

.pprogress__rail li[data-state="todo"] b {
  color: var(--ink-muted);
  font-weight: 600;
}

/* Facts about one applicant. */
.pfacts {
  margin: 12px 0 0;
  display: grid;
  gap: 0;
}

.pfacts > div {
  display: grid;
  grid-template-columns: minmax(9rem, auto) 1fr;
  gap: 12px;
  padding: 9px 0;
  border-top: 1px solid var(--rule);
}

.pfacts dt {
  font-family: var(--font-ui);
  font-size: 0.88rem;
  color: var(--ink-muted);
}

.pfacts dd {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 600;
  color: var(--ink);
}

.papplicants {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 20px;
}

.pquiet {
  margin: 16px 0 0;
  color: var(--ink-muted);
  font-size: 0.9rem;
}

/* The two fees. */
.pfees {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
}

/* Stacked on a phone, two columns only when there is room.
 *
 * At 1fr auto on a 390px screen the state pill and the amount took the right
 * column and left the fee's name and its "not school fees" caveat wrapping in
 * a strip about twelve characters wide. The caveat is the sentence that stops
 * a parent thinking they have paid towards a term, so it is not something to
 * squeeze. */
.pfees li {
  display: grid;
  gap: 4px;
  padding: 14px 0;
  border-top: 1px solid var(--rule);
}

.pfees__state {
  justify-self: start;
}

@media (min-width: 30rem) {
  .pfees li {
    grid-template-columns: 1fr auto;
    gap: 2px 12px;
  }

  .pfees__state {
    justify-self: end;
  }
}

.pfees b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.pfees__state {
  font-family: var(--font-ui);
  font-size: 0.78rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-muted);
  white-space: nowrap;
}

.pfees li[data-state="pending"] .pfees__state {
  background: color-mix(in srgb, var(--brand-gold) 30%, #fff);
  border-color: color-mix(in srgb, var(--brand-gold) 60%, #fff);
  color: #6B4A00;
}

.pfees li[data-state="paid"] .pfees__state {
  background: color-mix(in srgb, var(--success) 14%, #fff);
  border-color: color-mix(in srgb, var(--success) 40%, #fff);
  color: #17532B;
}

.pfees li[data-state="failed"] .pfees__state {
  background: #FDECEC;
  border-color: #E9B7B7;
  color: #7A1F1F;
}

.pfees__note {
  font-size: 0.85rem;
  color: var(--ink-muted);
}

.pfees__amount {
  font-family: var(--font-ui);
  font-weight: 700;
  color: var(--brand-deep);
}

@media (min-width: 30rem) {
  .pfees__state {
    grid-column: 2;
    grid-row: 1;
  }

  .pfees__note {
    grid-column: 1;
  }

  .pfees__amount {
    grid-column: 2;
    text-align: right;
  }
}

.pannounce {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
}

.pannounce li {
  padding: 12px 0;
  border-top: 1px solid var(--rule);
  display: grid;
  gap: 2px;
}

.pannounce b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.pannounce span {
  color: var(--ink-muted);
  font-size: 0.92rem;
}

.pannounce time {
  font-family: var(--font-ui);
  font-size: 0.8rem;
  color: var(--ink-muted);
}

/* A fact where a control would otherwise be. Reads as an answer already
 * given, not as a disabled input: a greyed-out field invites a parent to
 * try to change it. */
.pstatic {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}

/* -------------------------------------------------------------------------
 * 7. The entrance test and the fees
 * ---------------------------------------------------------------------- */

.psittings {
  border: 0;
  margin: 0;
  padding: 0;
}

.psittings legend {
  padding: 0;
}

/* One sitting to choose. A whole row is the target, not just the radio: a
 * 20px circle is a hard thing to hit on a phone, and a label wrapping the
 * input makes the entire card the control for free. */
/* The row a parent taps to choose a date.
 *
 * On a phone the seats pill used to take a third column, which left the date
 * itself wrapping in about fourteen characters: "Friday, 11 Sep" then "2026"
 * on its own line, with the times and the note doing the same underneath. Four
 * ragged lines to say one thing. The pill now sits beside the date and
 * everything else runs the full width. */
.psitting {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 2px 12px;
  align-items: center;
  padding: 14px 4px;
  border-top: 1px solid var(--rule);
  cursor: pointer;
}

.psitting input {
  grid-column: 1;
  grid-row: 1 / -1;
  width: 22px;
  height: 22px;
  accent-color: var(--brand-primary);
}

.psitting__when {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--font-ui);
  font-weight: 700;
  color: var(--brand-deep);
}

.psitting__time,
.psitting__what {
  /* Full width under the date, rather than sharing it with the pill. */
  grid-column: 2 / -1;
  font-size: 0.88rem;
  color: var(--ink-muted);
}

.psitting__seats {
  grid-column: 3;
  grid-row: 1;
  align-self: center;
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-muted);
  white-space: nowrap;
}

/* A full sitting is SHOWN, greyed, rather than omitted. A parent told about a
 * date by the school and then not shown it assumes the site is broken. */
.psitting--full {
  cursor: not-allowed;
}

.psitting--full .psitting__when {
  color: var(--ink-muted);
}

.psitting--full .psitting__seats {
  background: #FDECEC;
  border-color: #E9B7B7;
  color: #7A1F1F;
}

.psitting:has(input:focus-visible) {
  outline: 3px solid var(--brand-tint);
  outline-offset: 2px;
  border-radius: 10px;
}

.pbring {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
}

.pbring li {
  padding: 10px 0 10px 28px;
  border-top: 1px solid var(--rule);
  position: relative;
  color: var(--ink);
}

.pbring li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 17px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand-primary);
}

.pamount {
  font-family: var(--font-ui);
  font-size: var(--step-2);
  font-weight: 700;
  color: var(--brand-deep);
  margin: 4px 0 12px;
}

.pmethods {
  border: 0;
  margin: 8px 0 0;
  padding: 0;
}

.pmethod {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 12px;
  padding: 12px 4px;
  border-top: 1px solid var(--rule);
  cursor: pointer;
}

.pmethod input {
  grid-row: span 2;
  align-self: center;
  width: 20px;
  height: 20px;
  accent-color: var(--brand-primary);
}

.pmethod__label {
  font-family: var(--font-ui);
  font-weight: 600;
  color: var(--brand-deep);
}

.pmethod__detail {
  grid-column: 2;
  font-size: 0.88rem;
  color: var(--ink-muted);
}

.pbank {
  margin-top: 18px;
  padding: 16px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
}

/* THE SCHOOL'S BANK DETAILS ARE TYPED ON SEPARATE LINES AND MUST READ AS
 * SEPARATE LINES. The office types
 *
 *     Privian Academy
 *     CBZ Bank, Borrowdale branch
 *     [currency] account [number]
 *
 * and HTML collapsed the newlines into one run-on sentence, where a parent
 * copying an account number off a phone cannot tell where the branch name
 * ends and the number begins. That is a deposit paid into nothing. */
.pbank__details {
  margin: 0;
  font-family: var(--font-ui);
  font-size: 1rem;
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.pbank__details span {
  display: block;
  /* A hanging indent, so a line too long for a handset still reads as one
     line: "USD account 021 1234 5678 900" wraps on a 390px screen, and a
     continuation starting hard against the left margin looks like a fourth
     line of the address rather than the end of the third. */
  padding-left: 1.4em;
  text-indent: -1.4em;
}

.presult h2 {
  font-size: var(--step-4);
  margin: 0 0 4px;
}

.presult--good {
  border-color: color-mix(in srgb, var(--success) 45%, #fff);
}

.presult--good h2 {
  color: var(--success);
}

/* A wide table scrolls INSIDE its own box. Letting the page scroll sideways
 * instead is how a phone ends up able to swipe the whole layout away. */
.ptablewrap {
  overflow-x: auto;
  /* Belt and braces: this is the box that is MEANT to scroll, so it must never
     be the box that grows. */
  min-width: 0;
  margin-top: 8px;
}

.ptable {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-ui);
  font-size: 0.9rem;
}

.ptable th,
.ptable td {
  text-align: left;
  padding: 10px 12px 10px 0;
  border-top: 1px solid var(--rule);
  color: var(--ink);
  white-space: nowrap;
}

.ptable thead th {
  border-top: 0;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.ptable tr[data-state="failed"] td,
.ptable tr[data-state="failed"] th {
  color: #7A1F1F;
}

/* A TABLE ON A PHONE IS A STACK OF ROWS, NOT A THING TO DRAG SIDEWAYS.
 *
 * The payments history and the documents list are four and five columns of
 * nowrap cells inside a 308px card. `.ptablewrap` kept them from taking the
 * page sideways, which was the bug that mattered, and left a parent with a
 * table she had to drag inside a card to read the last column: "Sent" and
 * "When" were simply not on the screen, and nothing said so. A grandmother
 * does not drag a table.
 *
 * Every cell already carries `data-label` -- the stacked mode was designed
 * and never written -- so each row becomes a small labelled block. Above the
 * fold of a wider screen it goes back to being a table, where a table is
 * genuinely the better shape. */
@media (max-width: 44rem) {
  .ptable,
  .ptable tbody,
  .ptable tr,
  .ptable th,
  .ptable td {
    display: block;
  }

  .ptable thead {
    /* Not display:none. The header row still names the columns for a screen
       reader; it is the sighted layout that no longer needs it, because the
       label is repeated on every cell. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .ptable tr {
    border-top: 1px solid var(--rule);
    padding: 10px 0 4px;
  }

  .ptable tr:first-child {
    border-top: 0;
  }

  .ptable th,
  .ptable td {
    border-top: 0;
    padding: 3px 0;
    /* The values are the point; they must be free to wrap. */
    white-space: normal;
    display: flex;
    gap: 12px;
    align-items: baseline;
    justify-content: space-between;
  }

  .ptable th[data-label]::before,
  .ptable td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    /* Stated, never inherited: this colour is drawn on a white card. */
    color: var(--ink-muted);
  }

  .ptable tbody th[scope="row"] {
    font-weight: 700;
  }
}

/* -------------------------------------------------------------------------
 * 8. Enrolment, messages and help
 * ---------------------------------------------------------------------- */

.pbtnrow {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* The three things that have to be true before a child is enrolled, exactly
 * as the school's design draws them. State is carried by a data attribute and
 * a word, never by colour alone. */
.pchecks {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
}

.pchecks li {
  display: grid;
  grid-template-columns: 24px 1fr;
  gap: 12px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
  font-family: var(--font-ui);
  color: var(--ink-muted);
}

.pchecks li::before {
  content: "";
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--line);
}

.pchecks li[data-done="yes"] {
  color: var(--brand-deep);
  font-weight: 600;
}

.pchecks li[data-done="yes"]::before {
  background: var(--success);
  border-color: var(--success);
}

.pchecks li[data-done="yes"]::after {
  content: "Done";
  grid-column: 2;
  justify-self: end;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--success);
}

.pmessages {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 16px;
}

.phelp {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
  display: grid;
}

.phelp li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 2px 12px;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
}

.phelp li::before {
  content: counter(step);
  grid-row: span 2;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--brand-primary);
}

.phelp b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.phelp span {
  grid-column: 2;
  color: var(--ink-muted);
  font-size: 0.9rem;
}

.pcontact {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
}

.pcontact li {
  border-top: 1px solid var(--rule);
  display: flex;
  gap: 10px;
  align-items: center;
  color: var(--ink);
  padding: 4px 0;
}

.pcontact a {
  color: var(--brand-primary);
  font-family: var(--font-ui);
  font-weight: 600;
  /* A parent taps this standing outside the school gate. 44px, and the whole
     row, rather than the 26px the text happened to occupy. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  flex: 1;
}

.pcontact li:not(:has(a)) {
  padding: 14px 0;
}

.pcontact__tag {
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--success) 14%, #fff);
  border: 1px solid color-mix(in srgb, var(--success) 40%, #fff);
  color: #17532B;
}

/* An individual slot carries less than a main test day: no description, since
 * the panel above the list says it once instead of repeating it on every row.
 * Twelve rows each ending in the same sentence is a reader scanning for a
 * difference that is not there. */
.psitting--slot {
  padding: 10px 4px;
}

.psitting--slot .psitting__when {
  font-weight: 600;
}

/* -------------------------------------------------------------------------
 * 9. Proof of payment
 * ---------------------------------------------------------------------- */

.pproofs {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
}

.pproofs li {
  padding: 18px 0;
  border-top: 1px solid var(--rule);
}

.pproofs__head {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  align-items: baseline;
  justify-content: space-between;
}

.pproofs b {
  font-family: var(--font-ui);
  color: var(--brand-deep);
}

.pproofs__amount {
  font-family: var(--font-ui);
  font-weight: 700;
  color: var(--brand-deep);
}

/* The reference is the one thing on this screen a parent has to copy onto a
 * bank deposit. It is set apart so it cannot be skimmed past. */
.pproofs__ref {
  margin: 8px 0 0;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--brand-gold) 16%, #fff);
  border: 1px solid color-mix(in srgb, var(--brand-gold) 50%, #fff);
  font-size: 0.92rem;
  color: var(--ink);
}

.pproofs__sent {
  margin: 10px 0 0;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--success) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--success) 35%, #fff);
  color: #17532B;
  font-size: 0.9rem;
}

/* A booking that is chosen and not yet confirmed.
 *
 * Deliberately NOT the success green and not the gold of an action: nothing
 * has gone wrong and there is nothing for the parent to do except wait, so it
 * reads as held rather than as either finished or failed. */
.portal-card--waiting {
  border-color: color-mix(in srgb, var(--brand-gold) 55%, #fff);
  background: color-mix(in srgb, var(--brand-gold) 7%, #fff);
}

/* What the school made of a document a parent sent. Colour is never the only
 * signal: the words say it too, and the reason for a refusal is printed under
 * it so a parent knows what to do rather than only that something is wrong. */
.ptable td[data-state="accepted"] {
  color: #17532B;
  font-weight: 600;
}

.ptable td[data-state="rejected"] {
  color: #7A1F1F;
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   What has happened at school: the parent's notifications.

   Built from the card and button this portal already has rather than a new
   surface. The only new idea on the page is the mark down the left of an
   unread row, which is the school's own gold: it says "this is the new one"
   without a second colour, a second border weight or a bolder face, all of
   which this file has enough of already.

   The whole row is the button. A card with a small "Open" link in it makes a
   parent aim, and she is reading this on a handset. */

.pnotify {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.pnotify__clear {
  display: flex;
  justify-content: flex-end;
  margin: 0 0 14px;
}

/* Padding comes off the card and goes onto the button inside it, so the
   whole surface is the tap target rather than a rectangle with a smaller
   rectangle in it. */
.pnotify__row {
  padding: 0;
  overflow: hidden;
}

.pnotify__open {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  width: 100%;
  padding: 18px 20px;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.pnotify__open:hover {
  background: var(--surface);
}

/* The mark. Present on every row so nothing moves when one is read; it is
   simply colourless once it has been. */
.pnotify__mark {
  flex: 0 0 auto;
  width: 4px;
  align-self: stretch;
  min-height: 2.6em;
  border-radius: 999px;
  background: transparent;
}

.pnotify__row--new .pnotify__mark {
  background: var(--brand-gold);
}

.pnotify__words {
  display: grid;
  gap: 3px;
  min-width: 0;
}

.pnotify__head {
  font-family: var(--font-ui);
  font-weight: 600;
  color: var(--brand-deep);
}

.pnotify__detail {
  color: var(--ink);
}

.pnotify__when {
  font-size: 0.8rem;
  color: var(--ink-muted);
}

/* What she is told about. A short list of real checkboxes, sized for a
   thumb: 20px is the smallest a checkbox may be on a handset and still be
   hit first time. */
.pnotify__choices { margin-top: 20px; }

.pnotify__choice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 0;
  cursor: pointer;
}

.pnotify__choice input {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  accent-color: var(--brand-primary);
  cursor: pointer;
}
