/* =====================================================================
   Paras — base: reset, typography, controls
   ===================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--white);
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: var(--body-m);
  line-height: var(--body-m-lh);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
svg { flex: none; }

h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 600; }
p { margin: 0 0 var(--s4); }
ul, ol { margin: 0 0 var(--s4); padding-left: 1.25em; }
li + li { margin-top: var(--s2); }

a { color: var(--blue-700); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--blue-600); }

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

:focus-visible {
  outline: 3px solid var(--blue-600);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink-900); color: #fff;
  padding: var(--s3) var(--s5); z-index: 999;
  border-radius: 0 0 var(--r-md) 0;
}
.skip-link:focus { left: 0; color: #fff; }

/* --- Type scale ---------------------------------------------------- */
.display-xl, .display-l, .display-m, .h2, .h3, .stat-l, .stat-m {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink-900);
}
.display-xl { font-size: var(--display-xl); line-height: var(--display-xl-lh); letter-spacing: -.02em; }
.display-l  { font-size: var(--display-l);  line-height: var(--display-l-lh);  letter-spacing: -.02em; }
.display-m  { font-size: var(--display-m);  line-height: var(--display-m-lh);  letter-spacing: -.02em; }
.h2         { font-size: var(--h2);         line-height: var(--h2-lh);         letter-spacing: -.02em; }
.h3         { font-size: var(--h3);         line-height: var(--h3-lh);         letter-spacing: -.01em; }
.h4 { font-family: var(--font-body); font-weight: 700; font-size: var(--h4); line-height: var(--h4-lh); letter-spacing: -.01em; }
.h5 { font-family: var(--font-body); font-weight: 700; font-size: var(--h5); line-height: var(--h5-lh); }
.stat-l { font-size: var(--stat-l); line-height: var(--stat-l-lh); letter-spacing: -.02em; }
.stat-m { font-size: var(--stat-m); line-height: var(--stat-m-lh); letter-spacing: -.02em; }

.body-l { font-size: var(--body-l); line-height: var(--body-l-lh); }
.body-m { font-size: var(--body-m); line-height: var(--body-m-lh); }
.body-s { font-size: var(--body-s); line-height: var(--body-s-lh); }
.label-m { font-size: var(--label-m); line-height: var(--label-m-lh); font-weight: 600; }
.label-s { font-size: var(--label-s); line-height: var(--label-s-lh); font-weight: 600; }
.overline {
  font-size: var(--overline); line-height: var(--overline-lh);
  font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--blue-700);
}
.accent-italic { font-family: var(--font-display); font-style: italic; font-weight: 400; }

.muted { color: var(--ink-500); }
.quiet { color: var(--ink-300); }
.tnum { font-variant-numeric: tabular-nums; }

/* --- Layout --------------------------------------------------------- */
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--s5); }
.section { padding-block: var(--s12); }
.section--tight { padding-block: var(--s10); }
.stack > * + * { margin-top: var(--s4); }
.row { display: flex; gap: var(--s4); align-items: center; }
.row--between { justify-content: space-between; }
.row--wrap { flex-wrap: wrap; }
/* On a phone a row of buttons or date inputs has nowhere to go, so it pushed
   its card — and with it the whole canvas — wider than the screen. This hit
   the profile, exams, lectures, video library and reports screens. Wrapping
   is the right answer at this width whether the row asked for it or not. */
@media (max-width: 560px) {
  .row { flex-wrap: wrap; }
}
.grid { display: grid; gap: var(--s6); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 980px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
  .section { padding-block: var(--s10); }
  .display-xl { font-size: 40px; line-height: 46px; }
  .display-l  { font-size: 34px; line-height: 40px; }
  .display-m  { font-size: 28px; line-height: 34px; }
  .h2 { font-size: 30px; line-height: 36px; }
  .h3 { font-size: 23px; line-height: 30px; }
}

