
:root {
  /* Tells the browser this page is happy either way, so the
     pieces IT draws - date and time pickers, scrollbars, the
     text caret - are dark in dark mode instead of being the
     next white rectangle to stand out. Same fault as the
     status bar, different owner. */
  color-scheme: light dark;

  /* PassLee.
     Blue leads, because red already means "needs full
     instruction" on the progress sliders and a red app would
     fight it. The L-plate red stays on the icon only. */
  --bg: #f4f6fa;
  --surface: #ffffff;
  --surface-2: #eef1f7;
  --border: #dde3ec;
  --border-soft: #e9edf3;
  --text: #131720;
  --dim: #5c6779;
  --faint: #8a94a6;
  --accent: #1a4fd6;
  --accent-dark: #1540ad;
  --accent-soft: rgba(26, 79, 214, .10);
  --accent-text: #ffffff;
  --danger: #c62828;
  --good: #14a05a;
  --head-bg: #eef1f7;
  --shadow: 0 1px 2px rgba(16,24,40,.05), 0 2px 6px rgba(16,24,40,.05);
  --radius: 14px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1017;
    --surface: #161b24;
    --surface-2: #1c2230;
    --border: #2a3240;
    --border-soft: #222937;
    --text: #e7ebf2;
    --dim: #9aa5b8;
    --faint: #78839a;
    --accent: #6f9bff;
    --accent-dark: #5a86ea;
    --accent-soft: rgba(111, 155, 255, .16);
    --accent-text: #0d1017;
    --danger: #ff7b72;
    --good: #4ec98a;
    --head-bg: #1c2230;
    --shadow: none;
    --radius: 14px;
  }
}

* { box-sizing: border-box; }

html {
  /* 🔴 NOTHING IN THIS APP IS EVER MEANT TO SCROLL
     SIDEWAYS. Lee found the terms page doing it on an
     iPhone. The two likely causes are fixed properly on
     that page; this stops the WHOLE CLASS of fault from
     reaching him as a page shunted half off the screen,
     which is unreadable rather than merely untidy.

     Anything genuinely wide - a table - already scrolls
     inside its own box, so this takes nothing away. */
  max-width: 100%;
  overflow-x: hidden;
}

body {
  margin: 0;
  max-width: 100%;
  overflow-x: hidden;
  /* Bottom padding clears the navigation bar, plus the home
     indicator on phones that have one. */
  padding: 18px 16px calc(80px + env(safe-area-inset-bottom, 0px));
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

/* ---------- the bottom navigation bar ---------- */
/* Added to every page by the hook, so no route needed
   changing to get it. */

.pl-nav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 50;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.pl-nav a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 9px 2px 7px;
  min-height: 56px;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--faint);
  text-decoration: none;
}

.pl-nav a svg { width: 22px; height: 22px; }
.pl-nav a.on { color: var(--accent); }
.pl-nav a:hover { text-decoration: none; color: var(--accent); }

/* ---------- cards ---------- */

.pl-cards {
  max-width: 760px;
  margin: 0 auto 20px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}

.pl-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
  text-decoration: none;
  color: var(--text);
}

.pl-card:hover { text-decoration: none; border-color: var(--accent); }
.pl-card .pl-card-title { font-weight: 650; }
.pl-card .pl-card-sub {
  font-size: .86rem; color: var(--dim); margin-top: 2px;
}
.pl-card .pl-big {
  font-size: 1.9rem; font-weight: 700; letter-spacing: -.02em;
  line-height: 1.1; color: var(--accent);
}

.pl-panel {
  max-width: 760px;
  margin: 0 auto 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
}

.pl-panel h2 { margin-top: 0; }
/* An address, over as many lines as it was typed on.
   pre-line rather than inserting <br>, so nothing in a pupil's
   address can ever become markup. */

.pl-address {
  white-space: pre-line;
  font-size: 1.05rem;
  line-height: 1.45;
}

.pl-event-off {
  opacity: .55;
  text-decoration: line-through;
}

