/* Parent portal (spec §5a) — mobile-first, navy design language. */
* { box-sizing: border-box; }
body { margin: 0; font-family: 'Segoe UI', system-ui, -apple-system, Arial, sans-serif;
       background: #f4f5f7; color: #1a1a2e; }
button, input, select { font-family: inherit; }

.pp-shell   { min-height: 100vh; display: flex; flex-direction: column; }
/* OPTION A - branded frame (2026-10-22).
   Red is the portal's IDENTITY here, not its action colour: the band and the
   mark carry the brand while every control keeps the colour it already had.
   That is deliberate - making "Book" red would put it in the same hue as
   "Cancel", and the week parents first meet this portal is the wrong week to
   change what a destructive action looks like.

   The band is a 4px rule and the logo sits on WHITE, never on the band. The
   Mathnasium mark contains this exact red, so a filled red header would
   swallow the A+. The booking emails solve it the same way, which is also why
   the two now look like one product. */
.pp-header  { background: #fff; color: #1a1a2e;
              border-top: 4px solid #ED1C24; border-bottom: 1px solid #e9ecef;
              padding: 11px 18px; display: flex;
              align-items: center; justify-content: space-between; gap: 10px; }
.pp-brand   { display: flex; align-items: center; gap: 9px; min-width: 0;
              font-size: 1.15rem; font-weight: 800; letter-spacing: .01em; white-space: nowrap; }
/* width/height are set on the tag too, so the header does not jump while the
   logo loads - the first thing a parent sees should not reflow under them. */
.pp-logo    { height: 24px; width: auto; display: block; flex-shrink: 0; }
.pp-brand span { font-weight: 400; font-size: .95rem; color: #868e96; opacity: 1; }
.pp-header-right { display: flex; align-items: center; gap: 12px; font-size: .85rem; }
.pp-header .pp-link { white-space: nowrap; font-size: .9rem; }
/* Was opacity .75 against a navy header; on white that reads as washed-out
   grey, so set the colour outright. */
.pp-header-right #ppWho { color: #667085; opacity: 1; max-width: 40vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pp-main    { flex: 1; width: 100%; max-width: 560px; margin: 0 auto; padding: 22px 16px 48px; }
.pp-card    { background: #fff; border-radius: 16px; padding: 26px 22px; box-shadow: 0 4px 18px rgba(26,26,46,.08); }
.pp-card h1 { margin: 0 0 4px; font-size: 1.45rem; }
.pp-state .pp-card + .pp-card { margin-top: 14px; }
.pp-hint    { margin-top: 12px; color: #868e96; font-size: .92rem; }
.pp-sub     { margin: 0 0 18px; color: #667085; }
/* Whose scheduler this is. Quiet, directly under the heading and before the
   contact field - a parent of ours skips it, and someone who arrived from a
   search looking for a different Mathnasium learns it before they type. */
.pp-centers { margin: 0 0 10px; color: #868e96; font-size: .85rem; font-weight: 600;
              letter-spacing: .01em; }

.pp-label   { display: block; font-size: .85rem; font-weight: 700; color: #495057; margin: 12px 0 5px; }
.pp-input   { width: 100%; padding: 14px 14px; border: 1.5px solid #dee2e6; border-radius: 12px;
              font-size: 1.05rem; outline: none; }
.pp-input:focus { border-color: #1a1a2e; }
.pp-code    { text-align: center; font-size: 1.9rem; letter-spacing: .45em; font-weight: 800; padding-left: .45em; }

.pp-btn     { width: 100%; margin-top: 16px; padding: 15px; border: none; border-radius: 12px;
              background: #1a1a2e; color: #fff; font-size: 1.05rem; font-weight: 700; cursor: pointer; }
.pp-btn:disabled { opacity: .55; }
.pp-btn-secondary { background: #eef0f3; color: #1a1a2e; }
.pp-btn-danger { background: #c92a2a; color: #fff; }
.pp-link    { display: inline-block; margin-top: 14px; background: none; border: none; color: #1971c2;
              font-size: .95rem; font-weight: 600; cursor: pointer; padding: 4px; }
/* #9ecbff was pale blue FOR A DARK HEADER - it is 1.7:1 on white, effectively
   invisible. On the white header these become the portal's ordinary link
   blue, which is 5.02:1. */
.pp-header .pp-link { color: #1971c2; margin: 0; }
.pp-err     { color: #c92a2a; font-weight: 600; margin-top: 10px; min-height: 1.2em; }

.pp-acct    { display: block; width: 100%; text-align: left; margin-top: 10px; padding: 16px;
              border: 1.5px solid #dee2e6; border-radius: 14px; background: #fff; cursor: pointer; font-size: 1.05rem; }
.pp-acct:hover { border-color: #1a1a2e; }
.pp-acct strong { display: block; }
.pp-acct span { color: #868e96; font-size: .9rem; }

.pp-stu     { background: #fff; border-radius: 16px; padding: 20px; margin-bottom: 16px;
              box-shadow: 0 4px 18px rgba(26,26,46,.07); }
.pp-stu-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pp-stu-name { font-size: 1.25rem; font-weight: 800; }
.pp-badge   { border-radius: 999px; padding: 4px 12px; font-size: .8rem; font-weight: 700; }
.pp-badge-ok  { background: #d3f9d8; color: #2b8a3e; }
.pp-badge-pps { background: #fff3bf; color: #997404; }
.pp-stu-center { color: #868e96; font-size: .9rem; }
.pp-appts   { margin-top: 12px; }
.pp-appt    { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 8px;
              padding: 8px 4px; border-top: 1px solid #f1f3f5; }
.pp-appt-status { font-size: .78rem; font-weight: 700; border-radius: 999px; padding: 3px 10px;
              background: #e7f5ff; color: #1971c2; white-space: nowrap; }
.pp-hist-toggle { margin-top: 6px; }
.pp-empty   { color: #868e96; padding: 10px 4px; }

/* Pre-cutover notice: earlier appointments are managed in the old system.
   Informational, not a warning - a family has done nothing wrong and nothing is
   broken, so this is a calm blue rather than the amber/red used for problems. */
.pp-note    { background: #eef6fb; border: 1px solid #c7e0f0; border-left: 4px solid #2a7ab0;
              border-radius: 8px; padding: 12px 14px; margin: 0 0 14px;
              color: #1c4f6b; font-size: .95rem; line-height: 1.45; }
.pp-foot    { text-align: center; color: #868e96; margin-top: 6px; }
.pp-foot-who { font-size: .85rem; margin-top: 2px; word-break: break-all; }

/* "Make sign-in easier" nudge / settings card */
.pp-nudge   { margin-bottom: 16px; border-left: 5px solid #1a1a2e; padding: 18px 20px; }
.pp-nudge-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.pp-nudge-head .pp-link { margin: 0; }
.pp-nudge-row { display: flex; align-items: center; justify-content: space-between; gap: 14px;
                padding: 12px 0; border-top: 1px solid #f1f3f5; }
.pp-nudge-row:first-of-type { border-top: none; }
.pp-nudge-row strong { display: block; }
.pp-nudge-row span { color: #868e96; font-size: .88rem; }
.pp-nudge-col { flex-direction: column; align-items: stretch; }
.pp-btn-small { width: auto; margin-top: 0; padding: 10px 16px; font-size: .95rem; white-space: nowrap; }
.pp-pwset   { display: flex; gap: 10px; }
.pp-pwset .pp-input { flex: 1; }

/* ---- booking flow ---- */
.pp-bookcta { margin-bottom: 16px; }
.pp-appt-acts { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
              gap: 2px; margin-left: auto; }
.pp-appt-acts .pp-link { margin-top: 0; }
.pp-stu-book { margin-left: auto; }
.pp-stu-head { justify-content: flex-start; }
.pp-link-danger { color: #c92a2a; }
.pp-book-head { display: flex; align-items: center; justify-content: space-between; }
.pp-book-head h1 { margin: 0; }
.pp-kids    { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.pp-kidchip { border: 1.5px solid #dee2e6; background: #fff; border-radius: 999px; padding: 9px 16px;
              font-size: 1rem; font-weight: 600; cursor: pointer; }
.pp-kidchip.on { background: #1a1a2e; color: #fff; border-color: #1a1a2e; }
.pp-kidchip em { font-style: normal; font-size: .72rem; font-weight: 800; opacity: .7; margin-left: 5px; }

.pp-mon-head { display: flex; align-items: center; justify-content: center; gap: 22px; margin-bottom: 8px; font-size: 1.1rem; }
.pp-mon-nav { border: none; background: #f1f3f5; border-radius: 8px; width: 38px; height: 38px; font-size: 1.3rem; cursor: pointer; }
.pp-mon-nav:disabled { opacity: .35; cursor: default; }
.pp-dow-row { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; color: #868e96;
              font-size: .78rem; font-weight: 700; margin-bottom: 4px; }
.pp-mon-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.pp-day     { text-align: center; padding: 10px 0; border-radius: 10px; font-weight: 600; }
.pp-day-blank { background: none; }
.pp-day-off { color: #ced4da; }
.pp-day-has { background: #e3faf0; color: #0b7a52; cursor: pointer; }
.pp-day-has:hover { background: #c3f0dd; }
.pp-day-full { background: #f1f3f5; color: #868e96; cursor: pointer; }
.pp-day-full:hover { background: #e9ecef; }
.pp-day-sel { background: #1a1a2e !important; color: #fff !important; }

/* EMPTY MONTH - stands in for the grid, never beside it.
   DASHED, and in the portal's own greys rather than a warning colour: nothing
   has gone wrong and the family has done nothing. It is a space waiting to be
   filled, and the one piece of colour is the way out. */
.pp-blank     { border: 2px dashed #dee2e6; border-radius: 14px; padding: 34px 22px 30px;
                text-align: center; }
.pp-blank-ico { width: 56px; height: 56px; border-radius: 50%; background: #f1f3f5;
                display: inline-flex; align-items: center; justify-content: center;
                color: #1a1a2e; margin-bottom: 14px; }
.pp-blank-h   { margin: 0 0 8px; font-size: 1.12rem; font-weight: 800; color: #1a1a2e; }
.pp-blank-p   { margin: 0 auto; max-width: 24em; color: #868e96; font-size: .95rem; line-height: 1.45; }
/* WHAT TO DO ABOUT IT. Banded and darker than the body text so it reads as an
   instruction rather than more explanation. The portal's informational blue,
   not amber or red: the family has a problem to solve, but nothing has gone
   wrong and nothing is being warned against. */
.pp-blank-do  { margin: 16px auto 0; max-width: 27em; background: #eef6fb;
                border: 1px solid #c7e0f0; border-radius: 10px; padding: 11px 14px;
                color: #1c4f6b; font-size: .92rem; font-weight: 600; line-height: 1.45; }
/* .pp-btn is full-width by default - here it is a single CTA under centred
   text, so it shrinks to its words. */
.pp-blank .pp-btn { width: auto; margin-top: 20px; padding: 13px 26px; font-size: 1rem; }

.pp-day-title { margin: 16px 0 8px; font-weight: 800; color: #1a1a2e; display: flex; align-items: center; gap: 7px; }
.pp-slot    { border: 1.5px solid #eef0f3; border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; }
.pp-slot-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; cursor: pointer; }
.pp-slot-chev { color: #adb5bd; font-size: .9rem; }
.pp-chev-ghost { visibility: hidden; }   /* pinned rows: reserve the chevron slot so seat pills align */
.pp-slot-heldtag { color: #2b8a3e; font-weight: 700; font-size: .85rem; white-space: nowrap; }
.pp-slot-bookedtag { color: #1971c2; font-weight: 700; font-size: .85rem; white-space: nowrap; }
/* Right-hand cluster of a time row: seats pill, booked/held tags, chevron. */
.pp-slot-tags { margin-left: auto; display: inline-flex; align-items: center; justify-content: flex-end;
              flex-wrap: wrap; gap: 6px 8px; }
.pp-slot-body { margin-top: 10px; }
.pp-toast { position: fixed; left: 50%; transform: translateX(-50%); bottom: 74px; z-index: 70;
            background: #1a1a2e; color: #fff; padding: 12px 18px; border-radius: 10px; max-width: 90%;
            font-weight: 600; box-shadow: 0 4px 16px rgba(0,0,0,.3); }
.pp-slot-loc { color: #868e96; font-size: .9rem; }
.pp-loc-pill { font-size: .78rem; font-weight: 700; border-radius: 999px; padding: 2px 10px; white-space: nowrap; }
.pp-locfilter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.pp-locchip { border: 1.5px solid #dee2e6; background: #fff; border-radius: 999px; padding: 8px 15px;
              font-size: .95rem; font-weight: 700; cursor: pointer; color: #495057; }
.pp-locchip.on { background: #1a1a2e; color: #fff; border-color: #1a1a2e; }
.pp-loc-group { margin-bottom: 16px; }
.pp-loc-grouphead { font-size: .8rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
              border-left: 4px solid #1a1a2e; padding: 2px 0 2px 10px; margin-bottom: 8px; }
/* "Where" step: big tappable center cards */
.pp-where { display: flex; flex-direction: column; gap: 11px; margin-top: 14px; }
.pp-where-card { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
              border: 1.5px solid #dee2e6; background: #fff; border-radius: 14px; padding: 16px;
              font-size: 1.1rem; font-weight: 800; color: #1a1a2e; cursor: pointer; }
.pp-where-card:hover { border-color: #1a1a2e; }
.pp-where-dot { width: 13px; height: 13px; border-radius: 50%; flex: none; }
.pp-where-name { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.pp-where-kids { font-size: 12px; color: #6b7686; font-weight: 400; }
.pp-where-chev { color: #adb5bd; font-size: 1.3rem; font-weight: 700; }
/* Calendar breadcrumb: the chosen center + a Change link */
.pp-crumb { display: flex; align-items: center; gap: 9px; margin-bottom: 14px; }
.pp-crumb-pin { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.pp-crumb-name { font-weight: 800; font-size: 1rem; }
.pp-crumb-change { margin-left: 4px; background: #eef0f3; border: none; border-radius: 999px;
              padding: 5px 12px; font-size: .82rem; font-weight: 800; color: #1a1a2e; cursor: pointer; }
.pp-crumb-change:hover { background: #e2e5ea; }
.pp-slot-seats { background: #e7f5ff; color: #1971c2; font-size: .8rem; font-weight: 700; white-space: nowrap;
              border-radius: 999px; padding: 3px 10px; }
.pp-slot-full { background: #f1f3f5; color: #868e96; font-size: .8rem; font-weight: 700; white-space: nowrap;
              border-radius: 999px; padding: 3px 10px; }
/* Seat-pill affordance. The pills are rounded white tags, and `cursor: pointer`
   does not exist on touch - so on a phone nothing told a parent that a child's
   name IS the button. Mirrors .pp-wd-sec (the spot-alert dialog's section
   labels) so it reads as part of the app rather than bolted on. parent.js
   renders it ONLY when at least one pill can actually be tapped. */
.pp-slot-kidslabel { margin: 10px 0 0; font-size: .78rem; font-weight: 700; letter-spacing: .4px;
                     text-transform: uppercase; color: #8a94a4; }
/* The pills and pair rows already carry margin-top:10px. Tighten it under the
   label so the label reads as belonging to them, not floating between two gaps. */
.pp-slot-kidslabel + .pp-slot-kids,
.pp-slot-kidslabel + .pp-pairkid { margin-top: 4px; }
.pp-slot-kids { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; align-items: center; }
.pp-kidseat { border: 1.5px solid #dee2e6; background: #fff; border-radius: 999px; padding: 8px 14px;
              font-weight: 600; cursor: pointer; }
/* HELD, not booked. Deliberately NOT the confident green this used to be: a
   solid green pill with a tick is the universal "done" symbol, so it told a
   parent they had finished when they had not - while the genuinely booked state
   below is only a quiet blue. The hierarchy was inverted. Amber plus a dashed
   edge reads as provisional, which is what a 5-minute hold is. */
.pp-kidseat.on { background: #fff4e6; color: #d9480f; border-color: #ffa94d;
              border-style: dashed; }
.pp-kidseat:disabled { opacity: .4; cursor: not-allowed; }
.pp-kidseat-paired { text-decoration: line-through; }
/* Already booked in this very time: shown plainly, not as a dimmed dead button. */
.pp-kidseat-booked, .pp-kidseat-booked:disabled { opacity: 1; background: #e7f5ff; color: #1971c2;
              border-color: #a5d8ff; cursor: default; }

/* Stagger pair, expanded: one row per student — name toggle + the two start-time chips.
   A name tap defaults to the chip with fewer seats filled; the chips swap/release. */
.pp-pairkid { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.pp-pairkid-name { font-weight: 600; }
.pp-pairkid-times { display: inline-flex; gap: 6px; }
.pp-timeseat { border: 1.5px solid #dee2e6; background: #fff; border-radius: 999px; padding: 6px 12px;
               font-weight: 600; font-size: .9rem; cursor: pointer; white-space: nowrap; }
.pp-timeseat.on { background: #2b8a3e; color: #fff; border-color: #2b8a3e; }
.pp-timeseat:disabled { opacity: .4; cursor: not-allowed; }
.pp-timeseat-def { border-color: #74c69d; }
.pp-pairkid-booked { color: #1971c2; font-weight: 700; font-size: .9rem; }

/* "Seats on hold" card on My Schedule (leaving the picker with seats held is never silent). */
.pp-resume { margin-bottom: 16px; border-left: 5px solid #1971c2; background: #f3f9ff; padding: 16px 18px; }
/* One line of text now, not a two-item flex row - the clock sits inline at the
   end of the sentence. */
.pp-resume-head { line-height: 1.35; }
.pp-resume-clock { font-weight: 800; font-size: 1.15rem; color: #1971c2;
                   font-variant-numeric: tabular-nums; white-space: nowrap; }
.pp-resume-text { margin: 4px 0 10px; color: #495057; }
.pp-resume-acts { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pp-resume-acts .pp-link { margin-top: 0; }
/* Icon action buttons on appointment rows (calendar / reschedule / cancel). */
.pp-icobtn { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
             border: none; background: none; border-radius: 8px; color: #1971c2; cursor: pointer; padding: 0; }
.pp-icobtn:hover { background: #e7f5ff; }
.pp-icobtn-danger { color: #c92a2a; }
.pp-icobtn-danger:hover { background: #fff0f0; }

/* Tap the appointment line: the icons slide open into labeled rows, and back. */
.pp-appt-line[data-apptx] { cursor: pointer; }
/* Centered as a GROUP: one max-content column so the icons share a left edge. */
.pp-appt-menu { flex: 1 0 100%; overflow: hidden; max-height: 0; opacity: 0;
                transition: max-height .2s ease, opacity .2s ease;
                display: grid; justify-content: center; }
.pp-appt-open .pp-appt-menu { max-height: 150px; opacity: 1; }
.pp-appt-open .pp-appt-acts { display: none; }
.pp-actline { display: flex; align-items: center; gap: 10px; padding: 9px 18px;
              background: none; border: none; border-radius: 8px; color: #1971c2;
              font-weight: 600; font-size: .95rem; cursor: pointer; text-align: left; text-decoration: none; }
.pp-actline:hover { background: #f8fbff; }
.pp-actline-danger { color: #c92a2a; }
.pp-actline svg { flex: 0 0 auto; }
.pp-slot-note { margin-top: 8px; font-size: .85rem; color: #868e96; }

/* Spot alerts ("notify me when a spot opens"): one button per full time + one dialog. */
.pp-watchbtn { border: 1.5px dashed #adb5bd; background: #fff; border-radius: 999px; padding: 8px 14px;
               font-size: .9rem; font-weight: 600; color: #495057; cursor: pointer; }
.pp-watchbtn.on { border-style: solid; background: #e6f4f3; border-color: #0f766e; color: #0f766e; }
.pp-wd { text-align: left; }
.pp-wd-title { font-weight: 700; font-size: 1.05rem; color: #1a1a2e; }
.pp-wd-sub { margin: 2px 0 2px; font-size: .88rem; color: #667085; }
.pp-wd-sec { margin: 14px 0 4px; font-size: .78rem; font-weight: 700; letter-spacing: .4px;
             text-transform: uppercase; color: #8a94a4; }
.pp-wd-row { display: flex; align-items: center; gap: 9px; padding: 7px 2px; font-size: .95rem;
             color: #1a1a2e; cursor: pointer; border-bottom: 1px solid #f1f3f5; }
.pp-wd-row:last-of-type { border-bottom: none; }
.pp-wd-row input { width: 17px; height: 17px; flex: 0 0 auto; }
.pp-wd-full { font-size: .74rem; font-weight: 700; color: #868e96; background: #f1f3f5;
              padding: 2px 7px; border-radius: 999px; }
.pp-wd-day { background: #f8fafc; border: 1px solid #e3e8ef; border-radius: 10px; padding: 9px 10px; margin-top: 6px; }
.pp-wd-chans { display: flex; gap: 2px 18px; flex-wrap: wrap; }
.pp-wd-chans .pp-wd-row { border-bottom: none; }
.pp-wd-hint { margin-top: 12px; font-size: .8rem; color: #868e96; line-height: 1.4; }
/* Private session tag on an appointment row (center-scheduled, read-only here). */
.pp-privtag { display: inline-block; margin-left: 4px; padding: 1px 8px; border: 1px dashed #adb5bd;
              border-radius: 999px; font-size: .72rem; font-weight: 700; color: #667085; vertical-align: 1px; }

/* Collapsed "Spot alerts (N)" section inside a student card (mirrors past appointments). */
.pp-watchlist { margin-top: 6px; }
.pp-watchnote { font-size: .82rem; color: #868e96; padding: 4px 0 2px; }
.pp-watchrow { display: flex; align-items: center; justify-content: space-between; gap: 12px;
               padding: 9px 0; border-top: 1px solid #f1f3f5; font-size: .95rem; }
.pp-watchmeta { display: block; font-size: .82rem; color: #868e96; }
.pp-watchrow .pp-link { margin-top: 0; }
.pp-skiplist { margin: 6px 0 0; padding-left: 18px; color: #495057; font-size: .92rem; }
.pp-skiplist li { margin-bottom: 3px; }

/* Held-seats strip: PINNED TO THE BOTTOM of the viewport (owner, 2026-10-27).
   An earlier fixed bottom bar was pulled for spanning the full width of a
   desktop window; this one is constrained to the same 560px column as
   .pp-main and centred, so it reads as part of the page rather than browser
   chrome.
   Centred with left/right:0 + margin:auto, NOT translateX(-50%): the bump
   animation below animates `transform`, which would overwrite a transform
   used for centring and snap the bar to the left on every seat added. */
.pp-basketbar { position: sticky; z-index: 40;
              bottom: calc(10px + env(safe-area-inset-bottom, 0px));
              margin: 12px 0 0;
              background: #1a1a2e; color: #fff; border-radius: 14px;
              display: block; padding: 10px 12px;
              box-shadow: 0 4px 14px rgba(26,26,46,.25); }
.pp-basketbar-main { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* The bar is #1a1a2e and .pp-btn is ALSO #1a1a2e, so this CTA was chrome-less
   white text sitting on its own background - the one control we most want
   pressed did not read as a control at all.
   BLUE, not green (owner, 2026-10-27). Green was reading as a completion
   state - "you are done" - on a button whose whole job is to say the opposite:
   the seats are still only held. Blue is the portal's existing action colour
   (#1971c2, already used for links and secondary actions), so this introduces
   no new hue; it just stops the CTA claiming success it has not earned. */
.pp-basketbar .pp-btn-small { margin: 0; white-space: nowrap; background: #1971c2; }
.pp-basketbar .pp-btn-small:hover { background: #1c7ed6; }
/* The compensating bottom padding that a FIXED bar needed is gone with it: a
   sticky bar keeps its place in the document flow, so it can never cover the
   last row of the day list and the column needs no padding hack. */

/* A hold is added one tap at a time from somewhere down the list. Without a
   change cue the only feedback is a number quietly ticking over on a bar the
   parent is not looking at. */
@keyframes pp-bump {
    0%   { transform: scale(1);     box-shadow: 0 4px 14px rgba(26,26,46,.25); }
    35%  { transform: scale(1.025); box-shadow: 0 6px 20px rgba(25,113,194,.55); }
    100% { transform: scale(1);     box-shadow: 0 4px 14px rgba(26,26,46,.25); }
}
.pp-basketbar-bump { animation: pp-bump .55s ease-out; }
@media (prefers-reduced-motion: reduce) {
    .pp-basketbar-bump { animation: none; }
}

/* "2 seats held for 4:05" fits beside the button on an ordinary phone, so the
   bar stays ONE row - the stacked version was two rows plus a sub-line and
   dominated the screen. Only the narrowest handsets stack, where side by side
   would squeeze the countdown onto its own line anyway. */
@media (max-width: 359px) {
    .pp-basketbar-main { flex-direction: column; align-items: stretch; gap: 8px; }
    .pp-basketbar .pp-btn-small { width: 100%; }
}

/* A day with one or more of the family's HELD seats: green dot under the number. */
.pp-day { position: relative; }
/* AMBER, matching the held pill - the same inversion applied here: a green dot
   said "this day is sorted" about a seat that expires in five minutes, while a
   genuinely booked day got a quiet navy one. */
.pp-day-held::after { content: ""; position: absolute; left: 50%; bottom: 3px; margin-left: -3px;
                      width: 6px; height: 6px; border-radius: 50%; background: #f08c00;
                      box-shadow: 0 0 0 1.5px #fff; }
.pp-day-held.pp-day-sel::after { background: #ffc078; box-shadow: 0 0 0 1.5px #1a1a2e; }

.pp-rev-kid { margin-bottom: 14px; }
.pp-rev-kid > strong { display: block; margin-bottom: 4px; }
/* Review rows are ONE line: "Thu, Oct 29 · 4:00 PM · Redmond        Remove" */
.pp-appt-line { display: flex; align-items: baseline; gap: 5px; white-space: nowrap; min-width: 0; }
.pp-appt-line span { color: #868e96; font-size: .88rem; overflow: hidden; text-overflow: ellipsis; }
.pp-remrow  { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid #f1f3f5; }
.pp-remrow > span { flex: 1 0 100%; font-weight: 700; }
.pp-remsel  { padding: 8px; border: 1.5px solid #dee2e6; border-radius: 8px; margin-left: 4px; }
.pp-holdnote { margin: 12px 0 8px; padding: 9px 14px; background: #e7f5ff; color: #1864ab; border-radius: 10px;
              font-weight: 700; font-size: .92rem; text-align: center; }

.pp-overlay { position: fixed; inset: 0; background: rgba(15,15,30,.55); display: flex; align-items: center;
              justify-content: center; padding: 18px; z-index: 60; }
.pp-modal   { background: #fff; border-radius: 16px; padding: 24px; max-width: 480px; width: 100%; }
.pp-modal h2 { margin: 0 0 12px; text-align: center; }
.pp-terms ul { padding-left: 18px; color: #495057; }

/* The cancel/reschedule deadline, shown next to the appointment it governs -
   on My Schedule while it can still be acted on, and on every basket row at
   confirm time. Recessive: it is reference, not an action. */
/* flex-basis 100% so it wraps onto its OWN line under the date and the action
   icons, rather than sitting between them and pushing the icons to a third
   row (.pp-appt is a wrapping flexbox with space-between). */
/* Actions that cannot act. The row already says so in words, so these must
   not look live - but they stay tappable, because tapping is how a parent
   learns WHY (the cutoff / center-scheduled explainer). Hover and keyboard
   focus lift them slightly so they still read as reachable, and the dimming
   is dropped entirely under prefers-contrast. */
.pp-ico-muted        { opacity: .35; }
.pp-ico-muted:hover,
.pp-ico-muted:focus-visible { opacity: .65; }
@media (prefers-contrast: more) { .pp-ico-muted { opacity: 1; } }

.pp-appt-cutoff { flex: 0 0 100%; font-size: 12.5px; color: #6b7686; margin: 0; line-height: 1.35; }

/* Terms at the end of booking rather than a gate at the start: by here the
   basket is known, so the bullets can point at the per-session deadlines
   above instead of naming a figure that may not apply to every row. */
.pp-terms-block { margin-top: 20px; padding-top: 14px; border-top: 1px solid #e3e6ea; }
.pp-terms-head  { font-size: 1rem; font-weight: 700; color: #1a1a2e; margin: 0 0 6px; }
.pp-terms-block .pp-terms ul { margin: 0; }
.pp-terms-agree { font-size: 13px; color: #495057; margin: 14px 0 0; text-align: center; }

/* Confirm bar: STICKY, not fixed. It is the last thing in the card, so
   sticky-bottom pins it to the foot of the viewport for as long as the review
   list extends past it, then lets it settle at the natural end. Because it
   keeps its place in the document flow it can never cover the last reminder
   row, and needs no compensating padding anywhere - which a fixed bar does.
   Negative margins bleed it to the card's edges; it supplies its own bottom
   padding in place of the card's. */
.pp-confirmbar {
    position: sticky; bottom: 0; z-index: 30;
    background: #fff;
    margin: 14px -22px -26px;
    padding: 12px 22px calc(18px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid #eef0f3;
    border-radius: 0 0 16px 16px;
}
/* min-height on .pp-err reserves a blank line; inside the bar that would make
   it permanently taller for an error that is almost never showing. */
.pp-confirmbar .pp-err { min-height: 0; margin-top: 0; }
.pp-confirmbar .pp-err:empty { display: none; }
.pp-confirmbar .pp-terms-agree { margin-top: 0; }
.pp-confirmbar .pp-btn { margin-top: 8px; }
.pp-confirm-msg { font-size: 1.05rem; line-height: 1.5; text-align: center; padding: 6px 2px 2px; }
.pp-modal-actions { display: flex; gap: 12px; margin-top: 18px; }
.pp-modal-actions .pp-btn { margin-top: 0; padding: 14px 10px; font-size: 1rem; }
.pp-state h1 { color: #1a1a2e; }

/* Visible keyboard focus on every interactive control. */
.pp-btn:focus-visible, .pp-link:focus-visible, .pp-kidchip:focus-visible, .pp-locchip:focus-visible,
.pp-kidseat:focus-visible, .pp-timeseat:focus-visible, .pp-icobtn:focus-visible, .pp-actline:focus-visible, .pp-appt-line:focus-visible, .pp-mon-nav:focus-visible, .pp-acct:focus-visible, .pp-input:focus-visible,
.pp-slot-head:focus-visible, .pp-day:focus-visible, .pp-remsel:focus-visible,
.pp-where-card:focus-visible, .pp-crumb-change:focus-visible {
    outline: 3px solid #74c0fc; outline-offset: 2px;
}

/* Phones: the header carries brand + three links; the signed-in email moves to the foot of My Schedule. */
@media (max-width: 520px) {
    .pp-header { padding: 10px 14px; }
    .pp-header-right { gap: 8px; }
    .pp-header-right #ppWho { display: none; }
    .pp-brand { font-size: 1.05rem; gap: 7px; }
    /* The logo shrinks before the links do - three links a parent taps matter
       more than a mark they only read. */
    .pp-logo { height: 21px; }
    /* Tighter gutters so a time row (time + location + seats) stays on one line. */
    .pp-main { padding: 18px 12px 48px; }
    .pp-card { padding: 22px 16px; }
    /* Match the phone card padding so the bar still bleeds edge to edge. */
    .pp-confirmbar { margin: 14px -16px -22px;
                     padding: 12px 16px calc(16px + env(safe-area-inset-bottom, 0px)); }
    .pp-slot { padding: 11px 12px; }
    .pp-slot-head strong { font-size: .95rem; }
    .pp-slot-seats, .pp-slot-full { font-size: .74rem; padding: 3px 8px; }
    .pp-timeseat { font-size: .82rem; padding: 5px 10px; }
}
@media (max-width: 360px) {
    .pp-brand span { display: none; }
}

/* In-button busy spinner: confirming a booking sends its emails inline, so the
   request takes a moment and the button must not look inert. */
.pp-spin {
    display: inline-block; width: 13px; height: 13px; margin-right: 8px;
    vertical-align: -2px; border: 2px solid currentColor; border-right-color: transparent;
    border-radius: 50%; animation: ppSpin .6s linear infinite;
}
@keyframes ppSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .pp-spin { animation-duration: 2s; } }

/* Global in-flight bar: only after 250ms, so quick taps show nothing. On a slow
   day it is how a parent knows the tap registered. */
.pp-busybar {
    position: fixed; top: 0; left: 0; height: 3px; width: 100%;
    background: transparent; z-index: 99999; pointer-events: none;
    opacity: 0; transition: opacity .15s ease;
}
.pp-busybar.on { opacity: 1; }
.pp-busybar.on::before {
    content: ''; display: block; height: 100%; width: 35%;
    background: linear-gradient(90deg, transparent, #2b8a3e, transparent);
    animation: ppBusySlide 1.1s ease-in-out infinite;
}
@keyframes ppBusySlide {
    0% { transform: translateX(-40%); }
    100% { transform: translateX(300%); }
}
@media (prefers-reduced-motion: reduce) {
    .pp-busybar.on::before { animation-duration: 3s; }
}

/* ---- Group by: Student | Date (2026-10-23) ------------------------------
   Shown only when the account has more than one student. The control is
   deliberately quiet - it changes a layout, it is not an action - so it sits
   as a small segmented pair rather than buttons competing with Book. */
.pp-grouprow {
    display: flex; align-items: center; justify-content: flex-end; gap: 9px;
    margin: 0 2px 10px;
}
.pp-grouplbl { font-size: .78rem; color: #868e96; }
.pp-groupseg { display: inline-flex; border: 1px solid #dee2e6; border-radius: 999px; overflow: hidden; background: #fff; }
.pp-groupbtn {
    border: 0; background: transparent; cursor: pointer; font: inherit;
    font-size: .8rem; padding: 6px 14px; color: #495057; min-height: 32px;
}
.pp-groupbtn.on { background: #1a1a2e; color: #fff; font-weight: 650; }

/* Date headings in the by-date list.
   FIRST ATTEMPT WAS WRONG and worth recording: a bold dark heading on white sat
   directly above a bold dark student name, at the same size and the same indent,
   so nothing said which was the container and which the content. Student mode
   gets that for free from the card edge; date mode has 8-20 groups, so one card
   each would be an enormous scroll.
   The heading therefore stops looking like a row and becomes a DIVIDER: a tinted
   band bled to the card edges, small, uppercase and muted - the opposite
   treatment to the rows rather than a louder version of them. */
.pp-daygrp + .pp-daygrp { margin-top: 2px; }
.pp-dayhd {
    position: sticky; top: 0; z-index: 1;
    background: #eef0f3;
    margin: 0 -20px;                 /* bleed to .pp-stu's 20px padding */
    padding: 7px 20px;
    font-size: .72rem; font-weight: 800; color: #495057;
    letter-spacing: .07em; text-transform: uppercase;
    border-top: 1px solid #e4e7eb; border-bottom: 1px solid #e4e7eb;
}
/* The band already draws the line above the first row; .pp-appt's own top rule
   on top of it reads as a double border. */
.pp-dayhd + .pp-appt { border-top: 0; }

/* Already-booked day marker (2026-10-23).
   Navy, to read as "yours/committed", against the GREEN held dot which means
   "in your basket, not yet confirmed" - two different states that can both be
   true on one day, so they must not look alike and must not overlap. */
.pp-day-booked::before { content: ""; position: absolute; left: 50%; bottom: 3px; margin-left: -3px;
                         width: 6px; height: 6px; border-radius: 50%; background: #1a1a2e;
                         box-shadow: 0 0 0 1.5px #fff; }
/* Both states on one day: shoulder the dots apart rather than stacking them. */
.pp-day-held.pp-day-booked::before { margin-left: -8px; }
.pp-day-held.pp-day-booked::after  { margin-left: 2px; }
/* On the selected day the cell turns navy, so the navy dot would vanish. */
.pp-day-booked.pp-day-sel::before { background: #fff; box-shadow: 0 0 0 1.5px #1a1a2e; }
/* A booked day with no open times here is still worth marking - it is just not
   clickable, so give it a cursor that says so rather than looking dead. */
.pp-day-off.pp-day-booked { color: #868e96; }

/* ---- re-hold screen (abandoned-cart email) --------------------------------
   Rows read as a status list, not a form: the parent is being told where each
   spot stands, and only then offered one action. State colour follows the
   portal's existing meanings - blue for informational, green for good news,
   grey for gone - and never red, because nothing here is an error or a
   cancellation. */
.pp-rh-loading { color: #868e96; padding: 10px 4px; }
.pp-rh-row  { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
              gap: 6px 10px; padding: 11px 4px; border-top: 1px solid #f1f3f5; }
.pp-rh-row:first-child { border-top: 0; }
.pp-rh-when { min-width: 0; }
.pp-rh-when span { color: #495057; }
.pp-rh-state { font-size: .78rem; font-weight: 700; border-radius: 999px; padding: 3px 10px;
               white-space: nowrap; }
.pp-rh-ok   { background: #e7f5ff; color: #1971c2; }
.pp-rh-done { background: #e6f4ea; color: #1b7340; }
.pp-rh-gone { background: #f1f3f5; color: #6b7686; }
/* The server's own sentence, on its own line: it is the part that says what to
   do next, so it must not be squeezed beside the chip. */
.pp-rh-why  { flex-basis: 100%; color: #6b7686; font-size: .88rem; line-height: 1.45; }

.pp-rh-alts { margin-top: 18px; border-top: 1px solid #e9ecef; padding-top: 14px; }
.pp-rh-altshead { margin: 0 0 6px; font-size: .95rem; font-weight: 700; color: #1a1a2e; }
.pp-rh-alt  { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
              gap: 6px 10px; padding: 9px 4px; border-top: 1px solid #f1f3f5; }
.pp-rh-altbtns { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

/* Carried onto the Review screen after a partial recovery. Amber: something
   did go wrong for the family, but nothing was cancelled and the rest of the
   basket is fine, so this is not the red of a failure. */
.pp-rh-banner { background: #fff7e6; border: 1px solid #f3e0b5; border-radius: 8px;
                padding: 11px 13px; margin: 0 0 12px; color: #7a5a12;
                font-size: .93rem; line-height: 1.5; }
