/* ============================================================================
   BrightSparx components — Phase 04
   Every colour here comes from a token. No brand hex appears in this file.
   Mobile-first: the base rules are the 375px layout, and media queries add.
   ============================================================================ */

*,
*::before,
*::after { box-sizing: border-box; }

html { min-height: 100%; }

body {
    margin: 0;
    background: var(--page);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
}

/* A <use> reference clones only the <symbol> subtree — the sprite root's fill and
   stroke attributes do NOT come with it, so without this every icon renders as a
   solid black filled shape. Setting it here is authoritative for every icon. */
.icon {
    flex: none;
    vertical-align: -0.15em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Anything focused by keyboard must be obviously focused. */
:focus-visible {
    outline: 2px solid var(--blue-600);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* Keyboard users should be able to jump the sidebar. */
.skip-link {
    position: absolute;
    left: var(--space-3);
    top: -3rem;
    z-index: 100;
    padding: var(--space-2) var(--space-4);
    background: var(--surface);
    color: var(--ink);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    text-decoration: none;
    font-weight: 600;
    transition: top var(--transition);
}
.skip-link:focus { top: var(--space-3); }

/* ---------------------------------------------------------------- app shell */

.app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.app__main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

/* --- sidebar. Off-canvas below 900px, permanent above. --- */
.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-width);
    background: var(--navy-800);
    color: var(--ink-on-dark);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    padding: var(--space-4) 0;
    z-index: 40;
    transform: translateX(-100%);
    transition: transform var(--transition);
    overflow-y: auto;
}
.sidebar[data-open="true"] { transform: translateX(0); }

/*  The logo is a detailed illustration — a city, a microscope, an atom, a
    wordmark and a year. At the 30px height it used to have, none of that was
    legible: it read as a smudge next to the text that actually named the app.
    Sized by width instead, so it scales with the sidebar rather than being
    pinned to a height that suits a simple mark. */
.sidebar__brand {
    display: block;
    padding: 0 var(--space-4);
    color: var(--ink-on-dark);
    text-decoration: none;
}
.sidebar__logo {
    display: block;
    width: 100%;
    max-width: 176px;
    height: auto;
    margin: 0 auto;
}

.navgroup { padding: 0 var(--space-2); }
.navgroup__heading {
    margin: 0 0 var(--space-2);
    padding: 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: 0.625rem;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.4);
}
.nav { display: flex; flex-direction: column; gap: 1px; }
.nav__link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    color: var(--ink-on-dark-muted);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.2;
    transition: background var(--transition), color var(--transition);
}
.nav__link:hover { background: rgba(255, 255, 255, 0.06); color: var(--ink-on-dark); }
.nav__link[aria-current="page"] { background: rgba(255, 255, 255, 0.1); color: var(--ink-on-dark); }
.nav__link[aria-current="page"] .icon { color: var(--brand-gold); }
.nav__badge {
    margin-left: auto;
    background: var(--brand-coral);
    color: #fff;
    font-family: var(--font-mono);
    font-size: 0.5625rem;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
}

.sidebar__footer { margin-top: auto; padding: var(--space-4) var(--space-4) 0; }
.whoami {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.avatar {
    width: 30px; height: 30px;
    border-radius: 50%;
    display: grid; place-items: center;
    background: var(--brand-gold);
    color: var(--navy-800);
    font-weight: 600;
    font-size: var(--text-xs);
    flex: none;
}
.whoami__name { display: block; font-size: var(--text-sm); font-weight: 600; line-height: var(--leading-tight); }
.whoami__role { display: block; font-size: var(--text-xs); color: var(--ink-on-dark-muted); }

.sidebar__scrim {
    position: fixed;
    inset: 0;
    background: rgba(10, 13, 46, 0.45);
    z-index: 30;
    border: 0;
    padding: 0;
}
.sidebar__scrim[hidden] { display: none; }

/* --- top bar --- */
.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: var(--topbar-height);
    padding: var(--space-2) var(--space-4);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.topbar__title {
    margin: 0;
    font-size: var(--text-md);
    font-weight: 600;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.topbar__spacer { margin-left: auto; }

.iconbutton {
    display: inline-grid;
    place-items: center;
    width: 34px; height: 34px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink-muted);
    cursor: pointer;
}
.iconbutton:hover { color: var(--ink); background: var(--surface-sunken); }

.content { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); }

@media (min-width: 900px) {
    .sidebar { transform: none; }
    .app { padding-left: var(--sidebar-width); }
    .sidebar__scrim, .topbar__menu { display: none !important; }
    .content { padding: var(--space-5); }
}

/* ------------------------------------------------------------------ surfaces */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
}
.card__header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
}
.card__title { margin: 0; font-size: var(--text-base); font-weight: 600; }
.card__meta { margin-left: auto; font-size: var(--text-xs); color: var(--ink-muted); }
.card__body { padding: var(--space-4); }

/* ------------------------------------------------------------------- buttons */

.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border: 1px solid transparent;
    border-radius: var(--radius);
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--transition), border-color var(--transition);
}
/* Coral commits. At most one of these per screen. */
.btn--primary { background: var(--brand-coral); color: #fff; }
.btn--primary:hover { background: var(--coral-700); }

.btn--secondary { background: var(--surface); color: var(--ink-2); border-color: var(--line-strong); }
.btn--secondary:hover { background: var(--surface-sunken); color: var(--ink); }

/* Gold signals "this is the step you are on". */
.btn--attention { background: var(--brand-gold); color: var(--navy-800); }
.btn--attention:hover { background: var(--gold-200); }

.btn--ghost { background: transparent; color: var(--blue-700); }
.btn--ghost:hover { background: var(--blue-100); }

.btn--danger { background: var(--surface); color: var(--coral-700); border-color: var(--coral-200); }
.btn--danger:hover { background: var(--coral-100); }

.btn--sm { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }

/* --------------------------------------------------------------------- pills */

.pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-2);
    border: 1px solid;
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
}
/* Each state carries a distinct icon as well as a distinct colour (D14), so the
   states stay legible in greyscale and to colour-blind readers. */