/* 🔴 Not paid for. A band across the foot of the card,
   copied from Lee's own Total Drive diary, where every
   appointment carries one.

   It is a BAND and not a colour change, because the card
   colour already says which lesson type it is and whether
   it has been and gone. Three meanings, three places. */

.pl-event-owing::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: #d1332b;
}

/* ---------- the pupil page ---------- */

.pl-actions {
  max-width: 760px; margin: 0 auto 12px;
  display: flex; gap: 18px; padding: 10px 2px;
  border-bottom: 1px solid var(--border);
}
.pl-actions a { font-weight: 600; }

.pl-lesson-head { max-width: 760px; margin: 0 auto 14px; }
.pl-when-big {
  font-size: 1.15rem; font-weight: 650; margin-bottom: 8px;
}
.pl-pills { display: flex; gap: 7px; flex-wrap: wrap; }
.pl-pill {
  padding: 4px 12px; border-radius: 999px;
  font-size: .82rem; font-weight: 650;
}
.pl-pill-book { background: rgba(190,120,0,.16); color: #b07000; }
.pl-pill-type { background: var(--accent-soft); color: var(--accent); }
.pl-pill-paid { background: rgba(20,160,90,.16); color: #14a05a; }
.pl-pill-owing { background: rgba(209,51,43,.16); color: #d1332b; }

.pl-tests {
  max-width: 760px; margin: 0 auto 14px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
}
.pl-test-card {
  display: block;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 14px 16px;
  color: var(--text); text-decoration: none;
}
.pl-test-card:hover {
  text-decoration: none; border-color: var(--accent);
}
.pl-test-go {
  margin-top: 10px; font-size: .84rem; font-weight: 650;
  color: var(--accent);
}
.pl-test-name {
  font-size: .72rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 6px;
}
.pl-count {
  margin-top: 4px; font-size: 1.25rem; font-weight: 700;
  color: var(--accent); letter-spacing: -.01em;
}

@media (prefers-color-scheme: dark) {
  .pl-pill-book { background: rgba(224,162,74,.18); color: #e0a24a; }
}

/* ---------- call / text / navigate ---------- */

.pl-acts {
  max-width: 760px; margin: 0 auto 16px;
  display: flex; gap: 8px; flex-wrap: wrap;
}
.pl-act {
  flex: 1 1 90px;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  font-weight: 650; color: var(--accent); text-decoration: none;
}
.pl-act:hover { text-decoration: none; border-color: var(--accent); }

/* ---------- the quick-add button ---------- */
/* A + on every screen, because adding a lesson is the thing Lee
   does most. Built with <details> and NO JAVASCRIPT - a script
   here could break a page it has no business touching, and this
   cannot. */

.pl-quick {
  position: fixed;
  right: 16px;
  bottom: calc(78px + env(safe-area-inset-bottom, 0px));
  z-index: 40;
}
.pl-quick summary {
  list-style: none;
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--accent); color: var(--accent-text);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.7rem; font-weight: 300; line-height: 1;
  box-shadow: 0 4px 14px rgba(16, 24, 40, .28);
  cursor: pointer;
}
.pl-quick summary::-webkit-details-marker { display: none; }
.pl-quick[open] summary { background: var(--accent-dark); }
.pl-quick-menu {
  position: absolute; right: 0; bottom: 62px;
  min-width: 190px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 8px 24px rgba(16,24,40,.22);
  overflow: hidden;
}
.pl-quick-menu a {
  display: block; padding: 13px 16px; color: var(--text);
  text-decoration: none; font-weight: 600; font-size: .93rem;
  border-bottom: 1px solid var(--border-soft);
}
.pl-quick-menu a:last-child { border-bottom: 0; }
.pl-quick-menu a:hover { background: var(--surface-2); text-decoration: none; }

/* ---------- the standards check indicators ---------- */
/* One row per indicator: what it is, where Lee is, where the
   trigger is, and a bar showing how much room is left. The bar
   is decoration - the numbers beside it are the information,
   and they are readable without it. */

.pl-ind {
  max-width: 760px;
  margin: 0 auto 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
}
.pl-ind-top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
}
.pl-ind-name { font-weight: 650; }
.pl-ind-val { font-size: 1.35rem; font-weight: 700; letter-spacing: -.02em; }
.pl-ind-lim { font-size: .82rem; color: var(--dim); }
/* 🔴 NAMED pl-gauge, NOT pl-track.
   These were called .pl-track when the standards check was
   built, which is also what the progress slider has always
   called its row of five tap targets. The slider never set a
   height of its own, so it silently inherited `height: 9px;
   overflow: hidden` from here - 44px thumb targets clipped to
   nine. Lee found it as "very difficult to move, hit and miss".
   There is now a test that fails if any two top-level rules
   share a class name. */

.pl-gauge {
  margin-top: 9px; height: 9px; border-radius: 999px;
  background: var(--surface-2); overflow: hidden; position: relative;
}
.pl-gauge-fill { height: 100%; border-radius: 999px; }
.pl-verdict {
  display: inline-block; margin-top: 8px;
  font-size: .78rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; padding: 3px 9px; border-radius: 999px;
}
.pl-ok    { background: rgba(20,160,90,.14);  color: var(--good); }
.pl-near  { background: rgba(190,120,0,.16);  color: #b07000; }
.pl-over  { background: rgba(198,40,40,.14);  color: var(--danger); }

@media (prefers-color-scheme: dark) {
  .pl-near { background: rgba(224,162,74,.18); color: #e0a24a; }
}

.pl-headline {
  max-width: 760px; margin: 0 auto 14px;
  border-radius: var(--radius); padding: 16px 18px;
  border: 1px solid var(--border); background: var(--surface);
  box-shadow: var(--shadow);
}
.pl-headline .pl-big { font-size: 2.1rem; font-weight: 700;
  letter-spacing: -.02em; line-height: 1.05; }

/* Named pl-hint because .pl-note already existed as a
   highlighted callout box. Same collision as pl-track, caught
   by the same test. */

.pl-hint {
  max-width: 760px; margin: 0 auto 14px;
  font-size: .87rem; color: var(--dim); line-height: 1.5;
}

/* ---------- the week diary ---------- */
/* A Google Calendar style grid. The whole thing scrolls
   sideways on a phone, with the time column pinned to the
   left so you always know what hour you are looking at. */

.pl-cal-bar {
  max-width: 980px;
  margin: 0 auto 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  /* 🔴 Five buttons in this bar since bug batch 5, not
     three. Wrapping means a narrow phone stacks them
     rather than squashing them off the edge. */
  flex-wrap: wrap;
}

.pl-cal-bar .pl-when { font-weight: 650; }

.pl-cal-bar a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  min-height: 40px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  font-weight: 600;
  font-size: .9rem;
}

.pl-cal {
  max-width: 980px;
  margin: 0 auto 16px;
  overflow: auto;              /* both ways: hours and days */
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);

  /* The bar is hidden, the scrolling is not. A visible
     scrollbar made the diary look like a panel embedded in the
     page rather than the page itself. Every browser needs
     telling separately - there is no single standard property
     that covers all of them. */
  scrollbar-width: none;         /* Firefox */
  -ms-overflow-style: none;      /* older Edge */
}

.pl-cal::-webkit-scrollbar {     /* Safari, Chrome */
  width: 0;
  height: 0;
}

.pl-cal-inner { min-width: 660px; }

.pl-cal-head {
  display: flex;
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.pl-cal-head .pl-gutter { flex: 0 0 46px; }

.pl-cal-head .pl-dh {
  flex: 1 1 0;
  min-width: 84px;
  text-align: center;
  padding: 8px 2px;
  border-left: 1px solid var(--border-soft);
}

.pl-dh .pl-dow {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint);
}
.pl-dh .pl-dnum { font-size: 1.15rem; font-weight: 650; line-height: 1.2; }
.pl-dh.pl-today .pl-dnum {
  color: var(--accent-text);
  background: var(--accent);
  border-radius: 999px;
  display: inline-block;
  min-width: 30px;
  padding: 1px 6px;
}

.pl-cal-body { display: flex; }

.pl-gutter {
  flex: 0 0 46px;
  position: sticky;
  left: 0;
  z-index: 4;
  background: var(--surface);
  border-right: 1px solid var(--border);
}

.pl-hour {
  height: 56px;
  font-size: .68rem;
  color: var(--faint);
  text-align: right;
  padding: 2px 5px 0 0;
  border-top: 1px solid var(--border-soft);
}

.pl-day {
  flex: 1 1 0;
  min-width: 84px;
  position: relative;
  border-left: 1px solid var(--border-soft);
}

.pl-day.pl-today-col { background: var(--accent-soft); }

.pl-slot {
  display: block;
  height: 28px;
  border-top: 1px solid var(--border-soft);
  text-decoration: none;
}

.pl-slot.pl-hourline { border-top-color: var(--border); }
.pl-slot:hover { background: var(--accent-soft); }

/* 🔴 Time off, drawn BEHIND the lessons.

   z-index 1 puts it above the empty slots and below
   .pl-event at 2, so a lesson booked into time off -
   which is allowed, after a warning - stays readable.

   pointer-events: none so the slots underneath can still
   be tapped. "You are away" is information, not a lock. */

.pl-off {
  position: absolute;
  left: 2px; right: 2px;
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
  border-radius: 6px;
  padding: 3px 6px;
  font-size: .68rem;
  line-height: 1.2;
  font-weight: 650;
  color: #ffffff;
  background-color: #6b5ca5;
  background-image: repeating-linear-gradient(
      135deg,
      rgba(255, 255, 255, .00) 0px,
      rgba(255, 255, 255, .00) 7px,
      rgba(255, 255, 255, .16) 7px,
      rgba(255, 255, 255, .16) 14px);
  opacity: .82;
}

/* 🔴 The reason first, then the times under it - exactly
   the shape of a lesson card, and exactly the same values
   as .pl-event b and .pl-event span below.

   These were missed when .pl-off was written, because
   those rules hang off .pl-event BY NAME. Everything ran
   together on one line: "Test07:00-08:00". Lee spotted it
   in a screenshot; no test did, because every check asked
   whether the text was there, not how it was arranged. */

.pl-off b {
  display: block;
  font-weight: 600;
  line-height: 1.15;
}

.pl-off span {
  display: block;
  font-weight: 700;
  line-height: 1.2;
}

.pl-event {
  position: absolute;
  left: 2px; right: 2px;
  background: var(--accent);
  color: var(--accent-text);
  border-radius: 7px;
  padding: 3px 6px;
  font-size: .72rem;
  line-height: 1.25;
  overflow: hidden;
  text-decoration: none;
  box-shadow: var(--shadow);
  z-index: 2;
}

.pl-event:hover { text-decoration: none; background: var(--accent-dark); }

/* Name first, then the times under it in bold - copied from
   Lee's Total Drive diary. The card hides its overflow, so a
   short lesson loses the end time rather than squashing
   everything. */
.pl-event b {
  display: block;
  font-weight: 600;
  line-height: 1.15;
}

.pl-event span {
  display: block;
  font-weight: 700;
  line-height: 1.2;
}

/* ---------- tabs and list rows ---------- */

.pl-tabs {
  display: flex;
  gap: 4px;
  max-width: 760px;
  margin: 0 auto 12px;
  overflow-x: auto;
  scrollbar-width: none;
}

.pl-tabs::-webkit-scrollbar { height: 0; }

.pl-tab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 13px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: .88rem;
  font-weight: 600;
  color: var(--dim);
  text-decoration: none;
  white-space: nowrap;
}

.pl-tab span {
  font-size: .75rem;
  background: var(--surface-2);
  border-radius: 999px;
  padding: 1px 7px;
}

.pl-tab.pl-tab-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-text);
}