/* --- Buttons -------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: var(--font-body); font-weight: 600; font-size: var(--label-m);
  line-height: 1; text-decoration: none; cursor: pointer;
  padding: 14px var(--s6); border-radius: var(--r-pill);
  border: 1px solid transparent; transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease), transform .12s var(--ease);
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; transform: none; }

.btn--primary { background: var(--blue-700); color: #fff; }
.btn--primary:hover { background: var(--blue-600); color: #fff; }

.btn--gold { background: var(--gold-400); color: var(--ink-900); }
.btn--gold:hover { background: #eaa92e; color: var(--ink-900); }

.btn--ghost { background: transparent; color: var(--ink-900); border-color: var(--line-strong); }
.btn--ghost:hover { background: var(--blue-50); border-color: var(--blue-600); color: var(--blue-700); }

.btn--quiet { background: transparent; color: var(--blue-700); padding-inline: var(--s2); }
.btn--quiet:hover { text-decoration: underline; }

.btn--danger { background: var(--red-600); color: #fff; }
.btn--danger:hover { background: #8f1e18; color: #fff; }

.btn--sm { padding: 9px var(--s4); font-size: var(--label-s); }
.btn--block { width: 100%; }

/* --- Forms ---------------------------------------------------------- */
.field { display: block; margin-bottom: var(--s5); }
.field__label { display: block; font-size: var(--label-s); font-weight: 600; color: var(--ink-700); margin-bottom: var(--s2); }
.field__hint { font-size: var(--label-s); color: var(--ink-500); margin-top: var(--s2); }
.field__error { font-size: var(--label-s); color: var(--red-600); margin-top: var(--s2); }

.input, .select, .textarea {
  width: 100%; font-family: var(--font-body); font-size: var(--body-m);
  color: var(--ink-900); background: var(--white);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  padding: 12px var(--s4); transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}

/* A tick box is not a text field.
   input() in the portal stamps class="input" on everything, which is right
   for the thirty text fields and wrong for the twenty-six checkboxes and
   radios: they were inheriting width:100% and 12px of padding, so each one
   stretched across its whole row and shoved its own label off to the far
   side. Every permission grid, every "select all" and every filter box in
   the portal was drawn that way. Left as an override here rather than
   fixed at the twenty-six call sites, because the next one written will
   have the same class on it too. */
.input[type="checkbox"], .input[type="radio"] {
  width: auto; min-width: 0; flex: none;
  padding: 0; border-radius: 0; accent-color: var(--blue-600);
  /* Big enough to hit on a phone without a stylus. */
  block-size: 17px; inline-size: 17px;
}
.input::placeholder, .textarea::placeholder { color: var(--ink-300); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--blue-600);
  box-shadow: 0 0 0 3px var(--blue-100);
}
.input[aria-invalid="true"] { border-color: var(--red-600); }
.textarea { min-height: 120px; resize: vertical; }
.select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235e6b7d' stroke-width='2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right var(--s4) center;
  padding-right: var(--s9);
}

.checkbox, .radio { display: flex; gap: var(--s3); align-items: flex-start; margin-bottom: var(--s3); }
.checkbox input, .radio input { margin-top: 3px; width: 18px; height: 18px; accent-color: var(--blue-700); flex: none; }

/* --- Chips, badges, pills ------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 5px var(--s3); border-radius: var(--r-pill);
  font-size: var(--label-s); font-weight: 600;
  background: var(--blue-50); color: var(--blue-700); border: 1px solid var(--blue-100);
}
.chip--gold  { background: var(--gold-50);  color: var(--gold-700);  border-color: var(--gold-100); }
.chip--green { background: var(--green-100); color: var(--green-600); border-color: #c9e8d7; }
.chip--red   { background: var(--red-100);  color: var(--red-600);   border-color: #f6d5d3; }
.chip--grey  { background: var(--canvas);   color: var(--ink-500);   border-color: var(--line); }
/* Handed in and waiting to be marked — distinct from gold, which means
   something needs attention, and from green, which means finished. */
.chip--blue  { background: var(--blue-50);   color: var(--blue-700);  border-color: var(--blue-100); }

/* --- Cards ----------------------------------------------------------- */
.card {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s6);
}
.card--flat { box-shadow: none; }
.card--raised { box-shadow: var(--shadow-md); border-color: transparent; }