.pill--draft   { color: var(--ink-muted);  background: var(--surface-sunken); border-color: var(--line); }
.pill--sub     { color: var(--blue-700);   background: var(--blue-100);       border-color: var(--blue-200); }
.pill--eval    { color: var(--gold-600);   background: var(--gold-100);       border-color: var(--gold-200); }
.pill--revise  { color: var(--coral-700);  background: var(--coral-100);      border-color: var(--coral-200); }
.pill--final   { color: var(--ok-700);     background: var(--ok-100);         border-color: var(--ok-200); }

/* -------------------------------------------------------------------- tables */

.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
.table th {
    text-align: left;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line-strong);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
    white-space: nowrap;
}
.table td { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line); color: var(--ink-2); }
.table tr:last-child td { border-bottom: 0; }
.table__num { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------------------------------------------------------------------- form */

.field { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-4); }
.field__label { font-size: var(--text-sm); font-weight: 600; color: var(--ink-2); }
.field__label .req { color: var(--brand-coral); }
.field__hint { font-size: var(--text-xs); color: var(--ink-muted); }
.field__error { font-size: var(--text-xs); color: var(--coral-700); font-weight: 600; }

.input, .select, .textarea {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: var(--text-sm);
}
.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--blue-600);
    box-shadow: var(--focus-ring);
}
.textarea { min-height: 6rem; resize: vertical; }
.input[aria-invalid="true"] { border-color: var(--brand-coral); }

.formrow { display: grid; gap: var(--space-4); }
@media (min-width: 680px) {
    .formrow--two { grid-template-columns: 1fr 1fr; }
    .formrow--three { grid-template-columns: repeat(3, 1fr); }
}

/* ----------------------------------------------------------- empty / loading */

.empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-7) var(--space-4);
    text-align: center;
    color: var(--ink-muted);
}
.empty .icon { color: var(--line-strong); }
.empty__title { font-size: var(--text-md); font-weight: 600; color: var(--ink-2); margin: 0; }
.empty__body { margin: 0; max-width: 40ch; font-size: var(--text-sm); }

.skeleton {
    background: linear-gradient(90deg, var(--surface-sunken) 25%, var(--line) 37%, var(--surface-sunken) 63%);
    background-size: 400% 100%;
    animation: skeleton 1.4s ease infinite;
    border-radius: var(--radius-sm);
    height: 1rem;
}
@keyframes skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ------------------------------------------------------------------- notices */

.notice {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid;
    border-radius: var(--radius-lg);
    font-size: var(--text-sm);
}
.notice__body { margin: 0; }
.notice--info    { background: var(--blue-100);  border-color: var(--blue-200);  color: var(--blue-700); }
.notice--attention { background: var(--gold-100); border-color: var(--gold-200); color: var(--gold-600); }
.notice--success { background: var(--ok-100);    border-color: var(--ok-200);    color: var(--ok-700); }
.notice--error   { background: var(--coral-100); border-color: var(--coral-200); color: var(--coral-700); }

/* -------------------------------------------------------------------- footer */

.appfooter {
    padding: var(--space-4);
    border-top: 1px solid var(--line);
    color: var(--ink-muted);
    font-size: var(--text-xs);
}

.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------------- table toolbar & pager */
/* Phase 07: replaces the Kendo grid chrome. Everything here drives a server
   round trip, so paging and filtering are real rather than browser-side. */

.tabletoolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
}
.tabletoolbar__search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 12rem;
    min-width: 0;
}
.tabletoolbar__search .icon {
    position: absolute;
    left: var(--space-3);
    color: var(--ink-muted);
    pointer-events: none;
}
.tabletoolbar__search .input { padding-left: 2.1rem; }
.tabletoolbar__cycle { flex: 0 1 12rem; }

.table th a {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}
.table th a:hover { color: var(--ink); }
.table th a[aria-sort] { color: var(--blue-700); }

.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--line);
}
.pager__summary { margin: 0; font-size: var(--text-sm); color: var(--ink-muted); }
.pager__summary strong { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.pager__controls { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }
.pager__position { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }

.btn.is-disabled { opacity: 0.45; pointer-events: none; }

/* ------------------------------------------------------- revision timeline */
.timeline { list-style: none; margin: 0; padding: 0 0 0 var(--space-5); position: relative; }
.timeline::before {
    content: "";
    position: absolute;
    left: 5px; top: 6px; bottom: 6px;
    width: 2px;
    background: var(--line);
}
.timeline__row { position: relative; padding-bottom: var(--space-4); }
.timeline__row:last-child { padding-bottom: 0; }
.timeline__nub {
    position: absolute;
    left: calc(-1 * var(--space-5) + 1px); top: 4px;
    width: 12px; height: 12px;
    border-radius: 50%;
    background: var(--blue-600);
    border: 2px solid var(--surface);
    box-shadow: 0 0 0 1px var(--blue-200);
}
.timeline__nub--done { background: var(--ok-600); box-shadow: 0 0 0 1px var(--ok-200); }
.timeline__title {
    display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
    margin: 0 0 2px;
    font-size: var(--text-sm); font-weight: 600; color: var(--ink);
}
.timeline__when { margin-left: auto; font-size: var(--text-xs); font-weight: 400; color: var(--ink-muted); }
.timeline__body { margin: 0; font-size: var(--text-sm); color: var(--ink-2); }

/* --------------------------------------------------- dashboard (stage D) */

.hero {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-5);
    border-radius: var(--radius-lg);
    background: linear-gradient(105deg, var(--navy-800) 0%, var(--navy-700) 62%, var(--navy-600) 100%);
    color: var(--ink-on-dark);
}
.hero__eyebrow {
    margin: 0 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--brand-gold);
}
.hero__title { margin: 0 0 var(--space-2); font-size: var(--text-xl); font-weight: 700; letter-spacing: -0.02em; }
.hero__sub { margin: 0; font-size: var(--text-sm); color: var(--ink-on-dark-muted); max-width: 46ch; }

.hero__deadline {
    margin-left: auto;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(247, 201, 72, 0.28);
}
.hero__deadline-label {
    display: flex; align-items: center; gap: var(--space-1);
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--brand-gold);
}
.hero__deadline-value { margin: 0; font-size: var(--text-md); font-weight: 600; font-variant-numeric: tabular-nums; }
.hero__deadline-note { margin: 2px 0 0; font-size: var(--text-xs); color: var(--ink-on-dark-muted); }