.pl-tab.pl-tab-on span {
  background: rgba(255, 255, 255, .22);
  color: inherit;
}

.pl-tab:hover { text-decoration: none; }

.pl-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 760px;
  margin: 0 auto 8px;
  padding: 13px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--text);
  text-decoration: none;
}

.pl-row:hover { text-decoration: none; border-color: var(--accent); }
.pl-row-main { min-width: 0; }
.pl-row-edit span {
  color: var(--accent);
  font-size: .88rem;
  font-weight: 600;
  padding: 8px 4px;
  cursor: pointer;
}

.pl-eyebrow {
  max-width: 760px; margin: 24px auto 8px;
  font-size: .72rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint);
}

/* Everything sits in one readable column on any screen. */
body > * { max-width: 760px; margin-left: auto; margin-right: auto; }

h1 {
  font-size: 1.55rem; line-height: 1.2; margin: 0 0 14px;
  letter-spacing: -.02em; font-weight: 700;
}
h2 { font-size: 1.18rem; line-height: 1.25; margin: 26px 0 10px;
     letter-spacing: -.01em; }
h3 { font-size: 1.02rem; margin: 18px 0 8px; }

p { margin: 0 0 14px; }

hr { border: 0; border-top: 1px solid var(--border); margin: 26px auto; }