/* --- Tables ---------------------------------------------------------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; font-size: var(--body-s); }
.table th, .table td { text-align: left; padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); vertical-align: middle; }
.table th {
  font-size: var(--label-s); font-weight: 700; color: var(--ink-500);
  text-transform: uppercase; letter-spacing: .06em;
  background: var(--canvas); white-space: nowrap;
}
.table tbody tr:hover { background: var(--blue-50); }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Utility --------------------------------------------------------- */
.hidden { display: none !important; }
/* The HTML `hidden` attribute only sets `display: none` as a UA default, so
   any component rule that sets its own display silently beats it. That is
   what put a permanent pale-blue strip above the message box: the reply
   strip was `hidden`, and `.p-reply { display: flex }` won. The code was
   right and the element was still on screen.

   This is the standard normalize line and it was missing. It makes `hidden`
   mean hidden everywhere, which also covers the same latent collision in
   the assignment late-penalty field, the certificate purpose field and the
   sign-in error line — all set with `el.hidden` and all sitting behind
   their own display rules. */
[hidden] { display: none !important; }
.mt-0 { margin-top: 0 !important; }
.mb-0 { margin-bottom: 0 !important; }
.text-center { text-align: center; }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* =====================================================================
   Shared components — used by BOTH the marketing site and the portal.

   These lived in site.css, which the portal does not load: the portal
   page enqueues portal.css instead. That left the sign-in screen with no
   layout at all and every notice in the LMS as bare text, because
   ui.js notice() emits .notice-box and auth-screens.js draws .auth and
   .site-brand. Anything both surfaces use belongs here, in the layer
   they both load.
   ===================================================================== */

/* --- Brand lockup --------------------------------------------------------------- */
.site-brand { display: flex; align-items: center; gap: var(--s3); text-decoration: none; color: var(--ink-900); }
.site-brand__mark {
  width: 44px; height: 44px; border-radius: 12px; flex: none;
  background: linear-gradient(140deg, var(--blue-700), var(--blue-600));
  color: #fff; display: grid; place-items: center;
  font-family: var(--font-display); font-size: 22px; font-weight: 600;
}
.site-brand__name { font-family: var(--font-display); font-size: 19px; font-weight: 600; line-height: 1.1; }
.site-brand__sub { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-500); font-weight: 700; }

/* --- Auth pages ----------------------------------------------------------------- */
.auth { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; }
.auth__aside { background: var(--blue-700); color: #fff; padding: var(--s11) var(--s9); display: flex; flex-direction: column; justify-content: space-between; position: relative; overflow: hidden; }
.auth__aside::after { content: ""; position: absolute; right: -140px; bottom: -160px; width: 480px; height: 480px; border-radius: 50%; background: radial-gradient(circle, rgba(243,181,65,.3), transparent 65%); }
.auth__aside .display-m, .auth__aside .h3 { color: #fff; position: relative; }
.auth__aside p { color: #cfe0ff; position: relative; }
.auth__panel { display: grid; place-items: center; padding: var(--s9) var(--s6); }
.auth__form { width: 100%; max-width: 420px; }
.auth__form .site-brand { margin-bottom: var(--s8); }
.auth__switch { margin-top: var(--s6); font-size: var(--body-s); color: var(--ink-500); }
@media (max-width: 900px) { .auth { grid-template-columns: 1fr; } .auth__aside { display: none; } }

/* --- Notice --------------------------------------------------------------------- */
.notice-box { border-radius: var(--r-md); padding: var(--s4) var(--s5); font-size: var(--body-s); border: 1px solid; }
.notice-box--info  { background: var(--blue-50);  border-color: var(--blue-100);  color: var(--blue-700); }
.notice-box--warn  { background: var(--gold-50);  border-color: var(--gold-100);  color: var(--gold-700); }
.notice-box--error { background: var(--red-100);  border-color: #f6d5d3;          color: var(--red-600); }
.notice-box--ok    { background: var(--green-100); border-color: #c9e8d7;         color: var(--green-600); }

/* --- Key/value list ------------------------------------------------------------- */
/* Drawn by the portal's kv() and by the course detail page on the public
   site, so it cannot live in either one's own stylesheet. */
.p-kv { display: grid; grid-template-columns: 160px minmax(0,1fr); gap: var(--s3) var(--s5); }
.p-kv dt { font-size: var(--label-s); color: var(--ink-500); font-weight: 600; }
.p-kv dd { margin: 0; font-size: var(--body-s); }