.statgrid { display: grid; gap: var(--space-3); grid-template-columns: 1fr; }
@media (min-width: 640px) { .statgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) {
    .statgrid { grid-template-columns: repeat(4, 1fr); }
    .statgrid--three { grid-template-columns: repeat(3, 1fr); }
}

.stat {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
}
/* Gold rail marks the tiles that need someone to do something. */
.stat--attention { border-left: 3px solid var(--brand-gold); }
.stat--closed { border-left: 3px solid var(--line-strong); }

.stat__label {
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.stat__value {
    margin: 0;
    font-size: var(--text-2xl);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}
.stat__value--text { font-size: var(--text-md); font-weight: 600; letter-spacing: 0; }
.stat__value--money { font-size: var(--text-lg); }
.stat__note { margin: var(--space-2) 0 0; font-size: var(--text-xs); color: var(--ink-muted); }
.stat__note a { color: var(--blue-700); }

.bar { height: 5px; border-radius: var(--radius-pill); background: var(--surface-sunken); margin-top: var(--space-3); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--ok-600); }

.actionlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.actionlist__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--gold-200);
    background: var(--gold-100);
    border-radius: var(--radius);
    font-size: var(--text-sm);
    color: var(--ink-2);
}
.actionlist__item .icon { color: var(--gold-600); }
.actionlist__item > span { flex: 1; min-width: 0; }
.actionlist__item > a { margin-left: auto; }
.actionlist__item--calm { border-color: var(--ok-200); background: var(--ok-100); }
.actionlist__item--calm .icon { color: var(--ok-700); }

/* ============================================================================
   MODAL SKIN
   ----------------------------------------------------------------------------
   Bootstrap's modal markup is kept — it carries the focus trap, the backdrop and
   the escape handling, and reimplementing that badly is a real accessibility
   regression. Only the appearance is replaced, so every modal in the app moves
   onto the design system without its markup changing shape.

   components.css loads after bootstrap.min.css, so equal specificity wins here.
   ========================================================================== */

.modal-content {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    background: var(--surface);
    color: var(--ink);
}

.modal-header {
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-5) var(--space-3);
    border-bottom: 1px solid var(--line);
}

.modal-title {
    font-size: var(--text-lg);
    font-weight: 650;
    line-height: var(--leading-tight);
    color: var(--ink);
    margin: 0;
}

.modal-body {
    padding: var(--space-4) var(--space-5);
    font-size: var(--text-base);
    color: var(--ink-2);
    line-height: var(--leading-normal);
}
.modal-body > :first-child { margin-top: 0; }
.modal-body > :last-child { margin-bottom: 0; }
.modal-body p { margin: 0 0 var(--space-3); }

.modal-footer {
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5) var(--space-5);
    border-top: 1px solid var(--line);
    background: var(--surface-sunken);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.modal-footer > * { margin: 0; }

/* Bootstrap's close control is a background-image X. Recolour it to the ink
   ramp and give it a real focus ring rather than the default glow. */
.btn-close {
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    opacity: 0.55;
    transition: opacity var(--transition), background-color var(--transition);
}
.btn-close:hover { opacity: 1; background-color: var(--surface-sunken); }
.btn-close:focus { outline: none; box-shadow: var(--focus-ring); opacity: 1; }

.modal-backdrop.show { opacity: 0.55; background: var(--navy-900); }

/* A modal that leads with an outcome — saved, finalised, blocked — states it
   with a glyph as well as words, so the result is legible before the sentence
   is read and does not rest on colour alone. */
.modal__lead {
    display: flex;
    gap: var(--space-4);
    align-items: flex-start;
}
.modal__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius-pill);
    border: 1px solid;
}
.modal__icon--success { background: var(--ok-100);    border-color: var(--ok-200);    color: var(--ok-700); }
.modal__icon--info    { background: var(--blue-100);  border-color: var(--blue-200);  color: var(--blue-700); }
.modal__icon--warn    { background: var(--gold-100);  border-color: var(--gold-200);  color: var(--gold-600); }
.modal__icon--danger  { background: var(--coral-100); border-color: var(--coral-200); color: var(--coral-700); }

.modal__leadtext { min-width: 0; }
.modal__leadtext p { margin: 0 0 var(--space-2); }
.modal__leadtext p:last-child { margin-bottom: 0; }
.modal__leadtitle {
    margin: 0 0 var(--space-1);
    font-size: var(--text-md);
    font-weight: 650;
    color: var(--ink);
}

.modal--wide .modal-dialog { max-width: 46rem; }

/* ----------------------------------------------------------------- receipt */
/* Reference details a participant may need to quote back to an organiser: read
   rarely, but when it is read it is being copied by hand off a screen. */

.receipt {
    display: grid;
    gap: var(--space-3);
    margin: var(--space-4) 0 0;
    padding: var(--space-4);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
.receipt__row { display: grid; gap: var(--space-1); }
.receipt__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.receipt__value {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--text-md);
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    overflow-wrap: anywhere;
}
.receipt__copy { display: flex; align-items: center; gap: var(--space-2); }
.receipt__copy .receipt__value { flex: 1 1 auto; }

/* -------------------------------------------------------------------- steps */
/* Replaces the tab strip plus inner scroll region. The old pattern needed a
   standing instruction telling people to scroll inside a box, which is the
   interface apologising for itself; a form that says how many parts it has and
   which one you are on does not need the apology. */

.steps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0 0 var(--space-5);
    padding: 0;
    list-style: none;
}
.steps__item { flex: 1 1 12rem; min-width: 0; }

.steps__btn {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink-2);
    font: inherit;
    font-size: var(--text-sm);
    line-height: var(--leading-tight);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--transition), background-color var(--transition);
}
.steps__btn:hover { border-color: var(--line-strong); }
.steps__btn:focus-visible { outline: none; box-shadow: var(--focus-ring); border-color: var(--blue-600); }