a { color: var(--accent); text-decoration: none; font-weight: 500; }
a:hover { text-decoration: underline; }

/* Navigation links are the main way round the app and are
   tapped with a thumb, so they get a real target size. */
p > a { display: inline-block; padding: 7px 2px; }

/* --- tables ---------------------------------------------- */
/* Wrapped by the hook so a wide table scrolls inside itself
   instead of forcing the whole page sideways. */
.pl-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 auto 18px;
  max-width: 760px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

table {
  border-collapse: collapse;
  width: 100%;
  border: 0 !important;
  font-size: .97rem;
}

th, td {
  text-align: left;
  padding: 11px 13px !important;
  border: 0;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

th { background: var(--head-bg); font-weight: 600; white-space: nowrap; }

tr:last-child th, tr:last-child td { border-bottom: 0; }

td a { display: inline-block; padding: 4px 0; }

/* --- forms ------------------------------------------------ */
/* 16px minimum stops iOS zooming in when a field is focused. */
input, select, textarea, button {
  font-family: inherit;
  font-size: 16px;
  color: var(--text);
}

input, select, textarea {
  width: 100%;
  max-width: 420px;
  padding: 11px 12px;
  min-height: 44px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}

/* 🔴🔴 A TICK BOX IS NOT A TEXT BOX.

   26 August 2026. On a pupil's iPhone the "I have read and
   agree" line came out ONE LETTER PER LINE down the edge of
   the screen. Lee: "really bad".

   The cause was the rule directly above this one: it gives
   every <input> full width and a 44px height, which is
   right for a name box and absurd for a tick. The tick took
   the whole row, the label was left with no width, and a
   label told it may break anywhere broke after every single
   character.

   THE LABEL WAS NOT MISBEHAVING. IT WAS OBEYING TWO CORRECT
   RULES INSIDE A BOX WITH NO ROOM IN IT.

   🔴 THIS WINS BY SPECIFICITY, NOT BY POSITION - an
   attribute selector beats a bare element selector wherever
   it sits, including inside the phone-sized rules further
   down, which is exactly where a bottom-of-the-file fix
   would have been undone.

   🔴 AND IT SITS HERE, EARLY, ON PURPOSE: `.pl-dot input`
   hides its input deliberately and comes later with equal
   specificity, so it still wins. Un-hiding the progress
   dots would have traded one broken screen for another. */

input[type="checkbox"], input[type="radio"] {
  width: 22px;
  min-width: 22px;
  max-width: 22px;
  height: 22px;
  min-height: 22px;
  padding: 0;
  flex: 0 0 22px;
  border-radius: 4px;
  accent-color: var(--accent);
}

textarea { min-height: 96px; }

/* Inside a table the control fits the cell, not the page. */
td select, td input { max-width: 100%; min-width: 150px; }

button, input[type="submit"] {
  width: auto;
  min-width: 150px;
  min-height: 46px;
  padding: 11px 22px;
  background: var(--accent);
  color: var(--accent-text);
  border: 0;
  border-radius: 10px;
  font-weight: 650;
  cursor: pointer;
  box-shadow: var(--shadow);
}

button:active, input[type="submit"]:active {
  background: var(--accent-dark);
}

button:hover, input[type="submit"]:hover { opacity: .9; }

label { display: inline-block; margin-bottom: 4px; color: var(--dim); }

/* --- progress sliders -------------------------------------- */
/* Built to match Total Drive, which is what Lee has used for
   years. Five dots, filled from the left, orange until the
   pupil is independent and then green. The colour is the
   point: it is what makes a hundred-item list scannable. */

.pl-save-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  margin: 0 auto 10px;
  max-width: 760px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.pl-save-bar h1 { margin: 0; font-size: 1.15rem; }
.pl-save-bar button { min-width: 0; padding: 10px 18px; }

.pl-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 26px auto 4px;
  max-width: 760px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.pl-section-head h2 { margin: 0; font-size: 1.05rem; }
.pl-pct { display: flex; align-items: center; gap: 8px; font-weight: 700; }

.pl-item {
  max-width: 760px;
  margin: 0 auto;
  padding: 12px 4px 4px;
  border-bottom: 1px solid var(--border);
}

.pl-item-name { font-weight: 600; }
.pl-stage { color: var(--dim); font-size: .92rem; margin: 2px 0 6px; }

.pl-track { display: flex; align-items: center; margin: 0 0 6px; }

.pl-dot {
  flex: 1;
  position: relative;
  height: 44px;              /* a real thumb target */
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.pl-dot input { position: absolute; opacity: 0; width: 1px; height: 1px; }

/* TWO BARS PER DOT, and the reason is worth keeping.
   ::before is the grey track and is always the full width of
   its cell. ::after is the coloured fill and gets trimmed to
   the dot's centre when it is the last one coloured.
   They were one element until 24 August 2026, which meant the
   fill had to run to the edge of the cell - half a gap past
   the dot Lee had actually chosen. */

.pl-dot::before,
.pl-dot::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 6px;
  transform: translateY(-50%);
}

.pl-dot::before { background: var(--border); }
.pl-dot::after { background: transparent; }

.pl-dot:first-child::before,
.pl-dot:first-child::after { left: 50%; }

.pl-dot:last-child::before,
.pl-dot:last-child::after { right: 50%; }

.pl-dot i {
  position: relative;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--border);
}

