/* SPACS College platform.
   Tokens and component names are lifted from the approved mockup gallery, so these screens
   behave like the ones SPACS signed off rather than merely resembling them.
   Plain CSS on purpose: there is no build step to run on a cPanel host at deploy time. */
:root{
  --navy:#253D79; --navy-2:#31509A; --navy-ink:#16265E;
  --green:#4FB248; --green-dk:#3E9439; --green-lt:#EAF6E8;
  --gold:#B79600; --gold-lt:#FBF3CC; --gold-br:#F0DC55;
  --red:#D42A22; --red-lt:#FBEAE9;
  --ink:#14203A; --body:#4E5A72; --faint:#8A94A8;
  --line:#E3E8F0; --line-2:#EDF1F7; --wash:#F6F8FC;
  --sb:222px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--wash);color:var(--ink);min-height:100vh;
  font-family:'IBM Plex Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  font-size:14px;line-height:1.5}
h1,h2,h3,h4,h5{font-family:'Space Grotesk',sans-serif;letter-spacing:-.02em;margin:0}
.mono{font-family:'IBM Plex Mono',ui-monospace,monospace}
.hide{display:none !important}
a{color:inherit}
img{max-width:100%}
:focus-visible{outline:2px solid var(--navy-2);outline-offset:2px}

/* ---------- sign in ---------- */
.auth{min-height:100vh;display:grid;place-items:center;padding:24px;position:relative;overflow:hidden;
  background:radial-gradient(60% 80% at 15% 10%,rgba(49,80,154,.55),transparent 60%),
             radial-gradient(50% 70% at 100% 100%,rgba(79,178,72,.35),transparent 62%),
             linear-gradient(160deg,#16265E 0%,#253D79 55%,#101A38 100%)}
.auth-card{width:100%;max-width:400px;background:#fff;border-radius:16px;padding:32px 34px;
  box-shadow:0 30px 70px -20px rgba(6,16,40,.55);position:relative;z-index:1}
.auth-card .crest{display:block;height:70px;margin:0 auto 18px}
.auth-card h1{font-size:21px;font-weight:800;text-align:center}
.auth-card .sub{font-size:12.5px;color:var(--faint);text-align:center;margin:5px 0 24px}
.auth-card label{display:block;font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--faint);font-weight:700;margin-bottom:6px}
.auth-card input{width:100%;border:1px solid var(--line);border-radius:9px;padding:11px 13px;
  font-size:13.5px;font-family:inherit;color:var(--ink);background:#fff;margin-bottom:15px}
.auth-card .btn{width:100%;justify-content:center}
.auth-note{font-size:11px;color:var(--faint);text-align:center;margin-top:16px;line-height:1.6}

/* ---------- shell ---------- */
/* A proper app shell: the sidebar holds the viewport height and the main column scrolls
   inside it. Previously the shell only had a minimum height, so on a long page the sidebar
   stretched to the full height of the document and the footer carrying the signed-in name and
   the sign-out button ended up far below the fold, reachable only by scrolling to the very
   bottom of a list of courses. dvh first so a mobile browser's collapsing toolbar does not
   cut the sidebar off. */
.shell{display:flex;min-height:100vh;height:100vh;height:100dvh;overflow:hidden}
.sb{width:var(--sb);flex:none;background:var(--navy);color:#CBD7E8;display:flex;flex-direction:column;
  padding:20px 0;height:100%;overflow-y:auto;transition:width .18s ease}
.sb-logo{display:flex;align-items:center;gap:10px;padding:0 18px 20px;border-bottom:1px solid rgba(255,255,255,.1)}
.sb-logo img{width:32px;height:32px;object-fit:contain;background:#fff;border-radius:8px;padding:3px}
.sb-logo b{font-size:13.5px;color:#fff;font-weight:700;display:block;line-height:1.15}
.sb-logo span{font-size:9px;letter-spacing:.16em;text-transform:uppercase;color:#93A6C8;display:block;margin-top:2px}
.sb-sec{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:#6E86AE;padding:17px 18px 7px;font-weight:600}
/* A group heading is now the control that folds its links. Same type, same padding: the only
   additions are the chevron and a pointer. */
.sb-grp > summary{display:flex;align-items:center;gap:8px;cursor:pointer;list-style:none}
.sb-grp > summary::-webkit-details-marker{display:none}
.sb-grp > summary:hover{color:#93A6C8}
.sb-chev{width:12px;height:12px;flex:none;margin-left:auto;opacity:.75;transition:transform .15s ease}
.sb-grp[open] > summary .sb-chev{transform:rotate(90deg)}
.sb-ico{width:18px;height:18px;flex:none}
.sb a{display:flex;align-items:center;gap:10px;padding:8px 18px;font-size:13px;color:#CBD7E8;
  text-decoration:none;border-left:3px solid transparent;cursor:pointer}
.sb a:hover{background:rgba(255,255,255,.05)}
.sb a.on{background:rgba(255,255,255,.08);color:#fff;border-left-color:var(--green);font-weight:600}
.sb a .tag{margin-left:auto;font-size:9.5px;font-weight:700;background:var(--green);color:#fff;border-radius:20px;padding:1px 7px}
.sb-foot{margin-top:auto;padding:14px 14px 4px;border-top:1px solid rgba(255,255,255,.1)}
/* The identity block is a link to your own profile, so it needs to look pressable without
   becoming another nav item. It inherits .sb a, which brings a left border and nav padding
   it does not want; both are reset here. */
.sb-foot .who{display:flex;align-items:center;gap:10px;padding:7px 4px;margin-bottom:6px;
  border-left:0;border-radius:8px}
.sb-foot a.who:hover{background:rgba(255,255,255,.07)}
.sb-foot a.who:hover .nm{color:#fff}
.sb-foot a.who[aria-current="page"]{background:rgba(255,255,255,.1)}
.sb-foot .nm{font-size:12px;color:#fff;font-weight:600;line-height:1.25}
.sb-foot .rl{font-size:10px;color:#93A6C8}
/* Sign out was a single arrow glyph with no label, which nobody read as "sign out". */
.sb-out{display:flex;align-items:center;gap:8px;width:100%;background:rgba(255,255,255,.07);
  border:0;border-radius:8px;padding:9px 11px;color:#CBD7E8;font-size:12.5px;font-weight:600;
  font-family:inherit;cursor:pointer;text-align:left}
.sb-out:hover{background:rgba(255,255,255,.14);color:#fff}
/* The homepage link wears the sign-out button's clothes; it is an anchor, so it needs the
   underline taken off. It sits at the top of the rail, under the crest, so it carries its
   own padding rather than the footer's. */
.sb-top{padding:14px 14px 0}
.sb-home{text-decoration:none}

/* A scrolling list of things to tick: the programmes a person is on, and the courses a
   lecturer can monitor. Sized so the box itself says there is more below it. */
.picklist{max-height:150px;overflow-y:auto;border:1px solid var(--line);border-radius:9px;
  padding:9px 11px;background:#fff}
.picklist label{display:block;font-size:12px;padding:2px 0;color:var(--body)}
.picknone{font-size:11.5px;color:var(--faint);padding:4px 0}

/* The registration number, SPS/235/26: a fixed college prefix, then the two parts that are
   actually typed. The boxes are sized to what goes in them so the shape of the number is
   readable before anything is entered. */
.regno{display:flex;align-items:center;gap:6px}
.regno span{font-size:12.5px;font-weight:700;color:var(--faint);letter-spacing:.02em}
.regno input{width:62px;text-align:center}
.regno input:last-of-type{width:48px}


/* A lesson video on a student's week. Held to the reading column and to sixteen by nine,
   because an unstyled <video> takes whatever width it is given and this one took the lot.
   Black behind it so a frame that has not loaded is not a white flash mid-page. */
.vid{margin:22px 0 18px}
.vid video{display:block;width:100%;max-width:720px;aspect-ratio:16/9;background:#0B1226;
  border-radius:11px;border:1px solid var(--line)}

/* A video in a dialog rather than in the page. Inline, a player wide enough to watch forced
   the review page sideways out of its own column. */
.vmodal{border:0;padding:0;border-radius:14px;background:var(--navy);color:#fff;
  width:min(900px,92vw);max-width:none;box-shadow:0 30px 80px -20px rgba(6,16,40,.6)}
.vmodal::backdrop{background:rgba(6,16,40,.72)}
.vmodal video{display:block;width:100%;aspect-ratio:16/9;background:#0B1226}
.vmodal-head{display:flex;align-items:center;gap:14px;padding:14px 16px}
.vmodal-head b{display:block;font-size:13px;color:#fff}
.vmodal-head span{display:block;font-size:11px;color:#9DB2D8;margin-top:2px}
.vmodal-head .btn{margin-left:auto;flex:none}
.vmodal-foot{padding:12px 16px}
.vmodal-foot .file{color:#CBD7E8;border-color:rgba(255,255,255,.25);background:transparent}


/* ---------- the icon rail ---------- */
/* Narrowed, the sidebar keeps its icons and drops everything else. One variable carries the
   change; each rule below only decides what centres and what goes away. The control sits in
   the top bar rather than the sidebar, because it has to stay reachable at 66px and .sb
   scrolls its own overflow. */
.shell.mini{--sb:66px}
.shell.mini .sb-logo{padding:0 0 16px;justify-content:center}
.shell.mini .sb-logo div{display:none}
.shell.mini .sb-grp > summary{display:none}
.shell.mini .sb-grp + .sb-grp{margin-top:9px;padding-top:9px;border-top:1px solid rgba(255,255,255,.1)}
/* .sb a carries a 3px left border as the active marker, so the padding has to answer it on
   the right or every icon sits 3px off centre in a 66px rail. */
.shell.mini .sb a{position:relative;justify-content:center;gap:0;padding:11px 3px 11px 0}
.shell.mini .sb a .lbl{display:none}
.shell.mini .sb-ico{width:19px;height:19px}
/* An unread count has no room to be a number, so it becomes the fact that there is one. */
.shell.mini .sb a .tag{position:absolute;top:7px;right:13px;margin:0;padding:0;
  width:8px;height:8px;border-radius:50%;font-size:0;line-height:0;overflow:hidden}
.shell.mini .sb-foot{padding:12px 9px 4px}
.shell.mini .sb-foot .who{justify-content:center;padding:7px 0;gap:0}
.shell.mini .sb-foot .who > div{display:none}
.shell.mini .sb-out{justify-content:center;gap:0;padding:10px 0}
.shell.mini .sb-out .lbl{display:none}

.rail{display:none;background:none;border:1px solid var(--line);border-radius:8px;
  width:34px;height:34px;place-items:center;color:var(--faint);cursor:pointer;flex:none}
.rail:hover{color:var(--ink);background:#F4F6FB}
@media(min-width:821px){.rail{display:grid}}

.av{width:31px;height:31px;border-radius:50%;background:var(--green);color:#fff;display:grid;
  place-items:center;font-size:11.5px;font-weight:700;flex:none}
.av.b{background:var(--navy-2)}.av.g{background:#8A94A8}.av.y{background:var(--gold)}
.av.sm{width:24px;height:24px;font-size:9.5px}

.mn{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
.tb{min-height:62px;flex:none;background:#fff;border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:14px;padding:10px 26px}
.tb h1{font-size:17.5px;font-weight:700}
.tb .crumb{font-size:11.5px;color:var(--faint);margin-top:1px}
.tb .right{margin-left:auto;display:flex;align-items:center;gap:12px}
.badge{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:5px 11px;border-radius:20px;background:var(--gold-lt);color:var(--gold);white-space:nowrap}
.badge.live{background:var(--green-lt);color:var(--green-dk)}
.badge.nv{background:#E7EDF8;color:var(--navy)}
.ct{padding:22px 26px 60px;overflow-y:auto;flex:1}

.burger{display:none;background:none;border:1px solid var(--line);border-radius:8px;
  width:36px;height:36px;font-size:16px;cursor:pointer;color:var(--body)}

/* ---------- components ---------- */
.card{background:#fff;border:1px solid var(--line);border-radius:12px}
.card-h{padding:14px 18px;border-bottom:1px solid var(--line-2);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.card-h h3{font-size:14px;font-weight:700}
.card-h .sub{font-size:11.5px;color:var(--faint);margin-top:1px}
.card-b{padding:16px 18px}
.step{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--green-dk);font-weight:600;margin-bottom:9px}
/* Type values here match the approved gallery exactly; they had drifted a little.
   The centring is a client instruction and is the one deliberate difference from it:
   the gallery's tiles are left aligned. Change text-align to left to put it back. */
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px}
.kpi{background:#fff;border:1px solid var(--line);border-radius:11px;padding:15px 16px;
  text-align:center;display:flex;flex-direction:column;justify-content:center;
  /* A grid child is min-width:auto by default, so it will not shrink below its own text and
     bursts the panel sideways instead. */
  min-width:0}
.kpi .lb{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);font-weight:600}
.kpi .vl{font-size:23px;font-weight:750;letter-spacing:-.035em;margin:7px 0 4px;font-variant-numeric:tabular-nums}
.kpi .vl small{font-size:12.5px;font-weight:600;color:var(--faint);letter-spacing:0}
.kpi .mt{font-size:11px;color:var(--body)}
/* Several tiles put a bar or a pill in .mt, which was a flex row aligned to the left. */
.kpi .mt,.kpi .bar{margin-left:auto;margin-right:auto}
.kpi .mt{display:flex;align-items:center;justify-content:center;gap:5px;flex-wrap:wrap}
.up{color:var(--green-dk);font-weight:600}
.grid2{display:grid;grid-template-columns:1fr minmax(0,330px);gap:14px}
.grid2>*{min-width:0}
/* Four tiles across is a page-width layout. In the 330px side column they go two by two. */
.grid2 .kpis{grid-template-columns:repeat(2,1fr);gap:10px}
.grid2 .kpi{padding:13px 11px}
.grid2 .kpi .vl{font-size:20px}
.grid2 .kpi .lb{letter-spacing:.05em}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.stack>*+*{margin-top:14px}

table{width:100%;border-collapse:collapse;font-size:12.5px}
th{text-align:left;font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);
  font-weight:700;padding:9px 16px;border-bottom:1px solid var(--line-2);background:#FAFBFE}
td{padding:9px 16px;border-bottom:1px solid var(--line-2);color:var(--body);vertical-align:middle}
tr:last-child td{border-bottom:0}
td.nm{color:var(--ink);font-weight:650}
.num{text-align:right;font-variant-numeric:tabular-nums}
/* A count column. Centred rather than right aligned, because a heading like "Sat a quiz"
   wraps onto two lines and a right aligned heading then reads as centred while the figure
   below it does not. Both centred, and they sit in one line down the page. */
.ctr{text-align:center;font-variant-numeric:tabular-nums}
th.ctr{text-align:center}
.who{display:flex;align-items:center;gap:9px;white-space:nowrap}
.mut{color:var(--faint)}
.tbl-wrap{overflow-x:auto}

.pill{display:inline-flex;align-items:center;font-size:10px;font-weight:700;padding:3px 8px;border-radius:20px;white-space:nowrap}
.pill.ok{background:var(--green-lt);color:var(--green-dk)}
.pill.nu{background:#EEF2F9;color:#5A6B8C}
.pill.ai{background:var(--gold-lt);color:var(--gold)}
.pill.nv{background:#E7EDF8;color:var(--navy)}
.pill.rd{background:var(--red-lt);color:var(--red)}

.pg-sum{margin:0;font-size:13px;line-height:1.65;color:var(--body)}

/* When a teaching week begins, beside the week it belongs to. Quiet, because it is
   context for the title rather than a thing to read first. */
.wkdate{display:block;margin-top:2px;font-size:10.5px;color:var(--faint);font-weight:500}

/* The college's standing, beside its name on every dashboard. Gold on the gold wash so
   it reads as a mark rather than as another line of the breadcrumb. */
.acc{display:inline-block;margin-left:5px;padding:1px 7px;border-radius:20px;
  background:var(--gold-lt);color:var(--gold);font-size:9.5px;font-weight:700;
  letter-spacing:.07em;vertical-align:1px;white-space:nowrap}

.bar{height:7px;border-radius:4px;background:var(--line-2);overflow:hidden;min-width:70px}
.bar i{display:block;height:100%;background:var(--navy-2);border-radius:4px}
.bar i.g{background:var(--green)}
.bar i.y{background:var(--gold-br)}

.btn{display:inline-flex;align-items:center;gap:8px;background:var(--green);color:#fff;border:0;
  border-radius:9px;padding:11px 20px;font-size:13.5px;font-weight:700;
  font-family:'Space Grotesk',sans-serif;cursor:pointer;text-decoration:none}
.btn:disabled,.btn.off{background:#C6CEDA;cursor:not-allowed}
.btn.o{background:#fff;color:var(--navy);border:1px solid var(--line)}
.btn.n{background:var(--navy);color:#fff}
.btn.r{background:var(--red);color:#fff}
.btn.sm{padding:8px 14px;font-size:12.5px}
.btn.xs{padding:6px 11px;font-size:11.5px;border-radius:7px}
/* An outline button that removes something. Red is the console's colour for failure and for
   damage, which is exactly what this is: unlike the brand red on the public site, it belongs
   here. Quiet until you are about to press it. */
.btn.o.danger{color:var(--red);border-color:#F0C9C6}
.btn.o.danger:hover{background:var(--red);color:#fff;border-color:var(--red)}
/* The per-message version. A row of buttons down a conversation would shout; this reads as a
   small word until it is wanted. */
.lnk-danger{background:none;border:0;padding:2px 4px;font-family:inherit;font-size:11px;
  font-weight:600;color:var(--faint);cursor:pointer;border-radius:5px}
.lnk-danger:hover{color:var(--red);background:var(--red-lt)}

.genrow{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--line-2)}
.genrow:last-child{border-bottom:0}
.genrow .ti{width:29px;height:29px;border-radius:8px;display:grid;place-items:center;flex:none;font-size:13px}
.genrow .ti.done{background:var(--green-lt);color:var(--green-dk)}
.genrow .ti.now{background:var(--gold-lt);color:var(--gold)}
.genrow .ti.wait{background:var(--line-2);color:var(--faint)}
.genrow b{display:block;font-size:12.5px;font-weight:700}
.genrow span{display:block;font-size:11px;color:var(--faint);margin-top:1px}
.genrow .rt{margin-left:auto;font-size:11px;font-weight:700;color:var(--faint);white-space:nowrap}

.hint{font-size:11.5px;color:var(--faint);margin-top:10px;line-height:1.55}
.sect{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);font-weight:700;margin:0 0 9px}
.empty{text-align:center;padding:38px 20px;color:var(--faint);font-size:13px}
.empty h4{font-size:15px;color:var(--ink);margin-bottom:6px}

.note{border-radius:10px;padding:13px 15px;font-size:12.5px;line-height:1.6;margin-bottom:14px}
.note.ok{background:var(--green-lt);border:1px solid #BFE3BA;color:#256B21}
.note.err{background:var(--red-lt);border:1px solid #F0C4C1;color:#8C2F28}
.note.ai{background:var(--gold-lt);border:1px solid #E9DA8E;color:#6E5A00}
.note.nv{background:#EEF3FB;border:1px solid #CFDCF1;color:var(--navy-ink)}

label.fld{display:block;font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);
  font-weight:700;margin-bottom:5px;line-height:1.35}
/* Every text-like control, password and file included. Leaving password out of this list is
   why the API key field rendered at the browser's default width next to full-width siblings. */
input[type=text],input[type=email],input[type=number],input[type=password],input[type=search],
input[type=tel],input[type=url],input[type=date],input[type=datetime-local],input[type=file],
select,textarea{width:100%;border:1px solid var(--line);border-radius:9px;padding:10px 12px;
  font-size:13px;font-family:inherit;color:var(--ink);background:#fff}
input[type=file]{padding:8px 12px}

/* A credential or a short value looks wrong stretched across a wide card. */
.w-md{max-width:440px}
textarea{resize:vertical;min-height:70px}
/* A row of form fields.
   Grid rather than flex, because these cells carry hint text of wildly different lengths and
   a flex row bottom-aligned them: every label and input in the row sat at a different height.
   Grid columns are equal width and start at the same top line, so the labels align, the inputs
   align, and hints simply hang below at whatever length they are.
   Each cell then pins its own input to the same baseline: the label block is given the height
   of two lines and its text sits at the bottom of it, so a label that wraps and one that does
   not still leave their inputs level. */
.row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px 14px;align-items:start;
  /* Cards run the full width of a large monitor. A form that stretched with them would put a
     540px box around a two-digit number, so the fields stop at a readable measure. */
  max-width:1080px}
.row>*{min-width:0}
.row>* label.fld{min-height:26px;display:flex;align-items:flex-end;margin-bottom:6px}
.row .hint{margin-top:6px}
.err-txt{color:var(--red);font-size:11.5px;margin-top:4px}

/* ---------- generator ---------- */
.progs{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:22px}
.pg{border:1px solid var(--line);border-radius:12px;padding:15px 16px;background:#fff;cursor:pointer;
  display:block;text-decoration:none;transition:border-color .12s,box-shadow .12s}
.pg:hover{border-color:var(--navy-2)}
.pg.on{border-color:var(--green);box-shadow:0 0 0 3px var(--green-lt)}
.pg h4{font-size:14.5px;font-weight:800;margin-bottom:3px}
.pg .aw{font-size:11px;color:var(--faint)}
.pg .n{margin-top:10px;font-size:11.5px;color:var(--body);font-weight:600}
.pg .n b{color:var(--green-dk)}
tr.sel td{background:var(--green-lt)}
tr.has{cursor:pointer}
tr.has:hover td{background:#F4F9F3}
td.pick{color:var(--faint);font-weight:700;font-size:11px;text-align:right;white-space:nowrap}
tr.has:hover td.pick{color:var(--green-dk)}

/* display:block matters: the upload zone is a <label> so that clicking anywhere in it opens
   the file picker, and a label is inline by default. Without this its dashed border broke
   across lines into fragments instead of drawing one rectangle. */
.drop{display:block;border:2px dashed #C3D0E4;border-radius:14px;
  background:linear-gradient(180deg,#FBFCFE,#F4F7FC);
  padding:26px;text-align:center;transition:border-color .12s,background .12s;cursor:pointer}
.drop:hover{border-color:var(--navy-2)}
.drop.over{border-color:var(--green);background:var(--green-lt)}
.drop.has{border-style:solid;border-color:var(--green);background:var(--green-lt);cursor:default}
.drop .ti{width:50px;height:50px;border-radius:14px;background:var(--navy);color:#fff;
  display:grid;place-items:center;margin:0 auto 12px;font-size:20px}
.drop.has .ti{background:var(--green)}
.drop h3{font-size:16px;font-weight:800;margin-bottom:5px}
.drop p{margin:0 0 14px;font-size:12.5px;color:var(--body)}
.drop .fine{margin-top:11px;font-size:10.5px;color:var(--faint)}
.drop.busy{opacity:.6;pointer-events:none}

/* The second chooser, shown only when a guide was refused for naming another course. */
.anyway{margin-top:12px;padding:13px 15px;border:1px solid var(--line);border-radius:12px;
  background:var(--wash);text-align:center}
.anyway p{margin:0 0 10px;font-size:12px;color:var(--body);line-height:1.6}

/* The action bar under the generator.
   It used to bottom-align its cells, and because a label, a select, a stepper, a checkbox and
   a button are all different heights, every label sat at a different level and no two controls
   shared a baseline. Each cell is now a column: a label block the height of two lines with its
   text at the bottom, then a control area of one fixed height with the control centred in it.
   Labels line up because the label blocks match, controls line up because the control rows do. */
.run{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;padding:16px 18px;
  border-top:1px solid var(--line-2);background:#FAFBFE;border-radius:0 0 12px 12px}
.run .f{flex:0 0 auto;display:flex;flex-direction:column;min-width:0}
.run .f label.fld{min-height:26px;display:flex;align-items:flex-end;margin-bottom:6px}
.run .f .ctl{min-height:40px;display:flex;align-items:center;gap:9px}
.run .f .val{font-size:14px;font-weight:750;color:var(--ink)}
.run .f select{width:auto;min-width:170px}
/* The button has no label above it, so it is pushed down to sit on the control line. */
.run .go{align-self:flex-start;margin-top:32px}
.run .check{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--body);
  white-space:nowrap;cursor:pointer}
.run .check input{width:auto;margin:0}
@media(max-width:700px){
  .run{gap:12px}
  .run .f{flex:1 1 100%}
  .run .go{margin-top:4px;width:100%;justify-content:center}
  .run .f select{width:100%}
}
.wk{display:flex;align-items:center;border:1px solid var(--line);border-radius:9px;overflow:hidden;background:#fff}
.wk button{border:0;background:#fff;width:34px;height:38px;font-size:17px;color:var(--navy);cursor:pointer}
.wk button:hover{background:var(--line-2)}
.wk input{width:52px;text-align:center;font-size:15px;font-weight:750;border:0;padding:0;
  font-variant-numeric:tabular-nums;-moz-appearance:textfield}
.wk input::-webkit-outer-spin-button,.wk input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}

.aihero{border-radius:12px;padding:20px 22px;color:#fff;position:relative;overflow:hidden;
  background:linear-gradient(135deg,#253D79,#16265E 60%,#101A38);margin-bottom:16px}
.aihero .lb{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold-br);font-weight:700}
.aihero h3{font-size:20px;font-weight:800;margin:7px 0 4px}
.aihero p{margin:0;font-size:12.5px;color:rgba(255,255,255,.78)}
.pbar{height:7px;border-radius:4px;background:rgba(255,255,255,.16);margin-top:15px;overflow:hidden}
.pbar i{display:block;height:100%;border-radius:4px;
  background:linear-gradient(90deg,var(--gold-br),#9BD48F);transition:width .4s ease}

.wkr{border-bottom:1px solid var(--line-2)}
.wkr:last-child{border-bottom:0}
.wkh{display:flex;align-items:center;gap:13px;padding:12px 18px;cursor:pointer;width:100%;
  background:none;border:0;text-align:left;font-family:inherit}
.wkh:hover{background:#FAFBFE}
.wkh .num{width:30px;height:30px;border-radius:8px;background:var(--navy);color:#fff;flex:none;
  display:grid;place-items:center;font-size:12px;font-weight:800}
.wkh b{font-size:13.5px;font-weight:700;display:block;color:var(--ink)}
.wkh span{font-size:11px;color:var(--faint)}
.wkb{padding:2px 18px 20px 61px}
.wkb h5{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);
  font-weight:700;margin:16px 0 8px}
.wkb ul{margin:0;padding-left:18px;color:var(--body);font-size:12.5px}
.wkb li{margin-bottom:5px}
details.wkr>summary{list-style:none}
details.wkr>summary::-webkit-details-marker{display:none}

/* No measure. A reading column left the right of the card empty on a wide screen and the
   college asked twice for the full width, so the lesson runs to the edge of its card and the
   card's own padding is the only margin. */
.lesson{font-size:13.5px;color:var(--body);line-height:1.75;max-width:none}
.lesson p{margin:0 0 13px}
.lesson b{color:var(--ink)}

.q{border:1px solid var(--line);border-radius:10px;padding:13px 15px;margin-bottom:9px;background:#fff}
.q .qn{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);font-weight:700}
.q h6{font-size:13px;font-weight:700;margin:5px 0 10px;font-family:'IBM Plex Sans',sans-serif}
.q .an{display:flex;gap:9px;align-items:flex-start;border:1px solid var(--line);border-radius:8px;
  padding:9px 11px;font-size:12.5px;margin-bottom:6px;color:var(--body);cursor:pointer}
.q .an:hover{border-color:var(--navy-2)}
.q .an.ok{border-color:var(--green);background:var(--green-lt);color:var(--ink);font-weight:600}
.q .an.bad{border-color:var(--red);background:var(--red-lt);color:#8C2F28}
.q .an input{width:auto;margin:2px 0 0}
.q .why{font-size:11.5px;color:var(--faint);margin-top:7px;font-style:italic}

.dl{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px;align-items:center}
.dl a.file{display:inline-flex;align-items:center;gap:8px;text-decoration:none;background:#fff;
  border:1px solid var(--line);border-radius:9px;padding:10px 15px;font-size:12.5px;
  font-weight:650;color:var(--navy)}
.dl a.file:hover{border-color:var(--navy-2)}
audio{height:38px;max-width:100%}
/* Pushes one item of a .dl row to the far end, so the player is never beside a link. */
.dl .push{margin-left:auto}
@media (max-width:720px){.dl .push{margin-left:0;width:100%}}


/* ---------- the week's narration ---------- */
/* Sticky against .ct, the page's own scroller, so the player holds its place while the
   lesson goes by under it. Stuck, it sheds everything but the controls. */
.wkp-sentinel{height:1px}
.wkp{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:13px;flex-wrap:wrap;
  background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 16px;
  transition:padding .16s ease,border-radius .16s ease,box-shadow .16s ease}
.wkp.stuck{border-radius:0 0 12px 12px;padding:8px 14px;
  box-shadow:0 12px 24px -18px rgba(16,26,56,.65)}
.wkp.gone{display:none}

.wkp-play{flex:none;width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  background:var(--navy);color:#fff;display:inline-flex;align-items:center;justify-content:center;
  transition:width .16s ease,height .16s ease,background .12s ease}
.wkp-play:hover{background:var(--navy-2)}
.wkp-play svg{width:18px;height:18px}
.wkp.stuck .wkp-play{width:34px;height:34px}
.wkp.stuck .wkp-play svg{width:15px;height:15px}

.wkp-meta{min-width:150px}
.wkp-meta b{display:block;font-size:13px;font-weight:700;color:var(--ink);line-height:1.3}
.wkp-meta span{display:block;font-size:11.5px;color:var(--faint);line-height:1.4}
.wkp.stuck .wkp-meta b{font-size:12.5px}

/* The thumb is drawn by the browser; the filled part of the track is painted by the script. */
.wkp-seek{flex:1 1 200px;-webkit-appearance:none;appearance:none;height:6px;border-radius:3px;
  background:var(--line-2);cursor:pointer;outline-offset:3px}
.wkp-seek::-webkit-slider-thumb{-webkit-appearance:none;width:15px;height:15px;border-radius:50%;
  background:var(--navy);border:2.5px solid #fff;box-shadow:0 0 0 1px var(--line)}
.wkp-seek::-moz-range-thumb{width:15px;height:15px;border:2.5px solid #fff;border-radius:50%;
  background:var(--navy);box-shadow:0 0 0 1px var(--line)}

.wkp-time{font-size:11.5px;color:var(--body);font-variant-numeric:tabular-nums;min-width:74px;
  text-align:right}

.wkp-dl,.wkp-hide{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
  background:#fff;border-radius:9px;color:var(--navy);cursor:pointer;text-decoration:none;
  font-size:12px;font-weight:650;padding:8px 12px}
.wkp-dl:hover,.wkp-hide:hover{border-color:var(--navy-2)}
.wkp-dl svg{width:15px;height:15px}
.wkp-hide{padding:8px;color:var(--faint)}
.wkp-hide svg{width:15px;height:15px}
/* Nothing to put away until it is in the way. */
.wkp .wkp-hide{display:none}
.wkp.stuck .wkp-hide{display:inline-flex}

.wkp-voices{display:flex;align-items:center;gap:8px;flex-wrap:wrap;width:100%;
  border-top:1px solid var(--line-2);margin-top:3px;padding-top:11px}
.wkp.stuck .wkp-voices{display:none}
.wkp-vl{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);
  font-weight:700}
.wkp-voice{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
  border-radius:999px;padding:6px 13px;font-size:12px;font-weight:650;color:var(--body);
  cursor:pointer}
.wkp-voice:hover{border-color:var(--navy-2)}
.wkp-voice input{position:absolute;opacity:0;width:0;height:0}
.wkp-voice.on{background:var(--green-lt);border-color:var(--green);color:var(--ink)}
.wkp-voice em{font-style:normal;font-size:10.5px;color:var(--faint)}
.wkp-vn{font-size:11px;color:var(--faint);margin-left:auto}

@media (max-width:760px){
  .wkp{gap:10px;padding:12px}
  .wkp-meta{min-width:0;flex:1 1 auto}
  .wkp-seek{flex:1 1 100%;order:5}
  .wkp-time{order:6;min-width:0}
  .wkp-vn{display:none}
}

/* ---------- student ---------- */
.hero{border-radius:12px;padding:22px 24px;color:#fff;margin-bottom:16px;
  background:linear-gradient(135deg,#253D79,#16265E 60%,#101A38)}
.hero h2{font-size:22px;font-weight:800;margin-bottom:5px}
.hero p{margin:0;font-size:13px;color:rgba(255,255,255,.8)}
.hero .btn{margin-top:16px}
.weekmap{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.wkcard{border:1px solid var(--line);border-radius:11px;padding:13px 14px;background:#fff;
  text-decoration:none;display:block}
.wkcard:hover{border-color:var(--navy-2)}
.wkcard .n{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);font-weight:700}
.wkcard b{display:block;font-size:13px;font-weight:700;margin:5px 0 9px;color:var(--ink);line-height:1.35}
.wkcard.done{border-color:var(--green);background:var(--green-lt)}
.wkcard.now{border-color:var(--navy-2);box-shadow:0 0 0 3px #E7EDF8}
.wkcard.locked{opacity:.55}

/* The first version of the public site lived here, unscoped. It was replaced by the
   gallery's rules further down, which are scoped under .web, and every selector in it was
   then either unused or superseded. One of them, `.wnav a`, was also more specific than
   `.btn` and so repainted the Student login button's text in body grey instead of white.
   Removed rather than overridden: two rules fighting over a colour is the bug, not the
   colour. */

/* ---------- responsive ---------- */
@media(max-width:1080px){
  .grid2{grid-template-columns:1fr}
  .kpis{grid-template-columns:repeat(2,1fr)}
  .progs,.grid-3{grid-template-columns:1fr}
}
@media(max-width:820px){
  .burger{display:grid;place-items:center}
  /* The drawer is already a hidden sidebar. Narrowing it as well helps nobody. */
  .shell.mini{--sb:222px}
  .sb-grp > summary{padding-top:15px;padding-bottom:11px}
  .sb{position:fixed;inset:0 auto 0 0;z-index:50;transform:translateX(-100%);
    transition:transform .2s ease;box-shadow:0 0 60px rgba(6,16,40,.4)}
  .shell.open .sb{transform:none}
  .shell.open::after{content:"";position:fixed;inset:0;background:rgba(6,16,40,.45);z-index:40}
  .ct{padding:16px 16px 50px}
  .tb{padding:10px 16px}
  .whero{padding:52px 20px}
  .whero h1{font-size:31px}
  .wsec{padding:38px 20px}
  .wkb{padding-left:18px}
}
@media(max-width:560px){
  .kpis{grid-template-columns:1fr 1fr;gap:9px}
  .kpi .vl{font-size:19px}
  .run{gap:12px}
  .run>*{flex:1 1 100%}
}

/* ================= public site — the approved gallery screens =============================
   01 Home and 02 Programme detail, lifted from the signed-off mockup gallery.

   Everything is scoped under .web so the gallery's own class names (.hero, .pg, .progs, .ti,
   .mt, .wnav, .wsec, .wfoot) can be reproduced verbatim without touching the console screens
   above, several of which already own those names. The earlier text-described public rules
   are left where they are for the same reason; every one of them is overridden here for
   anything inside .web.

   The mockup is a fixed 1240px canvas with a 44px gutter. --gut keeps that gutter, and on a
   wider screen centres the same 1152px content column, so the proportions the client approved
   survive at any viewport instead of stretching. */
/* The red from the college's own logo, which sets "of Paramedical Studies" in it beneath the
   name. Declared on .web so it cannot reach the console, and deliberately NOT --red: that
   token is semantic and means failure at all five of its call sites ("Below pass mark",
   "Generation failed", a wrong quiz answer). One token for both would make the college's own
   colour mean a mistake. */
.web{--gut:max(16px,calc((100% - 1152px) / 2));
  --brand-red:#D42A22; --brand-red-dk:#B8241D;
  background:#fff;min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden}
.web main{flex:1;padding-bottom:34px}
.web svg{display:block}
.web .ic{width:17px;height:17px;flex:none;stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.web .ic.sm{width:14px;height:14px}
.web .ic.lg{width:20px;height:20px}

/* ---- nav ---- */
.web .wnav{min-height:70px;display:flex;align-items:center;gap:22px;padding:0 var(--gut);
  border-bottom:1px solid var(--line);background:#fff;position:relative;z-index:5;max-width:none;margin:0}
.web .wlogo{display:flex;align-items:center;gap:11px;text-decoration:none;flex:none}
.web .wlogo img{height:38px;width:auto;display:block}
.web .wlogo .wm{font-family:'Space Grotesk',sans-serif;line-height:1.1}
.web .wlogo .wm b{display:block;font-size:14px;font-weight:800;letter-spacing:-.015em;color:var(--navy)}
/* The one place the brand red goes, matching the logo. It also repairs a contrast failure:
   the old --faint on white was 3.05:1, below the 4.5:1 this size needs. The red is 5.06:1.
   The hero and programme-head kickers stay gold for the same reason in reverse — red on the
   navy ground behind them is 2.82:1 and would be close to unreadable. */
.web .wlogo .wm span{display:block;font-size:8.5px;letter-spacing:.155em;text-transform:uppercase;
  color:var(--brand-red);font-weight:700;margin-top:3px}
.web .wnav nav{display:flex;gap:2px;margin-left:14px;flex-wrap:wrap}
.web .wnav nav a{font-size:13px;color:var(--body);text-decoration:none;font-weight:500;
  padding:7px 11px;border-radius:7px}
.web .wnav nav a:hover{background:var(--line-2);color:var(--navy)}
.web .wnav nav a.on{color:var(--navy);font-weight:700;background:#EAEFF9}
.web .wnav .right{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.web .wnav .tel{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--body);
  font-weight:600;margin-right:6px;font-variant-numeric:tabular-nums;text-decoration:none;white-space:nowrap}
.web .wnav .tel .ic{color:var(--green-dk)}
.web .wnav .btn{padding:9px 16px;font-size:12.5px;border-radius:8px;gap:7px}
/* The student login is the one thing a visitor comes back to this site to do, so it carries
   the brand red. :not(.o) keeps the outlined faculty login beside it white — without it this
   rule outranks .btn.o and would fill both.
   It is also a legibility fix: white on the green is 2.69:1, below the 4.5:1 this size needs.
   White on the red is 5.06:1. */
.web .wnav .btn:not(.o){background:var(--brand-red)}
.web .wnav .btn:not(.o):hover{background:var(--brand-red-dk)}

/* ---- hero ---- */
.web .hero{position:relative;min-height:418px;padding:34px var(--gut) 24px;color:#fff;
  display:flex;flex-direction:column;margin:0;border-radius:0;background:var(--navy-ink)}
.web .hero-bg{position:absolute;inset:0;overflow:hidden;background:var(--navy-ink)}
.web .hero-bg svg{position:absolute;inset:0;width:100%;height:100%}
.web .hero .hl{position:relative;z-index:2;display:flex;flex-direction:column;flex:1;max-width:660px}
.web .eyebrow2{display:inline-flex;align-items:center;gap:8px;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;font-weight:700;color:var(--gold-br);margin-bottom:14px}
.web .eyebrow2 i{width:22px;height:2px;background:var(--gold-br);display:block;border-radius:1px;flex:none}
.web .hero h1{font-size:42px;font-weight:800;letter-spacing:-.035em;line-height:1.05;margin:0 0 14px;
  max-width:16ch;text-shadow:0 2px 24px rgba(6,16,40,.45)}
.web .hero h1 em{font-style:normal;color:var(--gold-br)}
.web .hero p.lead{font-size:15px;margin:0 0 22px;max-width:50ch;color:rgba(255,255,255,.86);line-height:1.55}
.web .hero .acts{display:flex;gap:11px;align-items:center}
.web .hero .btn{padding:12px 22px;font-size:13.5px;border-radius:9px;margin-top:0}
.web .hero .btn.o{background:rgba(255,255,255,.1);color:#fff;border:1px solid rgba(255,255,255,.3)}
.web .hero .btn.o:hover{background:rgba(255,255,255,.18)}
.web .trust{margin-top:auto;padding-top:30px;display:grid;grid-template-columns:repeat(4,1fr);
  gap:10px;max-width:700px}
.web .trust .tc{display:flex;align-items:center;gap:9px;padding:10px 11px;border-radius:11px;
  background:rgba(10,22,48,.5);border:1px solid rgba(255,255,255,.15)}
.web .trust .ic{width:18px;height:18px;color:var(--gold-br);flex:none}
.web .trust b{display:block;font-size:13px;font-weight:800;letter-spacing:-.01em;line-height:1.1;white-space:nowrap}
.web .trust span{display:block;font-size:10.5px;color:rgba(255,255,255,.7);line-height:1.2;margin-top:2px}

/* ---- sections ---- */
.web .wsec{padding:26px var(--gut) 0;max-width:none;margin:0}
.web .wsec .hd{display:flex;align-items:flex-end;justify-content:space-between;gap:14px;
  margin-bottom:14px;flex-wrap:wrap}
.web .wsec h2{margin:0;font-size:21px;font-weight:800;letter-spacing:-.025em}
.web .wsec h2 small{display:block;font-size:12.5px;color:var(--body);font-weight:500;
  letter-spacing:0;margin-top:3px;max-width:70ch}
.web .more{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:700;
  color:var(--green-dk);white-space:nowrap;text-decoration:none}
.web .more:hover{text-decoration:underline}
.web .prose{max-width:74ch}
.web .prose p{margin:0 0 12px;font-size:13.5px;color:var(--body);line-height:1.68}
.web .prose p:last-child{margin-bottom:0}
.web .prose a{color:var(--green-dk);font-weight:600}
.web .note{margin:12px 0 0;font-size:11.5px;color:var(--faint);line-height:1.6;max-width:74ch}
.web .empty{border:1px dashed var(--line);border-radius:12px;padding:26px 20px;text-align:center;
  color:var(--body);font-size:12.5px;background:var(--wash)}
.web .empty h4{font-size:14px;font-weight:800;color:var(--ink);margin:0 0 5px}

/* ---- programme cards ---- */
.web .progs{display:grid;grid-template-columns:repeat(auto-fit,minmax(228px,1fr));gap:12px;margin:0}
.web .progs.three{grid-template-columns:repeat(auto-fit,minmax(264px,1fr))}
.web .pg{border:1px solid var(--line);border-radius:12px;padding:15px 16px;background:#fff;
  position:relative;overflow:hidden;display:block;text-decoration:none;color:inherit;cursor:auto;
  box-shadow:none;transition:border-color .12s,box-shadow .12s}
.web a.pg{cursor:pointer}
.web a.pg:hover{border-color:var(--green);box-shadow:0 0 0 3px var(--green-lt)}
.web .pg .ti{width:34px;height:34px;border-radius:9px;background:var(--green-lt);color:var(--green-dk);
  display:grid;place-items:center;margin:0 0 11px}
.web .pg h4{margin:0 0 4px;font-size:14px;font-weight:800;letter-spacing:-.015em}
.web .pg p{margin:0;font-size:11.5px;color:var(--body);line-height:1.45}
.web .pg .mt{margin-top:10px;display:flex;gap:6px;align-items:center;font-size:10.5px;
  color:var(--faint);font-weight:600}
.web .pg.hi{border-color:var(--green);box-shadow:0 0 0 3px var(--green-lt)}

/* Programme card picture. The card keeps its padding, so the photograph is pulled out to
 the card edges with a negative margin rather than the card losing its inset everywhere.
 A fixed 3:2 box keeps the grid even whatever shape the college uploads. */
.web .pg .pic{display:block;margin:-15px -16px 12px;aspect-ratio:3/2;overflow:hidden;background:var(--green-lt)}
.web .pg .pic img{width:100%;height:100%;object-fit:cover;display:block}
.web .pg .pic + .ti{display:none}


/* ---- programme detail head ---- */
.web .phead{position:relative;padding:30px var(--gut) 28px;color:#fff;overflow:hidden;background:
    radial-gradient(60% 90% at 0% 0%,rgba(49,80,154,.7),transparent 60%),
    radial-gradient(45% 85% at 100% 100%,rgba(79,178,72,.42),transparent 62%),
    linear-gradient(160deg,#16265E 0%,#253D79 54%,#141F42 100%)}
.web .phead > div{position:relative;display:flex;align-items:flex-end;gap:30px;flex-wrap:wrap}
.web .phead .eyebrow2{margin-bottom:8px}
.web .phead h1{margin:0;font-size:33px;font-weight:800;letter-spacing:-.03em;line-height:1.06}
.web .phead p{margin:9px 0 0;font-size:13.5px;color:rgba(255,255,255,.8);line-height:1.5;max-width:72ch}

/* ---- the course grid, in the slot the mockup gave the week cards ---- */
.web .sem+.sem{margin-top:20px}
.web .semh{display:flex;align-items:baseline;gap:9px;margin:0 0 10px;font-size:11px;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;color:var(--navy)}
.web .semh span{font-size:11px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--faint)}
.web .wk10{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:9px}
.web .wkc{border:1px solid var(--line);border-radius:10px;padding:11px 12px;background:#fff}
.web .wkc .n{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);
  font-weight:700;font-family:'IBM Plex Mono',ui-monospace,monospace}
.web .wkc h5{margin:5px 0 0;font-size:12px;font-weight:700;letter-spacing:-.01em;line-height:1.3}
.web .wkc .pill{margin-top:8px}
.web .wkc.hi{background:var(--green-lt);border-color:#BFE3BA}

/* ---- closing band ---- */
.web .cta-band{border:1px solid var(--line);border-radius:13px;padding:18px 22px;display:flex;
  align-items:center;gap:26px;flex-wrap:wrap;background:linear-gradient(120deg,#F7FBF6,#F4F7FC)}
.web .cta-band h3{margin:0 0 5px;font-size:17px;font-weight:800;letter-spacing:-.025em}
.web .cta-band p{margin:0;font-size:12px;color:var(--body);line-height:1.5;max-width:64ch}
.web .acts2{display:flex;gap:9px;margin-left:auto;flex-wrap:wrap}
.web .btn.o2{background:#fff;color:var(--navy);border:1px solid var(--line)}

/* ---- footer ---- */
.web .wfoot{background:var(--navy-ink);color:#9FB2CE;padding:20px var(--gut);display:flex;
  align-items:center;gap:20px;font-size:11.5px;flex-wrap:wrap;max-width:none;margin:0}
.web .wfoot .in{display:contents}
.web .wfoot img{height:30px;width:auto;background:#fff;border-radius:6px;padding:3px}
.web .wfoot b{color:#fff;font-size:12px;display:inline;margin:0}
.web .wfoot .sp{margin-left:auto;display:flex;gap:22px;flex-wrap:wrap}
.web .wfoot a{color:#CBD7E8;text-decoration:none}
.web .wfoot a:hover{color:#fff;text-decoration:underline}

/* ---- the mockup is desktop only; these are the widths it never showed ---- */
@media(max-width:1000px){
  .web .hero h1{font-size:35px}
  .web .trust{grid-template-columns:repeat(2,1fr);max-width:540px}
}
@media(max-width:820px){
  .web{--gut:20px}
  .web .wnav{min-height:0;padding-top:12px;padding-bottom:12px;flex-wrap:wrap;gap:10px}
  .web .wnav nav{order:3;width:100%;margin-left:-11px}
  .web .wnav .right{margin-left:auto}
  .web .hero{min-height:0;padding-top:28px;padding-bottom:26px}
  .web .hero h1{font-size:30px;max-width:none}
  .web .hero p.lead{font-size:14px;max-width:none}
  .web .trust{margin-top:26px;padding-top:0;max-width:none}
  .web .phead h1{font-size:26px}
  .web .acts2{margin-left:0;width:100%}
}
@media(max-width:560px){
  .web{--gut:16px}
  .web .wlogo img{height:32px}
  .web .wnav nav{gap:0}
  .web .wnav nav a{padding:7px 8px;font-size:12.5px}
  .web .wnav .right{width:100%;gap:8px}
  .web .wnav .tel{width:100%;margin-right:0}
  .web .wnav .btn{flex:1 1 0;min-width:0;justify-content:center;text-align:center;padding:9px 10px}
  .web .hero{padding-top:24px}
  .web .hero h1{font-size:25px}
  .web .hero .acts{flex-wrap:wrap;gap:9px}
  .web .hero .acts .btn{flex:1 1 100%;justify-content:center}
  .web .trust{grid-template-columns:1fr;gap:8px}
  .web .trust b{white-space:normal}
  .web .progs,.web .progs.three,.web .wk10{grid-template-columns:1fr}
  .web .wsec h2{font-size:18px}
  .web .phead h1{font-size:22px}
  .web .cta-band{padding:16px}
  .web .acts2 .btn{flex:1 1 100%;justify-content:center}
  .web .wfoot{flex-direction:column;align-items:flex-start;gap:13px}
  .web .wfoot .sp{margin-left:0;gap:14px}
}


/* ---------- pagination ---------- */
.pager{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.pager-sum{font-size:11.5px;color:var(--faint)}
.pager-links{margin-left:auto;display:flex;gap:5px;flex-wrap:wrap}
.pg-btn{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;
  padding:0 10px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--navy);
  font-size:12px;font-weight:650;text-decoration:none}
.pg-btn:hover{border-color:var(--navy-2)}
.pg-btn.on{background:var(--navy);border-color:var(--navy);color:#fff}
.pg-btn.off{color:var(--faint);background:var(--wash);cursor:not-allowed}
.pg-gap{color:var(--faint);padding:0 3px;align-self:center;font-size:12px}

/* A stray icon with no width must never be able to take over a page again. */
.ct svg:not([width]):not([viewBox]){max-width:24px;max-height:24px}

/* Public site: long course titles and programme names must never push the page sideways. */
.web .wkc h5,.web .pg h4,.web .pg p,.web .phead h1,.web .hero h1,.web .cta-band h3{overflow-wrap:anywhere}
.web .wnav .btn{white-space:normal;text-align:center}


/* ---------- viewing as someone else ---------- */
.viewas{position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  background:var(--gold-br);color:#3D3200;padding:9px 20px;
  border-bottom:1px solid rgba(0,0,0,.14)}
.viewas b{font-size:12.5px;font-weight:750;display:block}
.viewas span{font-size:11.5px;opacity:.8;display:block}
.viewas form{margin-left:auto}
.viewas button{background:#3D3200;color:var(--gold-br);border:0;border-radius:8px;
  padding:8px 14px;font-size:12px;font-weight:700;font-family:inherit;cursor:pointer}
.viewas button:hover{background:#241D00}
/* The shell is a fixed viewport height, so the banner has to come out of it. */
.shell.has-banner{height:calc(100vh - 46px);height:calc(100dvh - 46px)}
@media(max-width:560px){
  .viewas{padding:8px 14px}
  .viewas form{margin-left:0;width:100%}
  .viewas button{width:100%}
  .shell.has-banner{height:auto;min-height:60vh}
}


/* ---------- checkbox sets ---------- */
.checkset{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:6px 14px;
  max-width:1080px;border:1px solid var(--line);border-radius:9px;padding:11px 13px;background:#fff}
.check{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--body);cursor:pointer}
.check input{width:auto;margin:0;flex:none}


/* ---------- profile photographs ---------- */
/* The avatar is a circle whether it holds initials or a face, so a screen does not reflow
   when somebody uploads one. */
/* display:block matters. .av sets display:grid so initials can be centred, and a grid
   display on a replaced element is not something every browser paints reliably; Safari
   showed a broken-image glyph where the face should be. The photo variant is a plain
   block image again. */
.av.has-photo{display:block;object-fit:cover;background:var(--line-2);padding:0}
.av.lg{width:72px;height:72px;font-size:22px}
.photo-cell{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.photo-cell .meta{font-size:11.5px;color:var(--faint)}

/* The blocks under a person's details: access, photograph, fees, signing in, removal.
   They spread across the width rather than queueing down one side, which is what made the
   panel three screens tall on a wide monitor. */
.panel-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(270px,1fr));
  gap:16px 22px;align-items:start;
  /* Clear of the Save button above it, with a hairline so the details form reads as its own
     block rather than running straight into the photograph and fees. */
  margin-top:22px;padding-top:20px;border-top:1px solid var(--line-2)}
.panel-cols > div{min-width:0}

/* A person's panel. Its summary is the way out, so it only exists once the panel is open:
   shown while closed it sat under every row saying "Close" and opened the thing instead. */
details.person:not([open]) > summary{display:none}
details.person > summary::-webkit-details-marker{display:none}

/* A card that folds away. The summary marker is removed so the header reads as a header
   rather than a disclosure triangle, and the button on the right is the affordance. */
/* Adding a semester is the rare errand on a page about the college, so it is a button until
   it is wanted rather than a card competing with the calendar above it. */
.addsem > summary{cursor:pointer;list-style:none;display:inline-flex}
.addsem > summary::-webkit-details-marker{display:none}
.addsem[open] > summary .btn.o::after{content:" \00d7"}

details.card > summary::-webkit-details-marker{display:none}
details.card > summary{display:flex;align-items:center;gap:14px}
details.card > summary:hover .btn.o{background:var(--green-lt);border-color:var(--green)}
details.card[open] > summary .btn.o::after{content:" ×"}

/* ---------- choosing a narration voice ---------- */
/* One choice, so each option is a whole card rather than a tick in a row. The radio itself
   is hidden: the card is the control, and a 44px target works on a phone. */
.voices{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:9px;max-width:760px}
.voice{position:relative;display:block;padding:11px 13px;border:1px solid var(--line);
  border-radius:10px;background:#fff;cursor:pointer;min-height:44px}
.voice:hover{border-color:var(--green);background:var(--green-lt)}
.voice input{position:absolute;opacity:0;width:0;height:0}
.voice .nm{display:block;font-size:13.5px;font-weight:700;color:var(--ink)}
.voice .note{display:block;font-size:11.5px;color:var(--faint);margin-top:2px}
.voice .wait{display:block;font-size:10.5px;color:var(--gold);margin-top:4px;font-weight:600}
.voice.on{border-color:var(--green);background:var(--green-lt);box-shadow:inset 0 0 0 1px var(--green)}
.voice.on .nm::after{content:" ✓";color:var(--green-dk)}

/* ---------- month calendar ---------- */
.cal{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#fff}
.cal-head{display:flex;align-items:center;gap:12px;padding:13px 16px;border-bottom:1px solid var(--line-2);
  flex-wrap:wrap}
.cal-head h3{font-size:15px;font-weight:700}
.cal-nav{margin-left:auto;display:flex;gap:6px}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);background:var(--line);gap:1px;
  border-top:1px solid var(--line)}
.cal-dow{background:#FAFBFE;padding:7px 8px;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);font-weight:700;text-align:center}
.cal-day{background:#fff;min-height:98px;padding:7px 8px;display:flex;flex-direction:column;gap:4px}
.cal-day.muted{background:#FCFDFF}
.cal-day.muted .n{color:var(--line)}
.cal-day.today{background:var(--green-lt)}
.cal-day .n{font-size:11.5px;font-weight:700;color:var(--body);font-variant-numeric:tabular-nums}
.cal-day.today .n{color:var(--green-dk)}
.cal-ev{font-size:10.5px;line-height:1.35;padding:3px 6px;border-radius:5px;background:#EEF3FB;
  color:var(--navy);border-left:2px solid var(--navy);overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.cal-ev.deadline{background:var(--red-lt);color:#8C2F28;border-left-color:var(--red)}
.cal-ev.assignment{background:var(--gold-lt);color:var(--gold);border-left-color:var(--gold-br)}
.cal-ev.examination{background:#E7EDF8;color:var(--navy-ink);border-left-color:var(--navy-ink)}
.cal-more{font-size:10px;color:var(--faint);font-weight:600}
@media(max-width:820px){
  .cal-grid{grid-template-columns:repeat(7,minmax(74px,1fr));overflow-x:auto}
  .cal-day{min-height:78px}
}

/* Attachments on a message. A photograph is shown small and opens full size; a document is
   a plain row, because a PDF has nothing to preview at this size. */
.atts{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
.atts .att-img{display:block;max-width:220px;text-decoration:none}
.atts .att-img img{display:block;width:100%;height:150px;object-fit:cover;
  border:1px solid var(--line-2);border-radius:8px;background:var(--bg-2)}
.atts .att-img .mut{display:block;font-size:11px;margin-top:4px;word-break:break-word}
.atts .file{align-self:flex-start}

/* Presenter clips on the week review screen. One row per clip, the file field and its
   actions on the right, wrapping to their own line on a narrow screen. */
.clips{margin-top:16px;padding-top:14px;border-top:1px solid var(--line-2)}
.clip-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:9px 0;border-bottom:1px solid var(--line-2)}
.clip-row:last-of-type{border-bottom:0}
.clip-row > div:first-child{min-width:150px;flex:1 1 150px}
.clip-row form{display:flex;align-items:center;gap:8px;margin:0}
.clip-row input[type=file]{max-width:230px;font-size:12px}

/* ---- the semester band -------------------------------------------------------------------
   Which semester the college is in, at the top of every dashboard. One row on a desktop and
   stacked on a phone, because the dates are the part that must never wrap into nonsense. */
.semband{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  border:1px solid var(--line);border-left:3px solid var(--navy-2);border-radius:11px;
  background:#fff;padding:12px 16px;margin-bottom:16px}
.semband b{display:block;font-size:13.5px;font-weight:700;color:var(--ink)}
.semband span{display:block;font-size:11.5px;color:var(--faint);margin-top:2px}
.semband .sembar{flex:1 1 140px;height:7px;border-radius:4px;background:var(--line-2);
  overflow:hidden;min-width:110px;max-width:320px}
.semband .sembar i{display:block;height:100%;background:var(--navy-2);border-radius:4px}
.semband .semnote{font-size:11.5px;color:var(--body);white-space:nowrap}

/* A day that continues an entry from the day before. The run reads as one thing across the
   week because the middle days are quieter than the day it starts on, and the last one says
   so rather than leaving the reader to count squares. */
.cal-ev.cont{opacity:.72;font-style:italic}
.cal-ev .ends{font-style:normal;font-weight:700;font-size:9px;letter-spacing:.06em;
  text-transform:uppercase;opacity:.75}