.steps__num {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}
.steps__text { min-width: 0; }
.steps__label { display: block; font-weight: 600; color: var(--ink); }
.steps__hint  { display: block; font-size: var(--text-xs); color: var(--ink-muted); }

.steps__btn[aria-current="step"] {
    border-color: var(--blue-600);
    background: var(--blue-100);
    box-shadow: inset 0 0 0 1px var(--blue-600);
}
.steps__btn[aria-current="step"] .steps__num {
    background: var(--blue-600);
    border-color: var(--blue-600);
    color: var(--ink-on-dark);
}
.steps__btn[data-state="done"] .steps__num {
    background: var(--ok-600);
    border-color: var(--ok-600);
    color: var(--ink-on-dark);
}
.steps__btn[data-state="error"] { border-color: var(--coral-200); background: var(--coral-100); }
.steps__btn[data-state="error"] .steps__num {
    background: var(--brand-coral);
    border-color: var(--brand-coral);
    color: var(--ink-on-dark);
}

.steppanel[hidden] { display: none !important; }

.stepnav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--line);
}
.stepnav__spacer { margin-left: auto; }

/* -------------------------------------------------------------------- meter */
/* A number against its limit. The budget cap was previously only discoverable
   by exceeding it and reading the error that followed. */

.meter {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-sunken);
}
.meter__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
}
.meter__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.meter__value {
    margin-left: auto;
    font-size: var(--text-xl);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    line-height: 1;
}
.meter__limit { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }

.meter__track {
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--line);
    overflow: hidden;
}
.meter__fill {
    display: block;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: var(--blue-600);
    transition: width var(--transition), background-color var(--transition);
}
.meter__note { margin: 0; font-size: var(--text-xs); color: var(--ink-muted); }

.meter[data-state="near"] .meter__fill  { background: var(--gold-500); }
.meter[data-state="over"] { border-color: var(--coral-200); background: var(--coral-100); }
.meter[data-state="over"] .meter__value { color: var(--coral-700); }
.meter[data-state="over"] .meter__fill  { background: var(--brand-coral); }
.meter[data-state="over"] .meter__note  { color: var(--coral-700); font-weight: 600; }

/* ---------------------------------------------------------------- criterion */
/* The assessor workspace. Previously the six scores lived in one wide table and
   the six matching comment boxes lived in a separate list below it, so the
   assessor held the mapping between them in their head. Each criterion now
   carries its descriptors, its score and its comment in one block. */

.criterion {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    margin-bottom: var(--space-4);
    overflow: hidden;
}
.criterion__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-4);
    border-bottom: 1px solid var(--line);
    background: var(--surface-sunken);
}
.criterion__title { margin: 0; font-size: var(--text-md); font-weight: 650; color: var(--ink); }
.criterion__weight {
    margin-left: auto;
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--ink-muted);
}
.criterion__body { padding: var(--space-4); }

/* A criterion carrying no weight at this stage still has to appear, because the
   same rubric is used at every stage — but scoring it changes nothing, and the
   old table gave no hint of that. */
.criterion--unscored .criterion__head { background: var(--surface); }
.criterion--unscored .criterion__title { color: var(--ink-2); }

.levels {
    display: grid;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    padding: 0;
    list-style: none;
}
@media (min-width: 900px) { .levels { grid-template-columns: repeat(4, 1fr); } }

.level {
    display: block;
    position: relative;
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--ink-2);
    cursor: pointer;
    transition: border-color var(--transition), background-color var(--transition);
}
.level:hover { border-color: var(--line-strong); background: var(--surface-sunken); }
.level__mark {
    display: block;
    margin-bottom: var(--space-1);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.level input { position: absolute; opacity: 0; width: 0; height: 0; }
.level:has(input:checked) {
    border-color: var(--blue-600);
    background: var(--blue-100);
    box-shadow: inset 0 0 0 1px var(--blue-600);
    color: var(--ink);
}
.level:has(input:checked) .level__mark { color: var(--blue-700); }
.level:has(input:focus-visible) { outline: none; box-shadow: var(--focus-ring); }
fieldset:disabled .level { cursor: default; }

/* Zero is not a lower grade — it is a statement that the criterion does not
   apply — so it sits apart from the four descriptors rather than beside them. */
.level--na { border-style: dashed; }
.level--na:has(input:checked) {
    border-style: solid;
    border-color: var(--ink-muted);
    background: var(--surface-sunken);
    box-shadow: inset 0 0 0 1px var(--ink-muted);
}
.level--na:has(input:checked) .level__mark { color: var(--ink-2); }

/* ----------------------------------------------------------------- scorebar */
/* Running weighted total. The weights come from the server, never from a table
   copied into JavaScript — that duplication is what Phase 03 removed. */

.scorebar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow);
}
.scorebar__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.scorebar__value {
    font-size: var(--text-2xl);
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}
.scorebar__max { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.scorebar__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-left: auto; }
.scorebar__note { flex-basis: 100%; margin: 0; font-size: var(--text-xs); color: var(--ink-muted); }

/* ------------------------------------------------------------------- thread */
/*  Mentorship discussion. Author identity is carried by an avatar initial and a
    side rule, so the two voices stay apart without relying on colour alone.

    The thread is its own scroll region rather than something that grows the page.
    Length arrives from two directions and the live data has both: 22 of 63 comments
    run past a thousand characters, the longest is 10,390, so a season of discussion
    is several thousand pixels tall. Left to grow, the composer sits below the
    horizon and the newest comment — the reason anyone opened the page — ends up the
    furthest thing from the top.

    Hence two caps. The thread scrolls at roughly two thirds of the viewport, and any
    single comment taller than its own cap folds behind "Show the whole comment".
    Capping only the thread would have traded one long scroll for a smaller, worse
    one: five screens of inner scrolling through a single essay.

    max-height rather than height, so a two-comment thread keeps its natural size
    instead of sitting in a box of dead space.  */

.thread-shell { position: relative; }

.thread {
    display: grid;
    align-content: start;
    gap: var(--space-3);

    max-height: clamp(20rem, 62vh, 46rem);
    overflow-y: auto;
    scrollbar-gutter: stable;
    scroll-padding-block: var(--space-3);

    /*  White comment cards in a recessed well read as a container with its own
        extent; the same cards on the page background just read as the page. This
        does more to say "there is more of this, inside here" than any icon would. */
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-sunken);
}