/* Filled up to the chosen stage. Level 0 fills nothing, so a
   pupil who has not started shows an empty grey track - which
   is exactly how Total Drive shows it.

   TRAFFIC LIGHT, at Lee's instruction 24 August 2026:
   "I would use red, amber and then green for complete".
   Red while they need full instruction, through orange and
   amber, to green when they can do it alone. The point is that
   a section of red jumps out of an eighty-item list. */

.pl-track.lvl-1 .pl-dot:nth-child(-n+2)::after,
.pl-track.lvl-1 .pl-dot:nth-child(-n+2) i { background: #d1332b; }

.pl-track.lvl-2 .pl-dot:nth-child(-n+3)::after,
.pl-track.lvl-2 .pl-dot:nth-child(-n+3) i { background: #e07a00; }

.pl-track.lvl-3 .pl-dot:nth-child(-n+4)::after,
.pl-track.lvl-3 .pl-dot:nth-child(-n+4) i { background: #c9a200; }

.pl-track.lvl-4 .pl-dot::after,
.pl-track.lvl-4 .pl-dot i { background: #14a05a; }

/* The fill stops AT the chosen dot, not at the end of its cell.
   These must stay BELOW the colour rules above - same
   specificity, so the later one wins.
   Level 4 needs no rule: its last coloured dot is :last-child,
   which is already trimmed. That is also why level 4 was the
   only one that ever looked right. */

.pl-track.lvl-1 .pl-dot:nth-child(2)::after { right: 50%; }
.pl-track.lvl-2 .pl-dot:nth-child(3)::after { right: 50%; }
.pl-track.lvl-3 .pl-dot:nth-child(4)::after { right: 50%; }

.pl-track.changed i { box-shadow: 0 0 0 3px rgba(27, 87, 214, .25); }

.pl-index {
  max-width: 760px;
  margin: 0 auto 8px;
  font-size: .92rem;
}

.pl-index a { display: inline-block; padding: 6px 10px 6px 0; }

.pl-note {
  max-width: 760px;
  margin: 0 auto 12px;
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--accent-soft, rgba(27, 87, 214, .09));
  border: 1px solid var(--border);
}

/* --- the diary on a phone ---------------------------------- */
/* Lee: "I can only see 4 days before I have to scroll ... I
   should be able to view all 7 days at once."

   The columns had a minimum width for legibility, which made a
   week wider than a phone. Below 700px they give that up and
   share whatever is there: roughly 45px each once the time
   column is taken off, which is enough for the date and a
   colour block. The pupil's name is trimmed rather than the
   week being cut short - seeing the shape of the week matters
   more than reading every name, and tapping still opens it. */

@media (max-width: 700px) {

  .pl-cal-inner { min-width: 0; }

  .pl-day,
  .pl-cal-head .pl-dh { min-width: 0; }

  .pl-gutter,
  .pl-cal-head .pl-gutter { flex: 0 0 34px; }

  .pl-hour { font-size: .58rem; padding: 2px 3px 0 0; }

  .pl-dh { padding: 6px 1px; }
  .pl-dh .pl-dow { font-size: .55rem; letter-spacing: .02em; }
  .pl-dh .pl-dnum { font-size: .92rem; }
  .pl-dh.pl-today .pl-dnum { min-width: 22px; padding: 1px 3px; }

  .pl-event {
    font-size: .56rem;
    padding: 2px 3px;
    left: 1px; right: 1px;
    border-radius: 5px;
    line-height: 1.15;
  }

  /* Earlier today the time was hidden here to make room for the
     name. Lee looked at it against his own diary and wants the
     time shown, so it is back - just small. The card clips
     whatever will not fit. */
  .pl-event span { font-size: .55rem; }
}

/* --- small screens ---------------------------------------- */
@media (max-width: 560px) {
  body { padding: 16px 12px 56px; font-size: 16px; }
  h1 { font-size: 1.4rem; }
  input, select, textarea, button, input[type="submit"] { max-width: 100%; width: 100%; }
  td select, td input { min-width: 0; }
}


/* =================================================
   🔴🔴 A TAP HAS TO SHOW, IMMEDIATELY.
   =================================================

   Lee, 26 August 2026: "I am pressing a button and nothing
   is happening, I then press it another 5 times."

   HE DID NOT DESCRIBE A SLOW APP. He described a DEAD one.
   A wait with no sign of life is not experienced as a wait,
   it is experienced as a broken button - and no amount of
   making the page smaller fixes that, because even a fifth
   of a second of nothing reads as broken.

   🔴 NO JAVASCRIPT IN THIS PART ON PURPOSE. The phone does
   it, on the touch, before a single byte is requested. It
   cannot be late because nothing has to run. */

a:active, button:active, .pl-tab:active, [role="button"]:active {
  opacity: .55;
  transform: scale(.985);
}

a, button, .pl-tab {
  -webkit-tap-highlight-color: transparent;
  transition: opacity .08s linear, transform .08s linear;
}

/* The line that crawls across the top while the next page
   is coming. Deliberately slow and never quite finishing -
   it is honest about not knowing how long this will take,
   and it stops the screen looking frozen. */

/* 🔴 IT MOVES WITH transform, NOT width.

   Animating width makes the phone work out the layout of
   the whole page again on EVERY FRAME, sixty times a
   second, for as long as the animation runs - on a diary
   full of lessons that is real work, done exactly while
   somebody is waiting and judging the app.

   A transform is handed to the graphics chip and costs
   the page nothing. Same line, none of the cost. */

#pl-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  will-change: transform;
  background: var(--accent);
  z-index: 99999;
  pointer-events: none;
  opacity: 0;
}

#pl-bar.on {
  transform: scaleX(.92);
  opacity: 1;
  transition: transform 9s cubic-bezier(.05, .7, .1, 1);
}