@media (hover: hover) and (pointer: fine) {
    /*  Wheeling past the end of the thread should not carry the page along with it.
        Left alone on touch, where a contained box inside a scrolling page is exactly
        the thing that feels stuck under a thumb. */
    .thread { overscroll-behavior-y: contain; }
}

@media (max-width: 40rem) {
    .thread { max-height: 65vh; padding: var(--space-2); }
}

/*  Scrollable but not otherwise focusable, so it needs its own tab stop: without one
    a keyboard user cannot reach the older half of the conversation at all. */
.thread:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/*  A fade at whichever edge still has something behind it. Drawn on the shell rather
    than the scroller so it stays put while the content moves underneath. */
.thread-shell::before,
.thread-shell::after {
    content: "";
    position: absolute;
    left: 1px;
    right: 1px;
    height: 2.5rem;
    border-radius: var(--radius);
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--transition);
}
.thread-shell::before { top: 1px; background: linear-gradient(var(--surface-sunken), transparent); }
.thread-shell::after { bottom: 1px; background: linear-gradient(transparent, var(--surface-sunken)); }
.thread-shell--above::before { opacity: 1; }
.thread-shell--below::after { opacity: 1; }

/*  Reading back through the history strands you at the top of a long thread, and the
    newest comment is the one people come back for. After posting, this is also the
    confirmation that the comment landed. */
.thread__jump {
    position: absolute;
    left: 50%;
    bottom: var(--space-4);
    transform: translateX(-50%);
    z-index: 2;

    display: inline-flex;
    align-items: center;
    gap: var(--space-2);

    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    box-shadow: var(--shadow);

    font: inherit;
    font-size: var(--text-xs);
    font-weight: 650;
    color: var(--ink-2);
    cursor: pointer;
}
.thread__jump:hover { border-color: var(--blue-600); color: var(--blue-700); }
.thread__jump:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.comment {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--surface);
}
.comment--mentor { border-left-color: var(--blue-600); }
.comment--mentee { border-left-color: var(--brand-coral); }

.comment__avatar {
    flex: none;
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--ink-2);
}
.comment--mentor .comment__avatar { background: var(--blue-100); border-color: var(--blue-200); color: var(--blue-700); }
.comment--mentee .comment__avatar { background: var(--coral-100); border-color: var(--coral-200); color: var(--coral-700); }

.comment__main { flex: 1 1 auto; min-width: 0; }
.comment__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}
.comment__author { font-weight: 650; color: var(--ink); font-size: var(--text-sm); }
.comment__role {
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.comment__when { margin-left: auto; font-size: var(--text-xs); color: var(--ink-muted); }
.comment__content { font-size: var(--text-base); color: var(--ink-2); overflow-wrap: anywhere; }
.comment__content > :first-child { margin-top: 0; }
.comment__content > :last-child { margin-bottom: 0; }

/*  Folded, the thread stays a list you can scan and the reader opens the one they
    want. The cap is generous enough that an ordinary comment is never touched —
    only the essays, which in the live data means a comment past about a thousand
    characters. The class is applied by script, which measures first and takes it
    straight back off anything that already fits. */
/*  Doubled deliberately. A comment body carries .ql-editor too, and quill.snow.css
    loads from the page's Styles section — after this file — where it sets
    overflow-y: auto at the same specificity. A single class here would lose that
    tie and the fold would grow its own scrollbar instead of folding. */
.comment__content.comment__content--clamped {
    max-height: 19rem;
    overflow: hidden;
    /*  Fading the last line rather than slicing it: a clean cut reads as the end of
        the text, a fade reads as "this continues". */
    -webkit-mask-image: linear-gradient(#000 74%, transparent);
    mask-image: linear-gradient(#000 74%, transparent);
}
.comment__more {
    margin-top: var(--space-2);
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 650;
    color: var(--blue-700);
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.comment__more:hover { text-decoration: underline; }
.comment__more:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/*  A comment you have just written lands at the far end of a long thread. The scroll
    takes you to it; this says which one is yours once you arrive. Background only —
    the border-left carries the author's identity and must not be animated away. */
@keyframes comment-fresh {
    from { background: var(--gold-100); }
    to { background: var(--surface); }
}
.comment--fresh { animation: comment-fresh 2.4s ease-out; }

.composer { display: grid; gap: var(--space-3); }
.composer__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.composer__hint { font-size: var(--text-xs); color: var(--ink-muted); margin: 0; }

/* ------------------------------------------------------------- announcement */

.linkcell {
    display: inline-block;
    padding: 0;
    border: 0;
    background: none;
    color: var(--blue-700);
    font: inherit;
    font-size: var(--text-base);
    font-weight: 650;
    text-align: left;
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.linkcell:hover { text-decoration: underline; }
.linkcell:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Two lines of preview, ended by the browser at the real rendered width. The
   previous cut was measured in characters, so it ended mid-word and the column
   width still followed the content. */
.clamp2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: var(--space-1) 0 0;
    font-size: var(--text-xs);
    color: var(--ink-muted);
    line-height: var(--leading-normal);
}

/* Announcement bodies are plain text typed into a textarea, so the line breaks
   the author pressed are the only structure they have. */
.prose-plain {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font: inherit;
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--ink-2);
}

/* -------------------------------------------------------------- form alerts */
/* Replaces window.alert() for validation failures. A native alert steals focus,
   cannot be styled, and on a long form gives no clue which part is at fault. */

.formalert {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--coral-200);
    border-radius: var(--radius);
    background: var(--coral-100);
    color: var(--coral-700);
    font-size: var(--text-sm);
}
.formalert[hidden] { display: none !important; }
.formalert .icon { flex: none; margin-top: 0.1em; }
.formalert__body { margin: 0; }

.readonlybanner {
    display: flex;
    gap: var(--space-3);
    align-items: center;
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-sunken);
    color: var(--ink-2);
    font-size: var(--text-sm);
}
.readonlybanner .icon { flex: none; color: var(--ink-muted); }

/* A locked form still shows its values; it just cannot take new ones. Kept as a
   class rather than the disabled attribute so the values are still posted. */
.is-locked .input,
.is-locked .select,
.is-locked .textarea {
    background: var(--surface-sunken);
    color: var(--ink-2);
    pointer-events: none;
}

/* --------------------------------------------------------------- form layout */

.fieldgroup {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
}
.fieldgroup__title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-md);
    font-weight: 650;
    color: var(--ink);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.fieldgroup__badge {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ink-muted);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    padding: 0.1rem var(--space-2);
}

.switch { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch__track {
    position: relative;
    width: 2.6rem;
    height: 1.5rem;
    border-radius: var(--radius-pill);
    background: var(--line-strong);
    transition: background-color var(--transition);
}
.switch__track::after {
    content: "";
    position: absolute;
    top: 3px; left: 3px;
    width: 1.125rem; height: 1.125rem;
    border-radius: var(--radius-pill);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition);
}
.switch input:checked + .switch__track { background: var(--ok-600); }
.switch input:checked + .switch__track::after { transform: translateX(1.1rem); }
.switch input:focus-visible + .switch__track { box-shadow: var(--focus-ring); }
.switch__text { font-size: var(--text-sm); color: var(--ink-2); }

/* -------------------------------------------------------- submission viewer */
/* The work being judged or discussed, shown in place. Collapsible so it can sit
   above a long form without pushing the actual task off screen; open by default,
   because hiding the thing being assessed behind a click is how it got missed. */

.submissionview {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    margin-bottom: var(--space-4);
}

.submissionview__summary {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    cursor: pointer;
    list-style: none;
    border-radius: var(--radius-lg);
}
.submissionview__summary::-webkit-details-marker { display: none; }
.submissionview__summary:hover { background: var(--surface-sunken); }
.submissionview__summary:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.submissionview__title {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-md);
    font-weight: 650;
    color: var(--ink);
}
.submissionview__title .icon { color: var(--ink-muted); }
.submissionview__meta { font-size: var(--text-xs); color: var(--ink-muted); }
.submissionview__chevron { margin-left: auto; color: var(--ink-muted); display: inline-flex; transition: transform var(--transition); }
.submissionview[open] > .submissionview__summary { border-bottom: 1px solid var(--line); border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
.submissionview[open] .submissionview__chevron { transform: rotate(180deg); }

.submissionview__body { padding: var(--space-4); display: grid; gap: var(--space-4); }

.readblock { display: grid; gap: var(--space-2); }
.readblock__label {
    margin: 0;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}

.linklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.linklist a {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--blue-700);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    overflow-wrap: anywhere;
}
.linklist a:hover { text-decoration: underline; }

/* ------------------------------------------------------------- cycle picker */
/* One submission per cycle, so the participant's history is a short list of
   years rather than a table. */

.cyclelist { display: grid; gap: var(--space-3); }

.cyclecard {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--transition), background-color var(--transition);
}
.cyclecard:hover { border-color: var(--line-strong); background: var(--surface-sunken); }
.cyclecard:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.cyclecard--current { border-color: var(--blue-600); box-shadow: inset 0 0 0 1px var(--blue-600); }

.cyclecard__year {
    flex: none;
    display: grid;
    place-items: center;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: var(--radius);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    font-size: var(--text-md);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink-2);
}
.cyclecard--current .cyclecard__year { background: var(--blue-100); border-color: var(--blue-200); color: var(--blue-700); }

.cyclecard__main { flex: 1 1 14rem; min-width: 0; display: grid; gap: var(--space-1); }
.cyclecard__name { font-size: var(--text-md); font-weight: 650; color: var(--ink); }
.cyclecard__note { font-size: var(--text-sm); color: var(--ink-muted); }
.cyclecard__actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }

/* ------------------------------------------------------- add / edit form page */
/* One shape for every create and update screen, matching the Cycles pages. */

.formpage { max-width: 46rem; }
.formpage__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--line);
}
.formpage__foot .btn--primary { margin-left: auto; }
.formpage__back {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-muted);
    text-decoration: none;
    margin-bottom: var(--space-3);
}
.formpage__back:hover { color: var(--ink-2); text-decoration: underline; }

/* ------------------------------------------- submission viewer, section headings */
/*  These started as small muted uppercase labels, which is right for a key/value
    pair but wrong here: each one heads a paragraph of someone's writing that an
    assessor has to read closely and refer back to. They now read as headings —
    navy, larger, with a gold rule marking where each section begins — so the eye
    can find "Methodology" while scrolling rather than scanning grey capitals. */

.submissionview__body { gap: 0; }

.readblock {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4) 0;
    border-top: 1px solid var(--line);
}
.readblock:first-child { border-top: 0; padding-top: var(--space-1); }

.readblock__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--text-md);
    font-weight: 650;
    letter-spacing: normal;
    text-transform: none;
    color: var(--ink);
    line-height: var(--leading-tight);
}
.readblock__label::before {
    content: "";
    flex: none;
    width: 3px;
    height: 1.05em;
    border-radius: var(--radius-pill);
    background: var(--brand-gold);
}

.readblock .prose-plain {
    max-width: 78ch;
    padding-left: calc(3px + var(--space-2));
}
.readblock .tablewrap,
.readblock .linklist { margin-left: calc(3px + var(--space-2)); }

/* ------------------------------------------------------------- stage filter */
/*  One-click chips carrying their own counts, sitting under the toolbar.
    A second dropdown beside the year would have filtered the list without saying
    what was in it; the counts are what let the secretariat see where the cohort
    has got to before clicking anything. */

.stagefilter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
    background: var(--surface-sunken);
}

.stagefilter__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-right: var(--space-1);
}

.stagechip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--ink-2);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.7;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color var(--transition), background-color var(--transition), color var(--transition);
}
.stagechip:hover { border-color: var(--blue-600); color: var(--ink); }
.stagechip:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.stagechip__count {
    font-size: var(--text-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink-muted);
    background: var(--surface-sunken);
    border-radius: var(--radius-pill);
    padding: 0 var(--space-2);
    min-width: 1.6rem;
    text-align: center;
}

.stagechip.is-active {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: var(--ink-on-dark);
}
.stagechip.is-active .stagechip__count {
    background: rgba(255, 255, 255, 0.16);
    color: var(--ink-on-dark);
}

/*  A stage nobody has been assigned to is shown rather than hidden: an empty stage
    is information, and a chip row that changes length as you filter is harder to
    use than one that holds still. */
.stagechip.is-empty {
    opacity: 0.5;
    cursor: default;
    border-style: dashed;
}

/* --------------------------------------- submission viewer, expand / collapse cue */
/*  The section starts closed, so the bar has to say what is behind it and how to
    get at it — a chevron alone reads as decoration. The wording swaps with the
    state, and the cue is aria-hidden because <summary> already announces that. */

.submissionview__cue {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--blue-200);
    border-radius: var(--radius-pill);
    background: var(--blue-100);
    color: var(--blue-700);
    font-size: var(--text-xs);
    font-weight: 650;
    line-height: 1.7;
    white-space: nowrap;
}
.submissionview__cue::after { content: "Expand to read the team's work"; }

.submissionview[open] .submissionview__cue {
    border-color: var(--line-strong);
    background: var(--surface-sunken);
    color: var(--ink-muted);
}
.submissionview[open] .submissionview__cue::after { content: "Collapse"; }

/* The chevron no longer needs to push itself right — the cue holds that position. */
.submissionview__chevron { margin-left: 0; }

/* Closed, the bar is the whole component, so it keeps the full rounding and reads
   as one control rather than a header missing its body. */
.submissionview:not([open]) > .submissionview__summary:hover {
    border-color: var(--blue-600);
}
.submissionview:not([open]) {
    transition: border-color var(--transition);
}
.submissionview:not([open]):hover { border-color: var(--line-strong); }

@media (max-width: 40rem) {
    /* On a phone the cue's wording is the first thing to cost a line break. */
    .submissionview__cue::after { content: "Expand"; }
    .submissionview[open] .submissionview__cue::after { content: "Collapse"; }
}

/* --------------------------------------------------------------- decisions */
/*  The secretariat's "who goes through" list. A team is assessed by several
    people — three on 85 of 107 Selection entries, two on every Competition one —
    so the row is the team and the numbers are aggregates over its assessors. */

/* Secondary line under a cell's main value: the cycle under a team, "still
   scoring" under a count. Quieter than the value it belongs to, not a caption. */
.table__sub { margin-top: 2px; font-size: var(--text-xs); color: var(--ink-muted); }
.table__muted { color: var(--ink-muted); }

/* An incomplete count is a fact about the average above it, not an error. */
.is-pending { color: var(--gold-600); font-weight: 650; }

.scorecell { font-size: var(--text-md); font-weight: 700; color: var(--ink); }
.scorecell__max { margin-left: 2px; font-size: var(--text-xs); color: var(--ink-muted); }

/*  Assessor disagreement. Two people at 45 and 85 average the same as two at 64
    and 66, and those are not the same team to decide about — so the range sits on
    the row, and a wide one is marked rather than left to be noticed. */
.spread { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.spread--wide {
    color: var(--coral-700);
    font-weight: 650;
    border-bottom: 1px dotted var(--coral-200);
    cursor: help;
}

/*  A decision made from the numbers on the row, so the control opens in place.
    A dialog would take those numbers off screen at the moment they are being
    weighed; another page would lose them entirely. <details> because this needs no
    JavaScript and closes the same way it opens.

    Shared by advancing a team and by assigning an assessor — same shape, same
    reasoning, and two near-copies of it would have drifted. */
.rowaction > summary { list-style: none; cursor: pointer; }
.rowaction > summary::-webkit-details-marker { display: none; }
.rowaction[open] > summary { margin-bottom: var(--space-3); }

.rowaction__form {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-sunken);
    min-width: 16rem;
}
.rowaction__form .btn { justify-self: start; margin-top: var(--space-1); }

/*  A warning, not a block: the secretariat may have good reason to move a team on
    with a straggler outstanding. They should just know before they do. */
.rowaction__warn {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--gold-600);
}

/* ---------------------------------------------------------------- guidance */
/*  What a team writes their next entry from, sitting above the form they type
    into. Gold, because this is the "read me before you start" band and gold is
    the attention role in the palette (D7) — coral is reserved for the one
    committing action on a screen, which here is Submit. */

.guidance {
    margin-bottom: var(--space-5);
    border: 1px solid var(--gold-200);
    border-radius: var(--radius-lg);
    background: var(--surface);
    overflow: hidden;
}

.guidance__head {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-4);
    background: var(--gold-100);
    border-bottom: 1px solid var(--gold-200);
}
.guidance__head .icon { color: var(--gold-600); margin-top: 2px; }
.guidance__title { margin: 0 0 var(--space-1); font-size: var(--text-md); font-weight: 700; color: var(--ink); }
.guidance__sub { margin: 0; font-size: var(--text-sm); color: var(--ink-2); }

.guidance__block { padding: var(--space-4); border-bottom: 1px solid var(--line); }
.guidance__block:last-child { border-bottom: 0; }

/* The secretariat's own message: the instruction, so it gets the accent bar. */
.guidance__block--primary { border-left: 3px solid var(--brand-gold); }

.guidance__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
    cursor: default;
}
details.guidance__block > summary.guidance__label { cursor: pointer; }
details.guidance__block > summary.guidance__label::-webkit-details-marker { display: none; }

.guidance__when { margin-left: auto; font-weight: 500; letter-spacing: 0; text-transform: none; }
.guidance__count {
    padding: 1px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    letter-spacing: 0;
    text-transform: none;
    font-weight: 650;
    color: var(--ink-2);
}
.guidance__note { margin: 0 0 var(--space-3); font-size: var(--text-xs); color: var(--ink-muted); }

/*  One assessor's comments. Separated into cards because three assessors'
    remarks run together read as one contradictory voice. */
.assessor {
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-sunken);
}
.assessor + .assessor { margin-top: var(--space-3); }

.assessor__head {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}
.assessor__who { font-size: var(--text-sm); font-weight: 650; color: var(--ink); }
.assessor__score {
    margin-left: auto;
    font-size: var(--text-sm);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink-2);
}

.assessor__item + .assessor__item { margin-top: var(--space-3); }
.assessor__criterion {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--ink-2);
}

/* ------------------------------------------------------------------ rounds */
/*  A cycle holding the entries a team wrote for it. Once Selection and
    Competition can both exist in one year, the cycle stops being a link and
    becomes a heading over the rounds beneath it. */

.cyclegroup {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    overflow: hidden;
}
.cyclegroup--current { border-color: var(--blue-200); }

.cyclegroup__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--line);
}
.cyclegroup--current .cyclegroup__head { background: var(--blue-100); border-bottom-color: var(--blue-200); }

.cyclegroup__year {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--ink-muted);
    font-variant-numeric: tabular-nums;
}
.cyclegroup__name { font-weight: 650; color: var(--ink); }
.cyclegroup__count { margin-left: auto; font-size: var(--text-xs); color: var(--ink-muted); }

.rounds { list-style: none; margin: 0; padding: 0; }
.rounds > li + li { border-top: 1px solid var(--line); }

.round {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    color: inherit;
    text-decoration: none;
}
.round:hover { background: var(--surface-sunken); }
.round:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/*  The round number as a numbered step. The team's path through the cycle reads
    as a sequence, so it is numbered rather than bulleted. */
.round__num {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--surface-sunken);
    border: 1px solid var(--line-strong);
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--ink-2);
    font-variant-numeric: tabular-nums;
}
.round--past .round__num { background: transparent; color: var(--ink-muted); }

.round__main { flex: 1 1 auto; min-width: 0; }
.round__stage {
    display: block;
    font-weight: 650;
    color: var(--ink);
    font-size: var(--text-sm);
}
.round__note { display: block; font-size: var(--text-xs); color: var(--ink-muted); }

/*  Marked rather than dimmed. A superseded entry is still the team's work and
    still worth reading — it is just no longer the one being assessed. */
.round__tag {
    margin-left: var(--space-2);
    padding: 1px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0;
    color: var(--ink-muted);
}

.round__status { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.round__status .icon { color: var(--ink-muted); }

/* -------------------------------------------------------------- roundtrack */
/*  An assessor reading what the team wrote in an earlier round. Tabs rather
    than a dropdown: there are at most three, and the whole point is seeing the
    team's path at a glance — a closed dropdown shows one of them. */

.roundtrack {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}
.roundtrack__label {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-right: var(--space-1);
}

.roundtab {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--ink-2);
    text-decoration: none;
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1;
}
.roundtab:hover { border-color: var(--blue-600); color: var(--blue-700); }
.roundtab:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.roundtab.is-active {
    background: var(--navy-800);
    border-color: var(--navy-800);
    color: var(--ink-on-dark);
}

.roundtab__num {
    display: grid;
    place-items: center;
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    background: var(--surface-sunken);
    color: var(--ink-2);
    font-variant-numeric: tabular-nums;
}
.roundtab.is-active .roundtab__num { background: rgba(255, 255, 255, 0.2); color: var(--ink-on-dark); }

/*  Gold, because "this is the one your marks attach to" is the attention role
    in the palette (D7). It stays legible on the active navy tab too. */
.roundtab__marker {
    padding: 1px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--gold-100);
    color: var(--gold-600);
    font-size: 0.625rem;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    font-weight: 700;
}

/*  Submitted work with nobody assigned to it. Coral, because this is the one row
    on the cover screen that is actually blocking something — the team cannot be
    scored and so cannot reach the decision list at all. */
.is-uncovered { color: var(--coral-700); font-weight: 700; }

/*  "optional at Selection" beside a field label.
    Stated rather than implied by the absence of an asterisk: a field that is
    required later and not now is a different thing from one that is never
    required, and a team planning their work needs to know which. */
.field__optional {
    margin-left: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--ink-muted);
    text-transform: none;
    letter-spacing: 0;
}

/*  One round's feedback inside a cycle group on My results. */
.resultround { padding: var(--space-3) var(--space-4) var(--space-4); }
.resultround + .resultround { border-top: 1px solid var(--line); }

.resultround__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-3);
    font-size: var(--text-sm);
    font-weight: 650;
    color: var(--ink);
}
/* How much is still outstanding, without making the team hunt down the rows. */
.resultround__state { margin-left: auto; font-size: var(--text-xs); font-weight: 500; color: var(--ink-muted); }

/* ------------------------------------------------------------- cycle scope */
/*  Which competition year a secretariat list is showing. The running cycle is
    the default and the others fold away — hidden would be wrong, since a past
    year has to stay reachable, but open by default buries this year's dozen
    rows under last year's two hundred. */

.cyclescope {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
    background: var(--surface-sunken);
}
.cyclescope__label {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.cyclescope__current {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 650;
    color: var(--ink);
}
.cyclescope__badge {
    padding: 1px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--blue-100);
    border: 1px solid var(--blue-200);
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--blue-700);
}

.cyclescope__more { margin-left: auto; }
.cyclescope__more > summary {
    list-style: none;
    cursor: pointer;
    font-size: var(--text-xs);
    font-weight: 650;
    color: var(--blue-700);
}
.cyclescope__more > summary::-webkit-details-marker { display: none; }
.cyclescope__more > summary::after { content: " ▾"; }
.cyclescope__more[open] > summary::after { content: " ▴"; }

.cyclescope__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.cyclescope__list a {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--ink-2);
    text-decoration: none;
    font-size: var(--text-xs);
    font-weight: 600;
}
.cyclescope__list a:hover { border-color: var(--blue-600); color: var(--blue-700); }

/*  Earlier cycles on the overview, folded. The figures above are this cycle's;
    these are everything before it, kept reachable but out of the way. */
.pastcycles { margin-top: var(--space-4); }
.pastcycles > summary {
    list-style: none;
    cursor: pointer;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}
.pastcycles > summary::-webkit-details-marker { display: none; }
.pastcycles > summary::after { content: " ▾"; }
.pastcycles[open] > summary::after { content: " ▴"; }
.pastcycles__grid {
    display: grid;
    gap: var(--space-3);
    margin-top: var(--space-3);
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    opacity: .8;
}
