:root {
  color-scheme: light;
  --bg: #f6f8fb; --panel: #ffffff; --ink: #172033; --dim: #526071;
  --line: #d7dee8; --accent: #1d4ed8; --accent-soft: #e8f0ff;
  --on-accent: #ffffff; --ok: #087443; --ok-bg: #e9f9ef; --on-ok: #ffffff;
  --warn: #94500b; --warn-bg: #fff4df; --bad: #b42318; --bad-bg: #fff0ef;
  --neutral-bg: #edf1f6; --evidence-bg: #fff4b8; --evidence-line: #946200;
  --tooltip-bg: #172033; --tooltip-ink: #ffffff;
  --trace-source: var(--accent);
  --trace-category: var(--accent);
  --topbar-height: 53px; --bottombar-height: 60px;
  --code-keyword: #cf222e; --code-string: #0a3069; --code-comment: #6e7781;
  --code-constant: #0550ae; --code-function: #8250df; --code-class: #953800;
  --code-tag: #116329;
  --heat-0-bg: #ffe7e4; --heat-0-line: #d85e57;
  --heat-1-bg: #fff0cc; --heat-1-line: #c77a19;
  --heat-2-bg: #edf3c2; --heat-2-line: #82952f;
  --heat-3-bg: #dff4e8; --heat-3-line: #2f9967;
  --theory: #6941c6; --pdf-bg: #e4e7ec; --pdf-frame-bg: #d0d5dd;
  --floating-shadow: rgba(16, 24, 40, .18);
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    color-scheme: dark;
    --bg: #0f141b; --panel: #161d27; --ink: #e6ebf2; --dim: #a6b0c0;
    --line: #344154; --accent: #79b8ff; --accent-soft: #193554;
    --on-accent: #07111f; --ok: #5dde91; --ok-bg: #11291b; --on-ok: #07130c;
    --warn: #f7c75b; --warn-bg: #30250e; --bad: #ff8a85; --bad-bg: #321718;
    --neutral-bg: #202a37; --evidence-bg: #3c3408; --evidence-line: #f5cd47;
    --tooltip-bg: #eef2f7; --tooltip-ink: #111827;
    --heat-0-bg: #381b1d; --heat-0-line: #ff8a85;
    --heat-1-bg: #33260f; --heat-1-line: #f7c75b;
    --heat-2-bg: #293117; --heat-2-line: #c7d66d;
    --heat-3-bg: #123122; --heat-3-line: #5dde91;
    --theory: #c4b5fd; --pdf-bg: #40464f; --pdf-frame-bg: #525860;
    --floating-shadow: rgba(0, 0, 0, .42);
    --code-keyword: #ff7b72; --code-string: #a5d6ff; --code-comment: #8b949e;
    --code-constant: #79c0ff; --code-function: #d2a8ff; --code-class: #ffa657;
    --code-tag: #7ee787;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --code-keyword: #ff7b72; --code-string: #a5d6ff; --code-comment: #8b949e;
  --code-constant: #79c0ff; --code-function: #d2a8ff; --code-class: #ffa657;
  --code-tag: #7ee787;
  --bg: #0f141b; --panel: #161d27; --ink: #e6ebf2; --dim: #a6b0c0;
  --line: #344154; --accent: #79b8ff; --accent-soft: #193554;
  --on-accent: #07111f; --ok: #5dde91; --ok-bg: #11291b; --on-ok: #07130c;
  --warn: #f7c75b; --warn-bg: #30250e; --bad: #ff8a85; --bad-bg: #321718;
  --neutral-bg: #202a37; --evidence-bg: #3c3408; --evidence-line: #f5cd47;
  --tooltip-bg: #eef2f7; --tooltip-ink: #111827;
  --heat-0-bg: #381b1d; --heat-0-line: #ff8a85;
  --heat-1-bg: #33260f; --heat-1-line: #f7c75b;
  --heat-2-bg: #293117; --heat-2-line: #c7d66d;
  --heat-3-bg: #123122; --heat-3-line: #5dde91;
  --theory: #c4b5fd; --pdf-bg: #40464f; --pdf-frame-bg: #525860;
  --floating-shadow: rgba(0, 0, 0, .42);
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 15px/1.55 -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}
::selection { background: var(--accent-soft); color: var(--ink); }
input::placeholder, textarea::placeholder { color: var(--dim); opacity: 1; }
button, input, select, textarea { font: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wrap { max-width: 1540px; margin: 0 auto; padding: 0 20px; }
/* Every page gets the same gap under the bar, whatever it opens with. It used
   to come from the top margin of a leading <h1>, so a page whose first element
   was a card — the harvest run — started flush against the topbar. */
main.wrap { padding-top: 22px; }
main.wrap > :first-child { margin-top: 0; }
main.wrap > .message-list:first-child + * { margin-top: 0; }
/* The attribute has to beat the button system. ``.btn`` sets
   ``display: inline-block``, and an author class outranks the user agent's
   ``[hidden] { display: none }`` — so every control in this build that is a
   button *and* starts hidden was showing anyway, which is why the library's
   removal button appeared with nothing selected. */
[hidden] { display: none !important; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: var(--mono); font-size: 0.86em; background: var(--neutral-bg);
       padding: 1px 5px; border-radius: 4px; }
pre { background: var(--neutral-bg); padding: 12px 14px; border-radius: 8px;
      overflow-x: auto; font-family: var(--mono); font-size: 0.86em; }
pre code { background: none; padding: 0; }
/* Code in a lesson, coloured as GitHub colours it: Pygments marks the tokens
   (pymdownx.highlight, in the server's render) and these give them the
   palette of the theme in use. A block that names no language is left plain:
   guessing one coloured prose as code. Each block carries a button that copies
   it, added by the resource page's script. */
.highlight { position: relative; }
.highlight .k, .highlight .kd, .highlight .kn, .highlight .kp, .highlight .kr,
.highlight .kt, .highlight .o, .highlight .ow, .highlight .cp { color: var(--code-keyword); }
.highlight .kc, .highlight .m, .highlight .mb, .highlight .mf, .highlight .mh,
.highlight .mi, .highlight .mo, .highlight .il, .highlight .se, .highlight .na,
.highlight .nb, .highlight .bp, .highlight .nv, .highlight .vc, .highlight .vg,
.highlight .vi, .highlight .vm { color: var(--code-constant); }
.highlight .s, .highlight .s1, .highlight .s2, .highlight .sa, .highlight .sb,
.highlight .sc, .highlight .sd, .highlight .dl, .highlight .sh, .highlight .si,
.highlight .sr, .highlight .ss, .highlight .sx { color: var(--code-string); }
.highlight .c, .highlight .c1, .highlight .ch, .highlight .cm, .highlight .cpf,
.highlight .cs { color: var(--code-comment); }
.highlight .nf, .highlight .fm, .highlight .nd { color: var(--code-function); }
.highlight .nc, .highlight .ne { color: var(--code-class); }
.highlight .nt, .highlight .gi { color: var(--code-tag); }
.highlight .gd { color: var(--bad); }
.highlight .ge { font-style: italic; }
.highlight .gs { font-weight: 700; }
.code-copy { opacity: 0; position: absolute; right: 8px; top: 8px;
             transition: opacity .15s ease; }
.highlight:hover .code-copy, .code-copy:focus-visible, .code-copy.is-done { opacity: 1; }
@media (hover: none) { .code-copy { opacity: 1; } }

.topbar { background: var(--panel); border-bottom: 1px solid var(--line);
          position: sticky; top: 0; z-index: 50; }
.topbar .wrap { display: flex; align-items: center; gap: 10px; width: 100%;
                max-width: none; height: 52px; flex-wrap: nowrap; }
.brand { flex: 0 0 auto; font-weight: 700; letter-spacing: 0.2px; color: var(--ink);
         white-space: nowrap; }
.brand:hover { text-decoration: none; }
.brand .accent { color: var(--accent); }
.topbar nav { display: flex; flex: 0 1 auto; min-width: 0; gap: 2px; align-items: center;
              flex-wrap: nowrap; overflow: visible; }
.nav-menu { flex: 0 0 auto; position: relative; }
.nav-menu > summary { align-items: center; border-radius: 7px; color: var(--ink); cursor: pointer;
                      display: flex; list-style: none; padding: 6px 8px; transition: background .12s;
                      white-space: nowrap; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::marker { content: ""; }
.nav-menu > summary:hover, .nav-menu > summary.active, .nav-menu[open] > summary {
  background: var(--accent-soft);
}
.nav-menu > summary .ico { opacity: .82; }
.nav-menu > summary .nav-chevron { height: 10px; margin: 0 0 0 6px; transition: transform .15s;
                                   width: 10px; }
.nav-menu[open] > summary .nav-chevron { transform: rotate(180deg); }
.nav-menu-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
                  box-shadow: 0 10px 28px var(--floating-shadow); display: grid; gap: 2px;
                  left: 0; min-width: 270px; padding: 7px; position: absolute;
                  top: calc(100% + 7px); z-index: 60; }
.nav-menu-end .nav-menu-panel { left: auto; right: 0; }
.nav-menu-heading { color: var(--dim); font-size: 10.5px; font-weight: 700;
                    letter-spacing: .08em; padding: 3px 9px 5px; text-transform: uppercase; }
.nav-menu-section-label { border-top: 1px solid var(--line); color: var(--dim);
                          font-size: 9px; font-weight: 800; letter-spacing: .09em;
                          margin: 4px 7px 0; padding: 8px 2px 2px;
                          text-transform: uppercase; }
.nav-menu-heading + .nav-menu-section-label { border-top: 0; margin-top: 0; padding-top: 2px; }
.topbar nav a { flex: 0 0 auto; padding: 6px 8px; border-radius: 6px; color: var(--ink);
                white-space: nowrap; transition: background 0.12s; }
.topbar nav .nav-primary-link { align-items: center; display: flex; min-height: 32px; }
.nav-menu-panel a { align-items: flex-start; display: flex; gap: 3px; min-height: 42px;
                    padding: 7px 9px; }
.nav-menu-panel a > .ico { flex: 0 0 auto; height: 16px; margin-top: 3px; width: 16px; }
.nav-menu-item-copy { display: grid; gap: 1px; line-height: 1.25; }
.nav-menu-item-copy strong { font-size: 12px; font-weight: 680; }
.nav-menu-item-copy small { color: var(--dim); font-size: 9.5px; font-weight: 450; }
.nav-menu-panel a.active .nav-menu-item-copy small { color: color-mix(in srgb, var(--accent) 70%, var(--dim)); }
.topbar nav a.active, .topbar nav a:hover { background: var(--accent-soft); text-decoration: none; }
.topbar nav a.active { color: var(--accent); font-weight: 650; }
svg.ico { width: 14px; height: 14px; fill: currentColor; vertical-align: -2px;
          margin-right: 5px; }
.topbar nav svg.ico { opacity: 0.8; }
.account-dropdown > summary { border: 1px solid var(--line); min-height: 34px; }
.account-dropdown > summary:hover, .account-dropdown[open] > summary {
  border-color: var(--accent);
}
.account-icon { height: 16px; width: 16px; }
.account-name { max-width: 110px; overflow: hidden; text-overflow: ellipsis; }
.account-dropdown-panel { min-width: 220px; }
.account-action { align-items: center; background: transparent; border: 0; border-radius: 6px;
                  color: var(--ink); cursor: pointer; display: flex; min-height: 36px;
                  padding: 7px 9px; text-align: left; width: 100%; }
.account-action:hover { background: var(--accent-soft); }
.account-action .ico { flex: 0 0 auto; margin-right: 8px; }
.theme-toggle { align-items: center; background: var(--panel); border: 1px solid var(--line);
  border-radius: 8px; color: var(--ink); cursor: pointer; display: inline-flex;
  flex: 0 0 auto; height: 34px; justify-content: center; padding: 0; width: 34px; }
.theme-toggle:hover { border-color: var(--accent); background: var(--accent-soft); }
.theme-toggle .ico { margin: 0; width: 15px; height: 15px; }
.account-dropdown .theme-toggle { border: 0; height: auto; justify-content: flex-start;
                                  padding: 7px 9px; width: 100%; }
.account-dropdown .theme-toggle .ico { margin-right: 8px; }
.theme-icon-dark { display: none; }
:root[data-theme="light"] .theme-icon-dark,
:root[data-theme="dark"] .theme-icon-light { display: none; }
:root[data-theme="dark"] .theme-icon-dark { display: inline-block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-icon-light { display: none; }
  :root:not([data-theme]) .theme-icon-dark { display: inline-block; }
}
.qsearch { flex: 0 1 180px; min-width: 120px; margin-left: auto; }
.qsearch input { background: var(--bg); color: var(--ink); border: 1px solid var(--line);
                 border-radius: 999px; padding: 6px 14px; font-size: 13px; width: 100%;
                 transition: border-color 0.15s; }
.qsearch input:focus-visible { border-color: var(--accent); outline: 2px solid var(--accent-soft); }

h1 { font-size: 22px; margin: 22px 0 14px; }
h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em;
     color: var(--dim); margin: 0 0 10px; }
.dim { color: var(--dim); }
.foot { color: var(--dim); font-size: 12.5px; padding: 26px 20px; }

/* Grounded OER authoring playground */
#author-focus-starter-list { display: grid; gap: 5px; }
#author-focus-starter-list button { background: transparent; border: 1px dashed var(--line); border-radius: 6px;
                                    color: var(--dim); cursor: pointer; font-size: 10.5px; line-height: 1.4;
                                    padding: 6px 8px; text-align: left; }
#author-focus-starter-list button:hover, #author-focus-starter-list button:focus-visible {
  background: var(--panel); border-color: var(--accent); color: var(--ink); }
@keyframes author-spin {
  from { transform: rotate(0turn); }
  to { transform: rotate(1turn); }
}
/* A label rather than a rule: three dashed separators in a card the height of
   a paragraph made every issue look like a form to fill in. */
#author-audit-details { background: color-mix(in srgb, var(--panel) 62%, transparent); color: var(--ink);
                        line-height: 1.45; max-height: 330px; overflow: auto; padding: 11px 14px; }
#author-audit-details ul { margin: 0; padding-left: 21px; }
#author-audit-details li + li { margin-top: 6px; }
/* Evidence is selected in a workbench, not in an expanding checklist. Each
   pane keeps its own place while the educator moves between candidates. */
#author-passage-filter { background: var(--panel); border: 1px solid var(--line); border-radius: 7px;
                         font-size: 10.5px; margin-bottom: 7px; padding: 7px 8px; width: 100%; }
#author-restore-suggestion { flex: none; font-size: 9.5px; margin-top: 8px; padding: 5px 7px; width: 100%; }

/* ---- Source manifest --------------------------------------------------- */

/* ---- Version pathway -------------------------------------------------- */
/* A preview, not the diff itself — the draft carries that, marked in place.
   Four blocks, clipped, with a label instead of a strikethrough: a whole
   paragraph struck out is unreadable exactly where reading matters. */

.card { background: var(--panel); border: 1px solid var(--line);
        border-radius: 10px; padding: 16px 18px; margin-bottom: 16px; }

/* A grid rather than a flex row: four figures used to hug the left edge and
   leave two thirds of a wide screen empty, which read as a page that had not
   finished loading. */
.stat-row { display: grid; gap: 12px; margin: 14px 0 20px;
            grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
        padding: 10px 18px; min-width: 120px; }
.stat-n { font-size: 22px; font-weight: 700; }
.stat-l { color: var(--dim); font-size: 12.5px; }

.bar-row { display: grid; grid-template-columns: 150px 1fr 40px; gap: 10px;
           align-items: center; margin: 6px 0; font-size: 13.5px; }
.bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-track { background: var(--neutral-bg); border-radius: 4px; height: 10px; }
.bar { display: block; background: var(--accent); height: 10px; border-radius: 4px; }
.bar-n { text-align: right; color: var(--dim); }

table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
table.full { display: block; overflow-x: auto; }
/* The harvest list: what each run searched for, and a filter over it. The table
   is full width inside its own scroller rather than a block that shrinks to
   its content and left the list a third of the card. */
/* Its controls are the library's: ``filters`` styles them, and this only lays
   them out in a row. */
.filters.runs-filters { align-items: end; display: grid; gap: 12px;
                        grid-template-columns: minmax(220px, 2fr) minmax(220px, 2fr)
                                               repeat(2, minmax(130px, 1fr)) auto; }
.runs-filters input[type=search], .runs-filters select { height: 36px; width: 100%; }
.runs-filters-actions { align-items: center; display: flex; gap: 10px; height: 36px; }
.runs-count { margin: 0 0 10px; }
.runs-table-wrap { overflow-x: auto; }
.runs-table { width: 100%; }
.runs-plan { align-items: center; display: flex; flex-wrap: wrap; gap: 4px 6px; }
.runs-plan-kind { color: var(--dim); font-size: 10.5px; font-weight: 700; letter-spacing: 0.04em;
                  text-transform: uppercase; }
.runs-competency { background: var(--accent-soft); border-radius: 3px; color: var(--accent);
                   font: 650 11.5px var(--mono); padding: 1px 6px; }
.runs-competency:hover { text-decoration: underline; }
.runs-competency-name { font-size: 12.5px; }
@media (max-width: 960px) { .filters.runs-filters { grid-template-columns: 1fr 1fr; } }
th { text-align: left; color: var(--dim); font-weight: 600; }
th, td { padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: none; }
.row-drop { opacity: 0.62; }
.note-cell { max-width: 360px; }

.badge { display: inline-block; padding: 2px 6px; border-radius: 3px;
         font-size: 10.5px; font-weight: 700; letter-spacing: 0.045em; }
.v-OPEN { background: var(--ok-bg); color: var(--ok); }
.v-SHARE_ALIKE { background: var(--accent-soft); color: var(--accent); }
.v-OPEN_NC { background: var(--warn-bg); color: var(--warn); }
.v-RESTRICTED, .v-UNKNOWN { background: var(--bad-bg); color: var(--bad); }
.b-meta { background: var(--neutral-bg); color: var(--dim); }
.pill { display: inline-block; background: var(--neutral-bg); color: var(--dim);
        border-radius: 3px; padding: 2px 7px; font-size: 11px; }

.filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.filters input[type=search] { flex: 1 1 220px; }
.filters input, .filters select, .filters button {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 7px 10px; font-size: 13.5px; }
/* Only buttons that are not part of the button system. This used to catch every
   button inside any ``.filters`` block and repaint it as a primary action —
   which is why the library's removal control and the run page's "Delete this
   harvest" were both solid accent blue however they were classed. A blanket
   element rule beats a single class, so the system could not win. */
.filters button:not(.btn) { cursor: pointer; background: var(--accent);
                            color: var(--on-accent); border: none; }
.filters[aria-busy="true"] { opacity: 0.72; pointer-events: none; }
.filters a.active { font-weight: 700; }
.corpus-filters { background: transparent; border: 0; box-shadow: none; display: grid;
                  gap: 16px; margin: 8px 0 20px; padding: 0; }
.library-search-panel { background: var(--panel); border: 1px solid var(--line);
                        border-radius: 12px; padding: 18px; }
.library-search-heading { align-items: start; display: flex; gap: 18px;
                          justify-content: space-between; }
.library-search-heading > div { display: grid; gap: 2px; }
.library-search-eyebrow { color: var(--accent); font-size: 9.5px; font-weight: 800;
                          letter-spacing: .09em; text-transform: uppercase; }
.library-search-label { display: block; font-size: 18px; font-weight: 760;
                        letter-spacing: -.015em; }
.library-search-heading p { color: var(--dim); font-size: 11.5px; margin: 0; }
.library-search-tip { color: var(--dim); flex: none; font-size: 10.5px; padding-top: 4px; }
.library-search-tip kbd { margin-right: 3px; }
.library-search-row { align-items: stretch; display: flex; gap: 8px; }
.library-search-heading + .library-search-row { margin-top: 13px; }
.library-query-field { flex: 1 1 auto; min-width: 0; position: relative; }
.library-query-field > .ico { color: var(--dim); height: 19px; left: 14px; pointer-events: none;
                              position: absolute; top: 50%; transform: translateY(-50%); width: 19px; }
.filters .library-query-field input[type=search] { background: var(--panel); border-color: color-mix(in srgb, var(--accent) 32%, var(--line));
                                                   border-radius: 9px; font-size: 15px; min-height: 48px;
                                                   padding: 10px 78px 10px 42px; width: 100%; }
.filters .library-query-field input[type=search]::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none;
}
.filters .library-query-field input[type=search]::-ms-clear { display: none; }
.filters .library-query-field input[type=search]:focus { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); outline: none; }
.filters .library-query-clear { background: transparent; border: 0; color: var(--dim); font-size: 22px;
                                height: 30px; line-height: 1; min-width: 30px; padding: 0;
                                position: absolute; right: 34px; top: 9px; }
.filters .library-query-clear:hover { color: var(--ink); }
.library-search-shortcut { pointer-events: none; position: absolute; right: 10px; top: 13px; }
.filters .library-search-submit { border-radius: 9px; font-size: 14px; font-weight: 750;
                                  min-width: 104px; padding: 0 20px; }
.library-search-guidance { color: var(--dim); font-size: 11px; margin-top: 8px; }
.library-examples { align-items: center; display: flex; flex-wrap: wrap; gap: 5px; }
.library-examples[hidden] { display: none; }
.library-examples > span { color: var(--dim); font-size: 9.5px; font-weight: 750;
                           letter-spacing: .055em; margin-right: 3px; text-transform: uppercase; }
.library-examples a { background: var(--panel); border: 1px solid var(--line); border-radius: 4px;
                      color: var(--dim); padding: 2px 8px; text-decoration: none; }
.library-examples a:hover { border-color: var(--accent); color: var(--accent); }
.library-browser { align-items: start; display: grid; gap: 18px;
                   grid-template-columns: 310px minmax(0, 1fr); }
/* The column sticks under the bar and is as tall as the window below it. The
   search stays at its top; the filters scroll on their own inside their card,
   between its heading and the button that applies them, so every filter is in
   reach and applying is never a scroll away. A first version capped the whole
   column and scrolled it — two scrollbars, and a card cut off at the top once
   it had been scrolled — and a second rode up with the page, so the filters
   scrolled away with the results. Only the list scrolls now, inside edges that
   never move. The page's script sets --sidebar-top to where the column starts
   in the window, so before the page is scrolled it still ends at the window's
   bottom with its button in view; without the script it is cut there until it
   sticks. Below 1080 px the column sits above the results, and only the page
   scrolls. */
.library-sidebar { align-self: start; display: flex; flex-direction: column; gap: 12px;
                   height: calc(100vh - var(--sidebar-top, calc(var(--topbar-height) + 16px))
                            - 16px);
                   inset-block-start: calc(var(--topbar-height) + 16px); min-width: 0;
                   position: sticky; }
.library-sidebar > .library-search-panel { flex: none; }
.library-sidebar .library-search-panel { box-shadow: none; padding: 15px; }
.library-sidebar .library-search-heading { display: block; }
.library-sidebar .library-search-label { font-size: 15px; line-height: 1.3; }
.library-sidebar .library-search-heading p { font-size: 10.5px; line-height: 1.4;
                                             margin-top: 3px; }
.library-sidebar .library-search-tip { display: none; }
.library-sidebar .library-search-row { align-items: stretch; flex-direction: column; }
.library-sidebar .filters .library-query-field input[type=search],
.filters .library-sidebar .library-query-field input[type=search] {
  font-size: 12.5px; min-height: 44px; padding-left: 38px; padding-right: 62px;
}
.library-sidebar .library-query-field > .ico { height: 17px; left: 12px; width: 17px; }
.library-sidebar .library-search-shortcut { top: 11px; }
.library-sidebar .filters .library-query-clear,
.filters .library-sidebar .library-query-clear { top: 7px; }
.library-sidebar .library-search-submit { min-height: 40px; width: 100%; }
.library-sidebar .library-search-guidance { margin-top: 10px; }
/* The examples wrap as chips: one a line, they took three lines of a column
   whose filters now share its height. */
.library-sidebar .library-examples { align-items: center; display: flex; flex-wrap: wrap; }
.library-sidebar .library-examples > span { flex-basis: 100%; margin-bottom: 1px; }
.library-sidebar .library-examples a { overflow: hidden; text-overflow: ellipsis;
                                       white-space: nowrap; }
.library-results-column { min-width: 0; }
.library-filter-panel { background: var(--panel); border: 1px solid var(--line);
                        border-radius: 12px; display: flex; flex: 1 1 auto;
                        flex-direction: column; min-height: 0; padding: 13px 13px 11px; }
.library-filter-body { flex: 1 1 auto; margin-right: -6px; min-height: 0; overflow-y: auto;
                       overscroll-behavior: contain; padding-right: 6px;
                       scrollbar-width: thin; }
.library-filter-foot { border-top: 1px solid var(--line); flex: none; margin-top: 10px;
                       padding-top: 10px; }
.library-filter-foot .btn { width: 100%; }
/* Three groups — where it came from, what it is, what is known — each a grid
   of two, a long select across both. The labels are the app's filter labels
   (.filter-control > span), small and upper-case, with what each one means on
   hover or focus; the controls are a size shorter than a form's. */
.corpus-filter-section { border: 0; margin: 0; min-width: 0; padding: 0; }
.corpus-filter-section + .corpus-filter-section { border-top: 1px solid var(--line);
                                                  margin-top: 12px; padding-top: 10px; }
/* A legend sits on its fieldset's border by default, breaking the rule; floated
   across the width it is a heading under it. */
.corpus-filter-section > legend { float: left; margin-bottom: 7px; padding: 0; width: 100%; }
.corpus-filter-grid { clear: both; display: grid; gap: 8px 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.corpus-filter-grid > .filter-wide { grid-column: 1 / -1; }
.library-filter-panel .filter-control select,
.library-filter-panel .filter-control input { font-size: 12.5px; height: 32px;
                                              padding: 4px 8px; width: 100%; }
.library-filter-panel .filter-check { font-size: 12px; }
/* A choice of several, as a dropdown with a search (static/multiselect.js):
   the button looks like the selects beside it, and the panel floats under it,
   wider than a column and lined up with the nearer edge of its group. With
   no script the select of several stays, at its own height. */
.library-filter-panel .filter-control select[multiple] { height: auto; }
.multi-select { display: grid; gap: 4px; min-width: 0; position: relative; }
.filters button.multi-select-toggle { align-items: center; background: var(--panel);
  border: 1px solid var(--line); border-radius: 7px; color: var(--ink); cursor: pointer;
  display: flex; font-size: 12.5px; gap: 6px; height: 32px; justify-content: space-between;
  min-width: 0; padding: 4px 8px; text-align: left; width: 100%; }
.filters button.multi-select-toggle:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.filters button.multi-select-toggle[aria-expanded="true"] { border-color: var(--accent);
  outline: 2px solid var(--accent-soft); }
.multi-select-value { color: var(--dim); min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.multi-select.has-value .multi-select-value { color: var(--ink); font-weight: 650; }
.multi-select-toggle .ico { color: var(--dim); flex: none; height: 11px; width: 11px; }
.multi-select-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 9px;
  box-shadow: 0 10px 26px var(--floating-shadow); display: grid; gap: 6px; left: 0; padding: 7px;
  position: absolute; top: calc(100% + 4px); width: max(100%, 268px); z-index: 30; }
.multi-select.opens-left .multi-select-panel { left: auto; right: 0; }
.filters input.multi-select-search { font-size: 12px; height: 30px; padding: 4px 8px; width: 100%; }
.multi-select-options { display: grid; gap: 1px; max-height: 232px; overflow-y: auto;
  overscroll-behavior: contain; scrollbar-width: thin; }
.multi-select-option { align-items: center; border-radius: 6px; color: var(--ink); cursor: pointer;
  display: grid; font-size: 12.5px; gap: 7px; grid-template-columns: auto minmax(0, 1fr) auto;
  padding: 4px 6px; }
.multi-select-option:hover { background: var(--neutral-bg); }
.multi-select-option input { margin: 0; }
.multi-select-option span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.multi-select-option small { color: var(--dim); font: 600 11px var(--mono); }
.multi-select-none { color: var(--dim); font-size: 12px; margin: 2px 6px; }
.multi-select-foot { align-items: center; border-top: 1px solid var(--line); color: var(--dim);
  display: flex; font-size: 11px; justify-content: space-between; min-height: 30px; padding-top: 6px; }
.library-filter-head { align-items: center; display: flex; gap: 16px;
                       justify-content: space-between; margin-bottom: 12px; }
.library-filter-head > div { display: grid; gap: 1px; }
.library-filter-head strong { font-size: 13px; }
.library-filter-head span { color: var(--dim); font-size: 10.5px; }
.library-filter-head > a { color: var(--dim); font-size: 10.5px; }
.library-filter-head > a:hover { color: var(--accent); }
.filter-control { display: grid; gap: 4px; }
.filter-control > span { color: var(--dim); font-size: 9.5px; font-weight: 750;
                         letter-spacing: .065em; padding-left: 2px; text-transform: uppercase; }
.filter-control select { height: 36px; width: 100%; }
/* What a filter means is on its label's words, not on the control: a tip that
   opened over every dropdown the pointer crossed covered the next one down. The
   words keep their own width, so the empty space beside them says nothing. */
.filter-control > span[data-tip], .filter-check > span[data-tip] {
  cursor: help; justify-self: start; text-underline-offset: 3px;
  text-decoration: underline dotted color-mix(in srgb, var(--dim) 55%, transparent); }

.library-results-head { align-items: end; display: flex; justify-content: space-between;
                        margin: 0 0 10px; min-height: 49px; }
.library-results-eyebrow { color: var(--accent); font-size: 10px; font-weight: 800;
                           letter-spacing: .09em; text-transform: uppercase; }
.library-results-head h2 { color: var(--ink); font-size: 19px; letter-spacing: -.015em;
                           margin: 2px 0 0; text-transform: none; }
.library-results-head p { color: var(--dim); font-size: 11.5px; margin: 3px 0 0; }

.oer-list { display: flex; flex-direction: column; gap: 12px; }
/* Border and background only. A panel that sits in the page is not floating
   above it, and a drop shadow on every card is what makes a dense screen read as
   a pile rather than a list. Shadows are kept for the things that genuinely do
   float — menus, tooltips, the nav panel. */
.oer-item { background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
            color: var(--ink); overflow: hidden; transition: border-color .15s; }
.oer-item:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.oer-card-head { align-items: start; display: grid; gap: 18px;
                 grid-template-columns: minmax(0, 1fr) auto; padding: 15px 18px 6px; }
.oer-card-heading { min-width: 0; }
/* What it is, in one line of words and dots above the title. */
.oer-card-kicker { align-items: center; color: var(--dim); display: flex; flex-wrap: wrap;
                   font-size: 11.5px; gap: 2px 0; margin-bottom: 4px; }
.oer-card-kicker > * + *::before { color: var(--line); content: "·"; margin: 0 8px; text-decoration: none;
  display: inline-block; }
.oer-source { color: var(--ink); font-size: 10.5px; font-weight: 750; letter-spacing: .06em;
  text-transform: uppercase; }
.oer-trait { color: var(--dim); }
.oer-trait[data-tip] { cursor: help; }
/* A value nobody declared: the inferred colour and a dotted line, no box. */
.oer-trait.is-inferred { color: var(--theory); }
.oer-trait.is-inferred, .oer-provenance.is-inferred { text-decoration: underline dotted;
  text-decoration-color: color-mix(in srgb, var(--theory) 60%, transparent); text-underline-offset: 3px; }
.oer-container { font-family: var(--mono); font-size: 11px; }
.oer-title { color: var(--ink); display: -webkit-box; font-size: 17px; font-weight: 700;
             line-clamp: 2; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
             line-height: 1.32; overflow: hidden; }
.oer-card-state { align-items: center; display: flex; flex-wrap: wrap; gap: 6px;
                  justify-content: flex-end; padding-top: 1px; }
.oer-item > .oer-desc { color: var(--dim); display: -webkit-box; font-size: 12.5px;
                        line-clamp: 2; -webkit-box-orient: vertical;
                        -webkit-line-clamp: 2; line-height: 1.5; margin: 0 0 12px;
                        max-width: 1160px; overflow: hidden; padding: 0 18px; }
.oer-provenance { color: var(--dim); cursor: help; font-size: 10px; font-weight: 750; letter-spacing: .06em;
  margin-right: 8px; text-transform: uppercase; }
.oer-provenance.is-inferred { color: var(--theory); }
/* The facts at the foot, one line with an icon each and no rules between them. */
.oer-card-foot { align-items: center; border-top: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
  color: var(--dim); display: flex; flex-wrap: wrap; font-size: 11.5px; gap: 6px 22px; padding: 9px 18px 10px; }
.oer-fact { align-items: center; display: inline-flex; gap: 6px; min-width: 0; }
.oer-fact .ico { color: var(--dim); flex: 0 0 auto; height: 13px; opacity: .8; width: 13px; }
.oer-fact:first-child { color: var(--ink); font-weight: 600; }
.oer-proof { color: var(--ok); font-weight: 600; }
.oer-proof.is-missing { color: var(--warn); }
.oer-run { font-family: var(--mono); font-size: 11px; }
.library-empty { padding: 38px 24px; text-align: center; }
.library-empty > .ico { color: var(--accent); height: 28px; width: 28px; }
.library-empty h2 { font-size: 18px; margin: 8px 0 3px; }
.library-empty p { color: var(--dim); margin: 0; }
.library-empty small { color: var(--dim); }
.license-proof { display: inline-flex; align-items: center; width: fit-content;
                 border: 1px solid; border-radius: 3px; padding: 1px 7px;
                 font-size: 10.5px; line-height: 1.45; font-weight: 650; }
.license-proof.captured { color: var(--ok); background: var(--ok-bg);
                          border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); }
.license-proof.missing { color: var(--warn); background: var(--warn-bg);
                         border-color: color-mix(in srgb, var(--warn) 45%, var(--line)); }
.license-evidence { margin: 12px 0; padding: 14px; border: 1px solid;
                    border-radius: 10px; font-size: 12.5px; overflow-wrap: anywhere; }
.license-evidence h3 { margin: 0; font-size: 14px; }
.license-evidence.captured { border-color: color-mix(in srgb, var(--ok) 42%, var(--line));
                             background: var(--ok-bg); }
.license-evidence.missing { border-color: color-mix(in srgb, var(--warn) 48%, var(--line));
                            background: var(--warn-bg); }
.license-evidence p { margin: 4px 0 8px; }
.license-observed { background: color-mix(in srgb, var(--panel) 72%, transparent);
                    border: 1px solid var(--line); border-radius: 8px; padding: 9px 10px;
                    display: grid; gap: 4px; margin-bottom: 12px; }
.license-observed code { width: fit-content; font-size: 14px; }
.evidence-facts { display: grid; grid-template-columns: 116px minmax(0, 1fr);
                  gap: 8px 10px; margin: 0; }
.evidence-facts dt { color: var(--dim); font-weight: 600; }
.evidence-facts dd { margin: 0; min-width: 0; }
.evidence-responsibility { margin-top: 12px !important; line-height: 1.45; }
.evidence-links { display: grid; gap: 6px; margin-top: 11px; }
.evidence-method { margin-top: 11px; color: var(--dim); }
.evidence-method summary { cursor: pointer; }
.license-caveat { color: var(--warn); font-size: 11.5px; line-height: 1.45; }

@media (max-width: 1080px) {
  .library-browser { grid-template-columns: 1fr; }
  .library-sidebar { height: auto; position: static; }
  .library-filter-body { display: grid; gap: 14px; grid-template-columns: repeat(3, minmax(0, 1fr));
                         margin-right: 0; overflow: visible; padding-right: 0; }
  .corpus-filter-section + .corpus-filter-section { border-top: 0; margin-top: 0; padding-top: 0; }
  .library-sidebar .library-search-heading { display: flex; }
  .library-sidebar .library-search-label { font-size: 18px; }
  .library-sidebar .library-search-tip { display: inline; }
  .library-sidebar .library-search-row { flex-direction: row; }
  .library-sidebar .library-search-submit { width: auto; }
  .library-sidebar .library-examples { align-items: center; display: flex; }
  .library-sidebar .library-examples a { width: auto; }
}

@media (max-width: 900px) {
  .library-filter-body { grid-template-columns: 1fr; }
  .corpus-filter-section + .corpus-filter-section { border-top: 1px solid var(--line);
                                                    padding-top: 10px; }
  .oer-card-head { grid-template-columns: 1fr; gap: 8px; }
  .oer-card-state { justify-content: flex-start; }
  .oer-card-foot { gap: 6px 16px; }
}

@media (max-width: 560px) {
  .corpus-filters { padding: 0; }
  .library-search-panel { padding: 12px; }
  .library-sidebar .library-search-heading { display: block; }
  .library-sidebar .library-search-tip { display: none; }
  .library-sidebar .library-search-row { align-items: stretch; flex-direction: column; }
  .filters .library-search-submit { min-height: 42px; width: 100%; }
  .library-search-shortcut { display: none; }
  .filters .library-query-field input[type=search] { padding-right: 43px; }
  .filters .library-query-clear { right: 8px; }
  .library-search-guidance { align-items: flex-start; flex-direction: column; }
  .library-filter-panel { padding: 10px; }
  .oer-card-foot { align-items: flex-start; flex-direction: column; }
  .resource-type::before { display: none; }
}

.detail { display: grid; grid-template-columns: minmax(0, 1fr) minmax(410px, 450px); gap: 20px;
          align-items: start; margin-top: 8px; }
.detail > *, .meta { min-width: 0; }
@media (max-width: 1080px) { .detail { grid-template-columns: 1fr; } }
.resource-hero { display: grid; gap: 17px; grid-template-columns: minmax(0, 1fr);
                 padding: 22px 24px; }
.resource-hero-copy { min-width: 0; }
.resource-eyebrow { align-items: center; color: var(--dim); display: flex; flex-wrap: wrap;
                    font-size: 11px; font-weight: 700; gap: 7px; letter-spacing: .055em;
                    text-transform: uppercase; }
.resource-eyebrow .pill { color: var(--accent); letter-spacing: .035em; }
/* A facet in the eyebrow reads as it does on the card, not as the eyebrow's
   upper-case label: "component · inferred" is a value, not a heading. */
.resource-eyebrow .oer-facet { letter-spacing: normal; text-transform: none; }
.resource-hero h1 { font-size: clamp(21px, 2vw, 29px); letter-spacing: -.025em;
                    line-height: 1.22; margin: 9px 0 0; max-width: 1050px; }
/* Whose the line under a title is, when it is not the resource's own. */
.summary-source { border: 1px solid var(--line); border-radius: 3px; color: var(--dim);
                  cursor: help; font: 600 9.5px var(--mono); letter-spacing: .04em;
                  margin-right: 6px; padding: 1px 5px; text-transform: uppercase;
                  vertical-align: 1px; }
.summary-inferred { border-color: var(--theory); color: var(--theory); }
.resource-summary { color: var(--dim); display: -webkit-box; font-size: 13.5px; line-height: 1.5;
                    line-clamp: 2; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
                    margin: 8px 0 0; max-width: 1050px; overflow: hidden; }
.resource-facts { border-top: 1px solid var(--line); display: flex; flex-wrap: wrap;
                  gap: 10px 0; grid-column: 1 / -1; margin: 0; padding-top: 15px; }
.resource-facts > div { border-right: 1px solid var(--line); min-width: 130px;
                        padding: 0 20px; }
.resource-facts > div:first-child { padding-left: 0; }
.resource-facts > div:last-child { border-right: 0; }
.resource-facts dt { color: var(--dim); font-size: 9.5px; font-weight: 750;
                     letter-spacing: .07em; text-transform: uppercase; }
.resource-facts dd { align-items: center; display: flex; font-size: 13px; font-weight: 650;
                     gap: 6px; margin: 3px 0 0; }
/* How a resource is tied to the rest of the library, in its header below the
   facts: a
   component's lab, a lab's files, the index that lists a page, what a paper
   cites. The cards are the rail's own (.bundled-file-list), so a tie looks the
   same wherever it is shown, in one row that scrolls sideways a card at a time:
   three side by side showed a lab's first three files and hid the other three
   behind a button. The page buttons are the library's (.page-link). It used to
   be a fact in the row below, which wrapped and hid the lab among the licence
   and the authors. */
.resource-relations { border-top: 1px solid var(--line); display: grid; gap: 14px;
                      padding-top: 15px; }
.resource-relation { display: grid; gap: 8px; min-width: 0; }
.resource-relation-head { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; }
.resource-relation-head h2 { color: var(--ink); font-size: 13px; font-weight: 700;
                             letter-spacing: 0; margin: 0; }
.resource-relation-actions { align-items: center; display: flex; gap: 10px; margin-left: auto; }
.relation-carousel-controls { align-items: center; display: flex; gap: 4px; }
.relation-carousel-controls[hidden] { display: none; }
.relation-carousel-count { color: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums;
                           margin-right: 4px; white-space: nowrap; }
.relation-carousel-controls .page-link { cursor: pointer; font: inherit; font-size: 16px;
                                         height: 28px; line-height: 1; min-width: 28px;
                                         padding: 0 8px; }
.page-link:disabled { cursor: default; opacity: .45; }
.page-link:disabled:hover { border-color: var(--line); }
.resource-relation-shared { color: var(--dim); font-size: 11.5px; margin: -3px 0 0; }
.resource-relation .bundled-file-list {
  grid-auto-columns: minmax(min(250px, 85%), calc((100% - 16px) / 3)); grid-auto-flow: column;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  scrollbar-width: none; }
.resource-relation .bundled-file-list::-webkit-scrollbar { display: none; }
.resource-relation .bundled-file-list li { scroll-snap-align: start; }
.relation-file-name { font-family: var(--mono); overflow-wrap: anywhere; }
/* The rail's Related panel: one group a tie, the long ones folded. */
.related-group { display: grid; gap: 8px; margin-top: 16px; }
.related-group h3 { color: var(--ink); font-size: 12px; margin: 0; }
.related-more summary { color: var(--accent); cursor: pointer; font-size: 11px;
                        font-weight: 650; }
.related-more[open] summary { margin-bottom: 8px; }
.resource-detail-layout { display: grid; gap: 0; grid-template-columns: minmax(0, 1fr);
                          transition: grid-template-columns .2s ease, gap .2s ease; }
.resource-detail-layout.is-info-open { gap: 16px;
  grid-template-columns: minmax(520px, 1fr) minmax(420px, 500px); }
.resource-view-column { min-width: 0; }
.resource-info-rail { align-self: start; height: calc(100dvh - var(--topbar-height) - 16px);
                      inset-block-start: calc(var(--topbar-height) + 8px); min-width: 0;
                      position: sticky; }
.resource-info-shell { background: var(--panel); border: 1px solid var(--line); border-radius: 11px;
                       display: grid; height: 100%;
                       grid-template-rows: auto auto minmax(0, 1fr); overflow: hidden; }
.resource-info-head { align-items: flex-start; background: var(--panel); border-bottom: 1px solid var(--line);
                      display: flex; gap: 18px; justify-content: space-between; padding: 15px 16px 12px; }
.resource-info-kicker { color: var(--accent); font: 750 9.5px var(--mono); letter-spacing: .08em;
                        text-transform: uppercase; }
.resource-info-head h2 { color: var(--ink); font-size: 17px; letter-spacing: -.01em;
                         margin: 2px 0; text-transform: none; }
.resource-info-head p { color: var(--dim); font-size: 11.5px; line-height: 1.4; margin: 0; }
.resource-info-tabs { background: var(--neutral-bg); border-bottom: 1px solid var(--line); display: flex;
                      gap: 4px; overflow-x: auto; padding: 6px 10px 0; }
.resource-info-tab { align-items: center; background: transparent; border: 0;
                     border-bottom: 3px solid transparent; color: var(--dim);
                     cursor: pointer; display: inline-flex; flex: 0 0 auto; gap: 6px;
                     font-size: 11.5px; font-weight: 650; letter-spacing: .01em;
                     padding: 8px 10px 7px; white-space: nowrap; }
.resource-info-tab:hover { color: var(--ink); }
.resource-info-tab.active { border-bottom-color: var(--accent); color: var(--accent); }
/* A count on a tab sat on the same grey as the tab strip itself, so it read as
   a loose number rather than as a figure belonging to the tab. */
.resource-info-tab .badge { background: var(--panel); border: 1px solid var(--line);
                            border-radius: 999px; color: var(--dim);
                            font: 700 9.5px/1.5 var(--mono); padding: 1px 6px; }
.resource-info-tab.active .badge { border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
                                   color: var(--accent); }
.resource-info-body { min-height: 0; overflow-y: auto; padding: 0 16px 18px; }
.resource-info-panel { display: grid; grid-template-columns: minmax(0, 1fr); }
.resource-info-panel > .card { background: transparent; border: 0; border-bottom: 1px solid var(--line);
                               border-radius: 0; margin: 0; min-width: 0; padding: 17px 0; }
.resource-info-panel > .card:last-child { border-bottom: 0; }
.resource-info-panel dl { font-size: 13px; margin: 0; }
.resource-info-panel dt { clear: left; color: var(--dim); float: left; width: 96px; }
.resource-info-panel dd { margin: 0 0 6px 104px; overflow-wrap: anywhere; }
.resource-info-panel .evidence-facts { display: grid; }
.resource-info-panel .evidence-facts dt { clear: none; float: none; width: auto; }
.resource-info-panel .evidence-facts dd { margin: 0; overflow-wrap: normal; word-break: normal; }
#resource-info-processing, #resource-info-files { grid-template-columns: 1fr; }
.info-section-head { align-items: flex-start; display: flex; gap: 12px;
                     justify-content: space-between; margin-bottom: 14px; }
.info-section-head > div { min-width: 0; }
.info-section-kicker { color: var(--accent); display: block; font-size: 9.5px;
                       font-weight: 750; letter-spacing: .07em; margin-bottom: 3px;
                       text-transform: uppercase; }
.info-section-head h2 { color: var(--ink); font-size: 16px; letter-spacing: -.01em;
                        line-height: 1.25; margin: 0; text-transform: none; }
.info-section-head p { color: var(--dim); font-size: 11.5px; line-height: 1.45;
                       margin: 4px 0 0; }
.info-section-head > .pill, .info-section-head > .badge { flex: 0 0 auto; margin-top: 2px; }
.license-identity { align-items: center; background: var(--neutral-bg); border: 1px solid var(--line);
                    border-radius: 8px; display: flex; gap: 12px; justify-content: space-between;
                    margin-bottom: 10px; padding: 10px 11px; }
.license-identity > div { display: grid; gap: 2px; min-width: 0; }
.license-identity span { color: var(--dim); font-size: 9.5px; font-weight: 700;
                         letter-spacing: .055em; text-transform: uppercase; }
.license-identity strong { color: var(--ink); overflow-wrap: anywhere; }
.license-identity a { flex: 0 0 auto; font-size: 11px; }
.resource-info-rail .lic-plain { gap: 8px; margin: 0; }
.resource-info-rail .lic-plain > div { background: var(--bg); border: 1px solid var(--line);
                                      border-radius: 8px; display: grid; gap: 4px;
                                      padding: 10px 11px; }
.resource-info-rail .lic-plain > div > strong { font-size: 11.5px; margin-bottom: 2px; }
.license-evidence-disclosure { border: 1px solid var(--line);
  border-radius: 8px; margin-top: 10px; overflow: hidden; }
.license-evidence-disclosure > summary {
  align-items: center; cursor: pointer; display: flex; gap: 10px; justify-content: space-between;
  list-style: none; padding: 10px 11px; }
.license-evidence-disclosure > summary::-webkit-details-marker { display: none; }
.license-evidence-disclosure > summary::before { color: var(--accent); content: "›";
  flex: 0 0 auto; font-size: 19px; line-height: 1; transition: transform .15s ease; }
.license-evidence-disclosure[open] > summary::before { transform: rotate(90deg); }
.license-evidence-disclosure > summary > span:first-of-type { display: grid; gap: 1px;
  margin-right: auto; }
.license-evidence-disclosure summary strong { color: var(--ink); font-size: 12px; }
.license-evidence-disclosure summary small { color: var(--dim); font-size: 10.5px; }
.license-evidence-disclosure .license-evidence { border: 0; border-radius: 0;
                                                border-top: 1px solid var(--line); margin: 0; }
.bundled-file-list { display: grid; gap: 8px; list-style: none; margin: 0; padding: 0; }
.bundled-file-list li { align-items: center; border: 1px solid var(--line); border-radius: 8px;
                        display: grid; gap: 10px; grid-template-columns: 38px minmax(0, 1fr) auto;
                        padding: 9px 10px; }
.file-kind { align-items: center; background: var(--accent-soft); border-radius: 6px;
             color: var(--accent); display: flex; font: 750 9px var(--mono); height: 34px;
             justify-content: center; overflow: hidden; padding: 0 4px; text-align: center; }
.bundled-file-list li > div { display: grid; gap: 2px; min-width: 0; }
.bundled-file-list strong { color: var(--ink); font-size: 12px; overflow-wrap: anywhere; }
.bundled-file-list small { color: var(--dim); font-size: 10px; }
.bundled-file-list .btn { font-size: 10.5px; padding: 5px 8px; }

/* Local AI review methodology */
@media (max-width: 1200px) {
  .resource-detail-layout.is-info-open {
    grid-template-columns: minmax(440px, 1fr) minmax(360px, 420px);
  }
}
.doc-body { padding: 22px 28px; overflow-wrap: break-word; }
.content-page-nav { align-items: center; background: var(--neutral-bg); border: 1px solid var(--line);
                    border-radius: 9px; display: grid; gap: 12px;
                    grid-template-columns: minmax(190px, 1fr) minmax(190px, 360px) auto;
                    margin: 0 0 22px; padding: 11px 12px; }
.content-page-nav > div:first-child { display: grid; gap: 1px; }
.content-page-nav strong { font-size: 12px; }
.content-page-nav span { color: var(--dim); font-size: 10.5px; }
.content-page-nav select { background: var(--panel); border: 1px solid var(--line);
                           border-radius: 7px; color: var(--ink); min-width: 0;
                           padding: 7px 9px; width: 100%; }
.content-page-actions { display: flex; gap: 7px; justify-content: flex-end; }
.content-page-actions .btn { font-size: 11.5px; padding: 6px 10px; }
.content-page-nav-bottom { grid-template-columns: minmax(0, 1fr) auto; margin: 28px 0 0; }
.content-page-nav-bottom > span { align-self: center; font-weight: 700; }
.doc-body img { max-width: 100%; height: auto; }
.doc-body h1 { font-size: 24px; margin-top: 4px; }
.doc-body h2 { font-size: 19px; text-transform: none; letter-spacing: 0;
               color: var(--ink); margin: 22px 0 8px; }
.doc-body h3 { font-size: 16px; }
.doc-body blockquote { border-left: 3px solid var(--accent); margin: 10px 0;
                       padding: 2px 14px; color: var(--dim); background: var(--neutral-bg);
                       border-radius: 0 8px 8px 0; }
.doc-body table { display: block; overflow-x: auto; margin: 12px 0; }
.doc-body mjx-container[jax="SVG"][display="true"] {
  overflow-x: auto; overflow-y: hidden; padding: 6px 0; max-width: 100%;
}
.doc-body mjx-container[jax="SVG"] { color: var(--ink); }
.doc-body mjx-container svg { max-width: none; }
.doc-body sup { line-height: 0; }
.doc-body .footnote-backref { margin-left: 4px; }
@media (max-width: 760px) {
  .content-page-nav { align-items: stretch; grid-template-columns: 1fr; }
  .content-page-actions { justify-content: flex-start; }
  .content-page-nav-bottom { grid-template-columns: 1fr; }
}
.meta dl { margin: 0; font-size: 13.5px; }
.meta dt { color: var(--dim); float: left; clear: left; width: 96px; }
.meta dd { margin: 0 0 6px 104px; overflow-wrap: anywhere; }
.meta .evidence-facts dt { float: none; clear: none; width: auto; }
.meta .evidence-facts dd { margin: 0; overflow-wrap: normal; word-break: normal; }
.flags { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; }
.flags li { padding: 2px 0; }
.flags .ok::before { content: "✓ "; color: var(--ok); }
.flags .no::before { content: "✗ "; color: var(--bad); }

.empty { background: var(--panel); border: 1px dashed var(--line); border-radius: 10px;
         padding: 26px; color: var(--dim); }
a.plain { color: inherit; }

/* ---- harvest composer + live run ---- */
/* Three button weights and they mean three different things. Getting this wrong
   is not a matter of taste: a solid accent button is where the eye goes and the
   thumb follows, so anything that deletes must never wear it, and a control the
   page exists for must never look like an afterthought.
 *
 *   .btn-primary   the one thing this page is for. One per screen.
 *   .btn-danger    removes data. Outlined, never filled — a solid red beside a
 *                  solid blue is two targets that look equally inviting.
 *   .btn           everything else, including "stop", which keeps its work.
 *
 * Deletion was spread across all three before this: the library's bulk removal
 * wore the primary fill, the resource page's and the run page's wore the plain
 * one, and the only outlined-red control on the engine was Stop — the one
 * button here that destroys nothing. */
.btn { display: inline-block; border: 1px solid var(--line); background: var(--panel);
       color: var(--ink); border-radius: 8px; padding: 8px 16px; font-size: 14px;
       cursor: pointer; text-decoration: none; }
.btn:hover { border-color: var(--accent); text-decoration: none; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-danger { background: transparent; border-color: color-mix(in srgb, var(--bad) 45%, var(--line));
              color: var(--bad); }
.btn-danger:hover { background: var(--bad-bg); border-color: var(--bad); color: var(--bad); }
.btn-danger:disabled { background: transparent;
                       border-color: var(--line); color: var(--dim); }
.btn-danger:focus-visible { border-color: var(--bad);
                            outline-color: color-mix(in srgb, var(--bad) 55%, transparent); }

/* A checkbox and its label read as one control, which is the whole point of the
   class. It had no base rule at all — only variants scoped inside forms this
   build does not have — so wherever it was used outside one, the box and its
   text sat as two unrelated things with a space between them. */
.check-line { align-items: center; display: inline-flex; gap: 7px; cursor: pointer;
              font-size: 12.5px; color: var(--ink); }
.check-line input { flex: 0 0 auto; margin: 0; }
.btn-small { padding: 5px 9px; font-size: 11.5px; }
.btn-big { font-size: 15.5px; padding: 10px 26px; }

.composer { display: flex; gap: 8px; }
.composer select { flex: 0 0 130px; }
.composer input { flex: 1; }
.composer select, .composer input {
  background: var(--bg); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 11px; font-size: 14px; }
.hint { min-height: 1.2em; margin: 8px 2px 4px; }

.corpus-filter-group { color: var(--accent); font: 750 9.5px var(--mono);
                       letter-spacing: .08em; text-transform: uppercase; }
.filter-check { align-items: center; color: var(--ink); cursor: pointer; display: flex;
                font-size: 12.5px; gap: 7px; }
/* A card's type and objectives: neutral when declared, the inferred colour
   when the enrichment read them. */
.oer-facet { border: 1px solid var(--line); border-radius: 3px; color: var(--dim);
             cursor: help; font-size: 11px; padding: 0 6px; }
.oer-facet-inferred { border-color: var(--theory); color: var(--theory); }
.oer-facet-dataset { border-style: dashed; color: var(--ink); }
.oer-container { color: var(--dim); font: 11px var(--mono); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; min-height: 6px; }
.chip { display: inline-flex; align-items: center; gap: 7px; background: var(--accent-soft);
        color: var(--accent); border-radius: 3px; padding: 4px 9px; font-size: 13px;
        font-weight: 600; font-family: var(--mono); }
.chip button { all: unset; cursor: pointer; font-size: 15px; line-height: 1; opacity: 0.7; }
.chip button:hover { opacity: 1; }
.chip.static { font-weight: 500; }

.conn-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
             gap: 8px; margin-top: 14px; }

/* The one irreversible control on the page, and it used to be wherever the form
   happened to end — below the fold on a tall selection, so the thing you came to
   press was the thing you had to go looking for. ``margin-top: auto`` puts it on
   the floor of the stretched column and ``sticky`` keeps it on the floor of the
   window while everything above it scrolls. */
/* The navigation bar's mirror image: fixed to the bottom of the window, full
   bleed, always there. It is outside the form and reaches it through the submit
   button's ``form`` attribute, because a bar fixed to the viewport cannot also
   be a row inside a grid that scrolls. */
.bottombar { position: fixed; inset-inline: 0; bottom: 0; z-index: 50;
             background: var(--panel); border-top: 1px solid var(--line); }
/* Aligned with the page's own column, unlike the navigation bar above it: the
   nav is chrome and spans the window, this holds one control that belongs to the
   form it submits, and a button that does not line up with the column it acts on
   reads as part of the window rather than part of the page. */
.bottombar .wrap { display: flex; align-items: center; gap: 14px;
                   min-height: var(--bottombar-height); }
.launch-row { display: flex; align-items: center; gap: 14px; min-width: 0; }
.launch-row .dim { min-width: 0; overflow: hidden; text-overflow: ellipsis;
                   white-space: nowrap; }
.btn-quiet { border-color: transparent; background: transparent; color: var(--dim); }
.btn-quiet:hover { border-color: var(--line); color: var(--ink); }
.err { color: var(--bad); font-size: 13.5px; }

.pulse { display: inline-block; width: 11px; height: 11px; border-radius: 50%;
         background: var(--ok); animation: pulse 1.15s ease-in-out infinite; }
.pulse.off { animation: none; background: var(--dim); }
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); }
                   50% { opacity: 0.35; transform: scale(0.72); } }
.ok-n { color: var(--ok); }
.stat-n.tick { animation: tick 0.35s ease; }
@keyframes tick { 0% { transform: scale(1.18); } 100% { transform: scale(1); } }

.banner { border-radius: 9px; padding: 12px 16px; margin: 6px 0 16px; font-weight: 600; }
.b-ok { background: var(--ok-bg); color: var(--ok); }
.b-warn { background: var(--warn-bg); color: var(--warn); }
.b-bad { background: var(--bad-bg); color: var(--bad); }

.console-head { display: flex; justify-content: space-between; align-items: baseline; }
.console { background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
           height: 380px; overflow-y: auto; padding: 10px 12px;
           font-family: var(--mono); font-size: 12.5px; line-height: 1.65; }
.console-line { white-space: pre-wrap; overflow-wrap: anywhere; }

/* The disclosure is secondary to the match it belongs to: one accent-coloured
   line per row is enough, and an uppercase label on every row shouts. */
@keyframes evidence-inspector-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}
/* What an element with data-tip has to say, on hover or keyboard focus: one
   element, placed beside it by the script at the end of base.html. Title
   attributes did this before, late, unstyled and never on touch. */
.hover-tip { background: var(--tooltip-bg); border-radius: 7px;
  box-shadow: 0 7px 20px var(--floating-shadow); color: var(--tooltip-ink);
  font-size: 11.5px; font-weight: 450; line-height: 1.4; max-width: min(320px,
  calc(100vw - 16px)); overflow-wrap: anywhere; padding: 7px 10px; pointer-events: none;
  position: fixed; text-align: start; text-transform: none; white-space: normal;
  width: max-content; z-index: 150; }
.hover-tip[hidden] { display: none; }
.related { list-style: none; margin: 0; padding: 0; font-size: 13.5px; }
.related li { display: flex; justify-content: space-between; gap: 8px; padding: 3px 0; }

/* ---- review + metrics ---- */
.management-eyebrow { color: var(--accent); font-size: 9px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase; }

/* ---- UX pass: page heads, help, chips, shortcuts ---- */
.pagehead { margin: 22px 0 16px; }
.pagehead h1 { margin: 0 0 4px; }
.pagehead .purpose { margin: 0; color: var(--dim); max-width: 860px; }

details.help { display: inline-block; font-size: 12.5px; margin: 2px 0; }
details.help summary { cursor: pointer; color: var(--accent); list-style: none;
                       user-select: none; }
details.help summary::-webkit-details-marker { display: none; }

.chips-active { display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
                margin: -6px 0 12px; font-size: 12.5px; }
.chips-active .chip a { color: inherit; opacity: 0.7; margin-left: 5px;
                        text-decoration: none; }
.chips-active .chip a:hover { opacity: 1; }

.lic-plain { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 18px;
             font-size: 13.5px; margin-top: 8px; }
.lic-plain .ok::before { content: "✓ "; color: var(--ok); font-weight: 700; }
.lic-plain .no::before { content: "✗ "; color: var(--bad); font-weight: 700; }
.lic-plain .must::before { content: "! "; color: var(--warn); font-weight: 700; }

kbd { background: var(--neutral-bg); border: 1px solid var(--line);
      border-bottom-width: 2px; border-radius: 5px; padding: 1px 6px;
      font-family: var(--mono); font-size: 11.5px; }

.back-row { display: flex; align-items: center; justify-content: space-between;
            gap: 12px; margin: 18px 0 10px; }

.danger-zone { border-color: var(--bad); }
.danger-zone h2 { color: var(--bad); }
.wipe-opts { display: flex; flex-direction: column; gap: 8px; margin: 12px 0; }
.wipe-opts label { align-items: start; display: flex; font-size: 13.5px; gap: 9px; }
.wipe-opts label input { flex: 0 0 auto; margin-top: 3px; }
.wipe-opts label > span { min-width: 0; }
/* The explanation used to run on inline after the label, so the sentence saying
   what a tick does arrived in the middle of the sentence naming it. */
.wipe-opts label small { display: block; line-height: 1.45; margin-top: 3px;
                         max-width: 86ch; }
.wipe-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.wipe-row input { background: var(--bg); color: var(--ink); border: 1px solid var(--line);
                  min-width: 270px;
                  border-radius: 7px; padding: 8px 12px; width: 250px; }
.wipe-row input:focus-visible { border-color: var(--bad); outline: 2px solid var(--bad-bg); }
.btn-danger:disabled { opacity: 0.4; cursor: not-allowed; }
.l-spec { color: var(--accent); font-weight: 700; }
.l-gate { color: var(--accent); }
.l-ok { color: var(--ok); }
.l-warn { color: var(--warn); }
.l-bad { color: var(--bad); }
.l-dim { color: var(--dim); }

/* ---- workflow continuity + pagination ---- */

.pagination { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
              gap: 16px; margin: 18px 0 24px; color: var(--dim); font-size: 13px; }
.page-links { display: flex; align-items: center; justify-content: center; gap: 4px; }
.page-link { min-width: 34px; height: 34px; padding: 0 10px; border: 1px solid var(--line);
             background: var(--panel); color: var(--ink); border-radius: 7px;
             display: inline-flex; align-items: center; justify-content: center; }
.page-link:hover { border-color: var(--accent); text-decoration: none; }
.page-link.active { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.page-link.disabled { opacity: .45; cursor: default; }

/* ---- dedicated enrichment step ---- */
.stage { min-width: 130px; flex: 1; padding: 10px 14px; color: var(--dim);
         display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.stage:hover { text-decoration: none; background: var(--neutral-bg); }
.stage + .stage { border-left: 1px solid var(--line); }
.stage span { width: 23px; height: 23px; border: 1px solid var(--line); border-radius: 50%;
              display: inline-flex; align-items: center; justify-content: center; font-size: 11px; }
.stage.done span { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
.stage.current { color: var(--accent); background: var(--accent-soft); }
.stage.current span { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }

/* The catalogue's category filters, pills above its list. */
.heat-filters { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---- a card whose body is a searchable table: the catalogue, a run's rows ---- */

.table-card-head { display: flex; align-items: flex-end; justify-content: space-between;
                       gap: 18px; margin-bottom: 14px; }
.table-card-head h2 { margin-bottom: 4px; }
.table-card-head p { margin: 0; }
.table-card-search { flex: 0 1 390px; }
.table-card-search label { display: block; margin-bottom: 5px; color: var(--dim);
                               font-size: 12px; font-weight: 650; }
.table-card-search input{
  width: 100%; border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); color: var(--ink); padding: 8px 11px; font: inherit;
}
.table-card-search input:focus{
  border-color: var(--accent); outline: 2px solid var(--accent-soft);
}

/* The composer's two query modes. Radio cards rather than a select, because the
   choice changes which panel below is relevant and a curator should see both
   options while deciding. */
/* The composer: form on the left, the map and the preview beside it.
   A single column left most of the width empty on a wide screen and put the
   compiled strings a scroll away from the controls that change them. */
/* One workbench, one screen tall. Both columns take the row's height, so neither
   can end in a rounded corner halfway up the page while the other carries on
   past it — and the launch bar sits outside the part that scrolls, which is what
   keeps it visible without pinning it on top of the form.
 *
 * `position: sticky` was the first attempt and could not work: the bar is the
 * last thing in its column, so there is never any content below it to hold it
 * against, and it behaves as static the moment you reach it. */
/* The page owns the height, not the layout. Subtracting a guess at the header's
   height from the viewport is how the columns ended up sliding under the fixed
   bar: the guess was one heading and one paragraph out. Here the page is exactly
   one screen, its own head takes what it needs, the layout takes the rest, and
   the padding reserves the bar's strip so nothing can be covered by it. */
main.compose-page { display: flex; flex-direction: column;
                    height: calc(100dvh - var(--topbar-height));
                    padding-bottom: calc(var(--bottombar-height) + 16px); }
main.compose-page > .pagehead { flex: 0 0 auto; }
.compose-layout { flex: 1 1 auto; min-height: 0;
                  display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
                  align-items: stretch; gap: 16px; }
.compose-main { min-width: 0; min-height: 0; overflow-y: auto; padding-right: 4px;
                display: flex; flex-direction: column; gap: 16px; }
/* The rail is the viewer's, reused wholesale, but it must take the layout's
   height rather than the window's: `align-self: start` and a viewport height are
   what left it floating beside a taller form column. */
.compose-rail { position: static; align-self: stretch;
                height: 100%; max-height: none; min-height: 0; }
/* The viewer's three rows — header, tabs, body. The strip that summed up the map
   was a fourth while the map lived here; it went above the form with the map. */
.compose-rail .resource-info-shell { height: 100%; max-height: none;
                                     grid-template-rows: auto auto minmax(0, 1fr); }
.compose-rail .resource-info-body { max-height: none; }

/* What the 104 tiles add up to, above the tabs so it is read before them. */
.gap-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
               gap: 1px; margin: 0; padding: 0;
               background: var(--line); border-block: 1px solid var(--line); }
.gap-summary > div { background: var(--panel); display: grid; gap: 1px;
                     padding: 8px 10px; min-width: 0; }
.gap-summary dt { color: var(--dim); font-size: 9.5px; font-weight: 650;
                  line-height: 1.3; letter-spacing: .04em; text-transform: uppercase;
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gap-summary dd { color: var(--ink); font: 750 17px/1 var(--mono); margin: 0; }
.gap-summary dd.is-empty { color: var(--heat-0-line); }
.gap-summary dd.is-thin { color: var(--heat-1-line); }
.gap-summary dd.is-stocked { color: var(--heat-3-line); }

/* Above the map, because they act on it. */
.gap-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
               margin-bottom: 10px; }
.gap-actions-link { margin-left: auto; font-size: 11px; white-space: nowrap; }

/* One run, two lines: what was asked, and what came back. A column this narrow
   makes a table worse than a list, and the status belongs on the query rather
   than as a badge of its own — a row of pills for six runs is a wall. */
.recent-runs { display: grid; list-style: none; margin: 0; padding: 0; }
.recent-runs > li + li { border-top: 1px solid var(--line); }
.recent-run-link { display: grid; gap: 3px; min-width: 0; padding: 9px 8px;
                   margin-inline: -8px; border-radius: 8px; color: inherit; }
.recent-run-link:hover { background: var(--neutral-bg); text-decoration: none; }
.recent-run-top { align-items: center; display: flex; gap: 7px; min-width: 0; }
.recent-run-top code { background: transparent; color: var(--accent); padding: 0;
                       font-size: 11.5px; min-width: 0; overflow: hidden;
                       text-overflow: ellipsis; white-space: nowrap; }
.recent-run-dot { flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
                  background: var(--dim); }
.recent-run-dot.is-done { background: var(--ok); }
.recent-run-dot.is-live { background: var(--accent); }
.recent-run-dot.is-failed { background: var(--bad); }
.recent-run-dot.is-stopped { background: var(--warn); }
.recent-run-meta { color: var(--dim); font-size: 11px; padding-left: 14px; }
.recent-run-meta b { color: var(--ink); font: 700 11.5px var(--mono); }
.recent-runs-more { display: inline-block; margin-top: 12px; font-size: 11.5px; }
/* One column, and the page scrolls again. A fixed-height workbench needs two
   columns to be worth anything, and the launch bar can go back to being sticky
   here because the rail below it is something to hold against. */
@media (max-width: 1100px) {
  /* One column, and the page scrolls again — so it stops being one screen tall
     and only the bar's strip stays reserved. */
  main.compose-page { display: block; height: auto; }
  .compose-layout { grid-template-columns: minmax(0, 1fr); height: auto; }
  .compose-main { overflow: visible; padding-right: 0; }
  .compose-rail { height: auto; max-height: none; }
  .compose-rail .resource-info-shell { height: auto; }
  /* One column, so the page scrolls again — and here the bar does have content
     below it to hold against, which is what makes sticky work at all. */
}

/* The competencies currently composing the query. Every competency has a chip so
   the map has something to toggle; the unchosen ones are hidden rather than
   absent, which is what keeps the form working with no script running. */
.picked-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.picked-chip { display: inline-flex; align-items: baseline; gap: 6px;
               padding: 5px 9px; border: 1px solid var(--line); border-radius: 999px;
               background: var(--accent-soft); cursor: pointer; font-size: 11.5px; }
.picked-chip strong { color: var(--ink); font-size: 12px; }
.picked-chip span { color: var(--dim); }
.picked-chip input { margin: 0; }
.picked-chip.is-off { display: none; }


/* One collapsible block per source, so a twelve-string GitHub lane does not push
   the cost table off the screen. */
.compiled-list { display: flex; flex-direction: column; gap: 7px; }
.compiled-list details { padding: 8px 10px; border: 1px solid var(--line);
                         border-radius: 7px; background: var(--neutral-bg); }
.compiled-list summary { display: flex; align-items: center; gap: 8px;
                         cursor: pointer; font-size: 12.5px; }
.compiled-list code { display: block; margin-top: 6px; white-space: normal;
                      overflow-wrap: anywhere; font-size: 10.5px; line-height: 1.45; }

/* Centred, and short. Everything the old page explained about loopback trust and
   createsuperuser belongs in the docs, not in front of someone trying to log in. */
.signin-page { display: flex; justify-content: center; align-items: flex-start;
               padding: 6vh 0 0; }
.signin-card { width: min(360px, 100%); margin: 0; text-align: center; }
.signin-card h1 { margin: 0 0 4px; font-size: 21px; }
.signin-card > .dim { display: block; margin-bottom: 16px; font-size: 12px; }
.signin-card .field-label { margin: 10px 0 4px; text-align: left; }
.signin-card input[type="text"], .signin-card input[type="password"] { width: 100%; }
.signin-card .btn-primary { width: 100%; margin-top: 14px; }
.signin-card .err { display: block; margin-bottom: 10px; }
.signin-alt { display: inline-block; margin-top: 14px; font-size: 11.5px; }

.mode-choice { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
               gap: 10px; margin-bottom: 14px; }
.mode-option { min-width: 0; padding: 11px; border: 1px solid var(--line);
               border-radius: 8px; background: var(--panel); display: flex;
               align-items: flex-start; gap: 9px; cursor: pointer; }
.mode-option:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 58%, var(--line));
                                  background: var(--accent-soft); }
.mode-option input { margin-top: 3px; }
.mode-option span { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.mode-option strong { color: var(--ink); font-size: 13px; }
.mode-option small { color: var(--dim); font-size: 11.5px; line-height: 1.35; }
.mode-panel[hidden] { display: none; }
.field-label { display: block; margin-bottom: 6px; color: var(--dim);
               font-size: 11.5px; }

.source-option { min-width: 0; padding: 10px; border: 1px solid var(--line);
                   border-radius: 8px; background: var(--panel); display: flex;
                   align-items: flex-start; gap: 9px; cursor: pointer; }
.source-option:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 58%, var(--line));
                                      background: var(--accent-soft); }
.source-option input { margin-top: 3px; }
.source-option-copy { min-width: 0; display: flex; flex-direction: column; gap: 3px;
                        color: var(--dim); font-size: 11.5px; line-height: 1.35; }
.source-option-copy strong { color: var(--ink); font-size: 13px; }
.source-option-copy small { margin-left: 7px; padding: 1px 5px; border-radius: 999px;
                              background: var(--ok-bg); color: var(--ok);
                              font-size: 9px; text-transform: uppercase; }

/* ---- competency catalogue + explicit retrieval vocabulary ---- */
/* The four steps from a profile to a query, in a line that wraps: small
   steps and arrows between them, not four boxes stretched across the page. */
.vocabulary-flow { align-items: center; display: flex; flex-wrap: wrap; gap: 6px 0;
  list-style: none; margin: 0; padding: 0; }
.vocabulary-flow li { align-items: center; display: inline-flex; }
.vocabulary-flow li span { background: var(--neutral-bg); border: 1px solid var(--line);
  border-radius: 999px; color: var(--ink); font-size: 12px; padding: 4px 11px; }
.vocabulary-flow li:not(:last-child)::after { color: var(--accent); content: "→"; margin: 0 8px; }
.term-group { display: grid; grid-template-columns: 145px minmax(0, 1fr);
              gap: 10px 14px; align-items: start; }
.term-group > strong { padding-top: 4px; color: var(--dim); font-size: 12px; }
.term-list { display: flex; flex-wrap: wrap; gap: 5px; }
.term { display: inline-block; padding: 3px 8px; border: 1px solid var(--line);
        border-radius: 999px; background: var(--neutral-bg); font-size: 11.5px; }
.term-ai { border-color: color-mix(in srgb, var(--accent) 32%, var(--line));
           background: var(--accent-soft); color: var(--accent); }
.term-warning { border-color: color-mix(in srgb, var(--warn) 34%, var(--line));
                background: var(--warn-bg); color: var(--warn); }
.version-line { color: var(--dim); font-size: 12px; }
@keyframes assignment-composer-focus {
  0%, 35% { background: var(--accent-soft); box-shadow: 0 0 0 8px var(--accent-soft); }
  100% { background: transparent; box-shadow: 0 0 0 0 transparent; }
}
.term-group-warning { margin-top: 9px; }
/* The search string that found a resource: its whole provenance, so it has to
   wrap rather than be clipped, however long the compiled query was. */
.found-by { display: block; max-width: 100%; white-space: normal;
            overflow-wrap: anywhere; font-size: 11px; line-height: 1.45; }
.source-queries { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.source-queries summary { cursor: pointer; color: var(--accent); font-size: 12.5px; }
.source-query-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                     gap: 8px; margin-top: 10px; }
.source-query-grid > div { min-width: 0; padding: 9px; border: 1px solid var(--line);
                           border-radius: 7px; background: var(--neutral-bg); }
.source-query-grid strong, .source-query-grid code { display: block; }
.source-query-grid strong { margin-bottom: 5px; font-size: 11px; text-transform: uppercase;
                            color: var(--dim); }
.source-query-grid code { max-height: 160px; overflow: auto; white-space: normal;
                          overflow-wrap: anywhere; font-size: 10.5px; line-height: 1.45; }

/* ---- original PDF + extracted-text viewer ---- */
.source-viewer { padding: 0; overflow: hidden; min-width: 0; }
.source-view-tabs { min-height: 49px; display: flex; align-items: center; gap: 4px;
                    padding: 7px 10px; border-bottom: 1px solid var(--line);
                    background: var(--neutral-bg); }
.source-view-tab { border: 1px solid transparent; border-radius: 7px; padding: 7px 11px;
                   background: transparent; color: var(--dim); font: inherit;
                   font-size: 13px; cursor: pointer; }
.source-view-tab:hover { color: var(--ink); background: var(--panel); }
.source-view-tab.active { color: var(--accent); background: var(--panel);
                          border-color: var(--line); font-weight: 650; }
.source-view-tab:focus-visible, .source-view-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.source-view-spacer { flex: 1; }
.source-view-link { padding: 5px 7px; font-size: 12.5px; white-space: nowrap; }
.source-view-panel[hidden] { display: none; }
.source-viewer > .doc-body { margin: 0; border: 0; border-radius: 0; }
.pdf-view-panel { background: var(--pdf-bg); }
.pdf-frame { display: block; width: 100%; height: min(78vh, 980px); min-height: 680px;
             border: 0; background: var(--pdf-frame-bg); }
.pdf-fallback { margin: 0; padding: 8px 14px; background: var(--panel);
                border-top: 1px solid var(--line); font-size: 12px; }

/* ---- notebook document viewer ---- */
.notebook-head { margin: -22px -28px 24px; padding: 12px 18px; border-bottom: 1px solid var(--line);
                 background: var(--neutral-bg); display: flex; gap: 11px; align-items: center;
                 border-radius: 10px 10px 0 0; }
.notebook-head > div { display: flex; flex-direction: column; font-size: 13px; }
.notebook-icon { width: 31px; height: 31px; border-radius: 8px; background: var(--panel);
                 border: 1px solid var(--line); color: var(--warn); display: inline-flex;
                 align-items: center; justify-content: center; font: 700 13px var(--mono); }
.notebook-doc { counter-reset: notebook-cell; }
.notebook-doc .nb-cell { display: grid; grid-template-columns: 58px minmax(0, 1fr);
                         align-items: start; margin: 16px -8px; }
.notebook-doc .nb-prompt { color: var(--accent); font: 11px/1.5 var(--mono);
                           padding: 11px 8px 0 0; text-align: right; user-select: none; }
.notebook-doc .nb-code { min-width: 0; border: 1px solid var(--line); border-radius: 8px;
                         background: var(--neutral-bg); overflow: hidden; }
.notebook-doc .nb-code pre { margin: 0; border-radius: 0; padding: 13px 16px;
                             line-height: 1.55; max-height: 680px; }
.notebook-doc > img, .notebook-doc > p > img { display: block; margin: 16px auto;
                                              border: 1px solid var(--line); border-radius: 8px; }
.notebook-doc iframe, .notebook-doc video, .notebook-doc svg { max-width: 100%; }

@media (max-width: 820px) {
  .topbar .wrap { height: 52px; min-height: 52px; gap: 8px; }
  .topbar nav { flex: 1 1 auto; }
  .qsearch { flex-basis: 150px; margin-left: 0; }
  .pagination { grid-template-columns: 1fr; justify-items: center; }
  .table-card-head { align-items: stretch; flex-direction: column; }
  .table-card-search { flex-basis: auto; width: 100%; }
  .source-query-grid { grid-template-columns: 1fr; }
  .page-links .page-link:not(.active):not(:first-child):not(:last-child) { display: none; }
  .resource-detail-layout.is-info-open { grid-template-columns: 1fr; }
  .resource-detail-layout.is-info-open .resource-info-rail { grid-row: 1; }
  .resource-detail-layout.is-info-open .resource-view-column { grid-row: 2; }
  .resource-info-rail { height: min(72vh, 680px); inset-block-start: auto; position: static; }
}

@media (max-width: 1050px) {
  .qsearch { display: none; }
}

@media (max-width: 760px) {
  .account-name { display: none; }
}

@media (max-width: 650px) {
  .nav-menu-label { display: none; }
}

@media (max-width: 560px) {
  .wrap { padding-left: 12px; padding-right: 12px; }
  .qsearch { display: none; }
  .nav-menu-label { display: none; }
  .nav-menu .nav-menu-panel, .nav-menu-end .nav-menu-panel {
    left: 12px; max-height: calc(100dvh - 70px); min-width: 0; overflow-y: auto;
    position: fixed; right: 12px; top: 59px;
  }
  .nav-menu > summary { padding-left: 7px; padding-right: 7px; }
  .nav-menu > summary > .ico:first-child { margin-right: 0; }
  .nav-menu > summary .nav-chevron { margin-left: 4px; }
  .filters:not(.corpus-filters) { display: grid;
                                  grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .filters:not(.corpus-filters) > * { min-width: 0; max-width: 100%; width: 100%; }
  .filters:not(.corpus-filters) input[type=search],
  .filters:not(.corpus-filters) select[name="comp"],
  .filters:not(.corpus-filters) select[name="pedagogy"],
  .filters:not(.corpus-filters) button { grid-column: 1 / -1; }
  .composer { flex-wrap: wrap; }
  .composer select { flex: 1 0 110px; }
  .composer input { min-width: 100%; order: 3; }
  .term-group { grid-template-columns: 1fr; }
  .doc-body { padding: 18px 16px; }
  .notebook-head { margin: -18px -16px 20px; }
  .notebook-doc .nb-cell { grid-template-columns: 1fr; margin-left: 0; margin-right: 0; }
  .notebook-doc .nb-prompt { text-align: left; padding: 0 0 5px; }
  .lic-plain { grid-template-columns: 1fr; }
  .info-section-head, .license-identity { align-items: flex-start; }
  .license-identity { flex-direction: column; }
  .bundled-file-list li { grid-template-columns: 34px minmax(0, 1fr); }
  .bundled-file-list .btn { grid-column: 2; justify-self: start; }

  .source-view-tabs { flex-wrap: wrap; }
  .source-view-spacer { display: none; }
  .source-view-link { margin-left: 4px; }
  .pdf-frame { min-height: 520px; height: 72vh; }
  .resource-hero { gap: 14px; padding: 17px 16px; }
  .resource-facts > div { border-right: 0; flex: 1 1 130px; padding: 0; }
  .resource-info-head { padding: 16px; }
  .resource-info-body { padding-left: 12px; padding-right: 12px; }
}

/* ---- OER check 1.1.0: graded competency rows and quality dimensions ---- */


/* ── The competency catalogue: a map over a list and one competency ────────
   The map is the whole catalogue at a glance, coloured by what the alignment
   found; the list beside the detail finds one; the detail is that one. It was
   104 cards of one size in two columns, each with three badges and two
   collapsed panels: nothing on it said where the gaps were, and every card had
   to be opened to be read. */
.catalogue-main .pagehead { align-items: center; display: grid; gap: 8px 20px;
  grid-template-columns: auto minmax(0, 1fr); margin-block: 14px 10px; }
.catalogue-main .pagehead h1 { font-size: 23px; letter-spacing: -.025em; margin: 0;
  white-space: nowrap; }
.catalogue-main .pagehead .purpose { border-left: 1px solid var(--line); font-size: 12px;
  line-height: 1.45; max-width: none; padding-left: 20px; }
.status-dot { align-items: center; color: var(--dim); display: inline-flex; font-size: 10px;
  font-weight: 700; gap: 5px; white-space: nowrap; }
.status-dot::before { background: currentColor; border-radius: 50%; content: ""; height: 6px; width: 6px; }
.status-dot.is-ok { color: var(--ok); }
.status-dot.is-bad { color: var(--bad); }
.status-dot.is-warn { color: var(--warn); }

/* The map: a row a category and a column a number, as a table, so a tile
   carries only its figure — the one under 21 in row D is D21 — and the eye
   reads the colours rather than 104 labels. Borderless tiles on a scale of
   five; an empty column is a retired competency. */
.catalogue-map { margin-bottom: 14px; padding: 16px 18px; }
.catalogue-map-head { align-items: flex-start; display: flex; gap: 18px;
  justify-content: space-between; margin-bottom: 14px; }
.catalogue-map-head h2 { color: var(--ink); font-size: 15px; letter-spacing: normal;
  margin: 0 0 3px; text-transform: none; }
.catalogue-map-head p { font-size: 12px; margin: 0; max-width: 860px; }
.map-legend { align-items: center; color: var(--dim); display: flex; flex: 0 0 auto;
  flex-wrap: wrap; font-size: 11px; gap: 4px 12px; margin-top: 3px; }
.map-legend span { align-items: center; display: inline-flex; gap: 5px; white-space: nowrap; }
.map-swatch { border-radius: 3px; display: inline-block; flex: 0 0 auto; height: 11px; width: 11px; }
.catalogue-map-grid { align-items: center; display: grid; gap: 3px;
  grid-template-columns: auto repeat(var(--columns), minmax(0, 1fr)); }
.catalogue-map-col { color: var(--dim); font: 600 9.5px var(--mono); padding-bottom: 1px;
  text-align: center; }
.catalogue-map-label { align-items: baseline; color: var(--dim); display: flex; font-size: 11.5px;
  gap: 6px; grid-column: 1; padding-right: 12px; white-space: nowrap; }
.catalogue-map-label b { color: var(--accent); font: 750 12px var(--mono); }
.map-cell { border-radius: 6px; color: var(--ink); display: grid;
  font: 650 11.5px var(--mono); font-variant-numeric: tabular-nums; grid-column: var(--column);
  height: 30px; place-items: center; text-decoration: none;
  transition: box-shadow .12s, transform .12s; }
.map-cell:hover { box-shadow: 0 2px 7px color-mix(in srgb, var(--ink) 16%, transparent);
  transform: translateY(-1px); }
.map-cell.selected { outline: 2px solid var(--accent); outline-offset: 1px; }
/* A blind spot: the graded sample holds pairs for it that the map does
   not count. The app's dotted underline, which says there is more on hover. */
.map-cell.is-blind-spot { text-decoration: underline dotted; text-underline-offset: 3px; }
/* The figures of the warm shades take some ink: the shade's own line colour
   on its own tint read at 3:1, too faint for a figure this small. */
.map-0 { background: var(--heat-0-bg); color: color-mix(in srgb, var(--heat-0-line) 62%, var(--ink)); }
.map-1 { background: var(--heat-1-bg); color: color-mix(in srgb, var(--heat-1-line) 58%, var(--ink)); }
.map-2 { background: color-mix(in srgb, var(--heat-3-line) 16%, var(--panel)); }
.map-3 { background: color-mix(in srgb, var(--heat-3-line) 42%, var(--panel)); }
/* The deepest shade darkened with the ink, not lightened with the page: white
   figures on a mid green read at under 3:1. */
.map-4 { background: color-mix(in srgb, var(--heat-3-line) 78%, var(--ink)); color: var(--panel); }
/* The map read two ways: a switch above each view's legend, at the head's
   right, and only the shown view's title, sentence and legend on screen. */
.catalogue-map-tools { align-items: flex-end; display: flex; flex: 0 0 auto;
  flex-direction: column; gap: 8px; }
[data-map-view="aligned"] [data-map-only="searched"],
[data-map-view="searched"] [data-map-only="aligned"] { display: none; }
/* The dots mark what the alignment does not see, so they go with its view. */
.catalogue-map[data-map-view="searched"] .map-cell.is-blind-spot { text-decoration: none; }
/* The composer's cells are buttons, because they are the selection. */
button.map-cell { border: 0; cursor: pointer; padding: 0; width: 100%; }
button.map-cell:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The map in the composer's side panel, where the form keeps the page: the
   switch and the legend on one line, a sentence, the actions, and the columns
   folded in two blocks so a cell stays as wide as the catalogue's. */
.map-in-panel { display: grid; gap: 10px; padding: 14px; }
.map-panel-head { align-items: center; display: flex; flex-wrap: wrap; gap: 8px 14px;
  justify-content: space-between; }
.map-panel-head .map-legend { margin-top: 0; }
.map-panel-note { font-size: 11.5px; margin: 0; }
.map-in-panel .gap-actions { margin-bottom: 0; }
.map-in-panel .catalogue-map-label span { display: none; }
.map-in-panel .map-cell { height: 26px; }

/* The list beside the detail, kept in view while a long competency is read. */
.catalogue-layout { align-items: start; display: grid; gap: 16px;
  grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); }
.catalogue-side { background: var(--panel); border: 1px solid var(--line); border-radius: 11px;
  display: flex; flex-direction: column; gap: 8px; min-height: 0; padding: 12px;
  max-height: calc(100dvh - var(--topbar-height) - 28px);
  position: sticky; top: calc(var(--topbar-height) + 14px); }
.catalogue-search { display: grid; gap: 8px; }
.heat-filter { border: 1px solid var(--line); border-radius: 999px; color: var(--dim);
  font: 650 11px var(--mono); padding: 3px 9px; text-decoration: none; }
.heat-filter:hover { border-color: var(--accent); color: var(--accent); }
.heat-filter.active { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.catalogue-count { font-size: 11.5px; margin: 0; }
.catalogue-index { display: grid; gap: 1px; margin: 0 -6px; min-height: 0; overflow-y: auto;
  padding: 0 6px; }
.catalogue-index-item { align-items: center; border-radius: 7px; color: var(--ink); display: grid;
  font-size: 12.5px; gap: 8px; grid-template-columns: 10px 30px minmax(0, 1fr) auto;
  padding: 6px 8px; text-decoration: none; }
.catalogue-index-item[hidden] { display: none; }
.catalogue-index-item:hover { background: var(--neutral-bg); }
.catalogue-index-item.is-selected { background: var(--accent-soft); color: var(--accent); }
.catalogue-index-item code { color: var(--dim); font: 650 11px var(--mono); }
.catalogue-index-item.is-selected code { color: var(--accent); }
.catalogue-index-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.catalogue-index-item small { color: var(--dim); font: 650 11px var(--mono); }
.catalogue-index-item .map-swatch { height: 10px; width: 10px; }

/* One competency: what it is, three figures, its search vocabulary and its
   descriptor, each under a heading rather than behind a panel. */
.catalogue-detail { display: grid; gap: 14px; min-width: 0; }
.competency-detail { margin: 0; }
.competency-detail-meta { color: var(--dim); font-size: 12px; margin: 0 0 4px; }
.competency-detail-meta code { color: var(--accent); font: 750 12px var(--mono); margin-right: 6px; }
.competency-detail-head h2 { color: var(--ink); font-size: 20px; letter-spacing: -.01em;
  margin: 0 0 5px; text-transform: none; }
.competency-detail-head p:last-child { margin: 0; max-width: 860px; }
/* Two figures from two questions, side by side and never summed: each says
   in words what it counts, the alignment's with how much of it is decided. */
.competency-figures { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 16px; }
.competency-figure { background: var(--neutral-bg); border-radius: 10px; display: grid; gap: 4px;
  padding: 12px 14px; }
.competency-figure h3 { color: var(--ink); font-size: 12.5px; margin: 0; }
.competency-figure p { margin: 0; }
.competency-figure-main { color: var(--ink); font-size: 13.5px; }
.competency-figure-main strong { font: 750 24px/1.1 var(--mono); margin-right: 4px; }
.competency-figure-main strong.is-empty { color: var(--heat-0-line); }
.competency-figure-main strong.is-thin { color: var(--heat-1-line); }
.competency-figure-main strong.is-stocked { color: var(--heat-3-line); }
.competency-figure .dim { font-size: 12px; }
.competency-section { border-top: 1px solid var(--line); display: grid; font-size: 13.5px;
  gap: 10px; margin-top: 16px; padding-top: 14px; }
.competency-section p.dim:not(.descriptor-text) { font-size: 12.5px; margin: 6px 0 0; }
.competency-section > h3 { align-items: center; color: var(--ink); display: flex; font-size: 14px;
  gap: 10px; margin: 0; }
.competency-section > p { margin: 0; }
.competency-section .source-queries { margin-top: 0; }
/* How the page is read, once for all 104: a dialog each, opened beside the
   heading it explains, rather than a card of two disclosures under the last
   competency. */
.competency-explain { margin-left: auto; }
/* Wide enough for the four steps on one line. */
.confirm-dialog.explain-dialog { max-width: 900px; }
.explain-terms { display: grid; gap: 6px; }
.explain-terms > strong { color: var(--ink); font-size: 12px; }
/* Room under the last card, as the page ends, and under the list's last
   entry, which a fade lets go of instead of cutting. */
.catalogue-layout { margin-bottom: 32px; }
.catalogue-index { mask-image: linear-gradient(to bottom, #000 calc(100% - 16px), transparent);
  padding-bottom: 18px; }

/* A competency's alignment descriptor, under its vocabulary. */
.descriptor-list { margin: 0; padding-left: 18px; }
.descriptor-list li { margin: 0 0 4px; }
.descriptor-text { margin: 0; max-width: 850px; }

/* The alignment rubric. A level is a small square in the level's colour, the
   same square the review screen and a resource's alignment use. */
.rubric-status { align-items: center; display: flex; flex-wrap: wrap; gap: 8px 22px; }
.rubric-status > div { align-items: center; display: flex; gap: 8px; }
.rubric-levels { min-width: 720px; }
.rubric-levels td:first-child { width: 48px; }
.rubric-levels td:nth-child(2) { width: 22%; }
.rubric-reasons th { width: 190px; }
.alignment-level { border-radius: 5px; display: inline-grid; font: 750 12px/1 var(--mono);
  height: 24px; place-items: center; width: 24px; }
.alignment-level-3 { background: var(--ok-bg); color: var(--ok); }
.alignment-level-2 { background: var(--accent-soft); color: var(--accent); }
.alignment-level-1 { background: var(--warn-bg); color: var(--warn); }
.alignment-level-0 { background: var(--neutral-bg); color: var(--dim); }
.catalogue-main .term-group { grid-template-columns: 105px minmax(0, 1fr); }

@media (max-width: 1180px) {
  .catalogue-map-label span { display: none; }
}
@media (max-width: 980px) {
  .catalogue-main .pagehead { display: block; }
  .catalogue-main .pagehead .purpose { border-left: 0; margin-top: 5px; padding-left: 0; }
  .catalogue-map-head { flex-direction: column; gap: 8px; }
  .catalogue-map-tools { align-items: flex-start; }
  .catalogue-layout { grid-template-columns: minmax(0, 1fr); }
  .catalogue-side { max-height: 46vh; position: static; }
}
@media (max-width: 620px) {
  /* Too narrow for 27 columns: the tiles flow under their category's name,
     without the numbers on top, and say which competency they are when touched. */
  .catalogue-map-grid { grid-template-columns: repeat(auto-fill, minmax(30px, 1fr)); }
  .catalogue-map-col, .catalogue-map-corner { display: none; }
  .catalogue-map-label { grid-column: 1 / -1; padding: 6px 0 2px; }
  .catalogue-map-label span { display: inline; }
  .map-cell { grid-column: auto; height: 26px; }
  .competency-figures { grid-template-columns: minmax(0, 1fr); }
  .catalogue-main .term-group { grid-template-columns: 1fr; }
}

/* Keep the document viewer and its analysis rail side by side on tablets and
   Retina laptop windows. The older 820px breakpoint made the rail take over
   the page while moving the actual resource below it. */
.resource-detail-layout.is-info-open { align-items: flex-start; display: flex; gap: 16px; }
.resource-detail-layout.is-info-open > .resource-view-column { flex: 1 1 0; min-width: 0; order: 1; }
.resource-detail-layout.is-info-open > .resource-info-rail { flex: 0 0 clamp(420px, 29vw, 500px);
  min-width: 0; order: 2; width: auto; }
@media (min-width: 681px) and (max-width: 1200px) {
  .resource-detail-layout.is-info-open { gap: 12px; }
  .resource-detail-layout.is-info-open > .resource-info-rail {
    flex-basis: clamp(320px, 40vw, 420px); }
  .resource-detail-layout.is-info-open .resource-view-column,
  .resource-detail-layout.is-info-open .resource-info-rail { grid-row: auto; }
  .resource-info-rail { height: calc(100dvh - var(--topbar-height) - 16px);
    inset-block-start: calc(var(--topbar-height) + 8px); position: sticky; }
  .resource-info-head { padding: 12px 13px 10px; }
  .resource-info-head p { display: none; }
  .resource-info-body { padding-inline: 13px; }
  .resource-info-tab { padding-inline: 6px; }
}
@media (max-width: 680px) {
  .resource-detail-layout.is-info-open { flex-direction: column; }
  .resource-detail-layout.is-info-open > .resource-info-rail { flex-basis: auto; order: 1; width: 100%; }
  .resource-detail-layout.is-info-open > .resource-view-column { order: 2; width: 100%; }
  .resource-info-rail { height: min(72vh, 680px); inset-block-start: auto; position: static; }
}

/* --- e8 competency alignment ------------------------------------------- */

/* --- competency annotation ---------------------------------------------- */

/* ---- SPIKE 02 additions ------------------------------------------------- */
/* The stylesheet above is carried over from SPIKE 01. Everything below is new
   here, because these two things had no equivalent: SPIKE 01 reported failures
   through per-page markup rather than a message framework, and its pagination
   summary was never given a rule. Kept deliberately small — if this block grows,
   the design has drifted and should be reconciled rather than extended. */
.message-list { display: grid; gap: 8px; margin: 18px 0 0; }
.flash { border: 1px solid var(--line); border-left-width: 3px; border-radius: 7px;
         font-size: 13.5px; margin: 14px 0; padding: 10px 14px; }
.flash a { font-weight: 650; }
.flash-info, .flash-debug { background: var(--accent-soft); border-left-color: var(--accent); }
.flash-success { background: var(--ok-bg); border-left-color: var(--ok); color: var(--ok); }
.flash-warning { background: var(--warn-bg); border-left-color: var(--warn); color: var(--warn); }
.flash-error { background: var(--bad-bg); border-left-color: var(--bad); color: var(--bad); }
.flash-success a, .flash-warning a, .flash-error a { color: inherit; text-decoration: underline; }
.page-summary { color: var(--dim); font-size: 12.5px; }

/* ---- SPIKE 02: bounded panels ------------------------------------------- */

/* The cost table sits above the queries because it is the part that changes a
   decision. Searches are the cheap half of what a plan spends, and reading the
   two figures side by side is the whole point of showing them. */
/* The two figures a curator acts on, before the breakdown that explains them.
   The table alone made the decision — is this worth launching now? — something
   you had to add up yourself across five columns. */
.cost-headline { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                 gap: 1px; margin: 0 0 14px; padding: 0;
                 background: var(--line); border: 1px solid var(--line);
                 border-radius: 9px; overflow: hidden; }
.cost-headline > div { background: var(--panel); display: grid; gap: 2px;
                       padding: 9px 11px; min-width: 0; }
/* Short enough to fit the cell. The label that was being clipped was clipped
   because it was a sentence — "Requests, worst case" — and the caveat belongs in
   the note under the table, which is where it now is. */
.cost-headline dt { color: var(--dim); font-size: 9.5px; font-weight: 650;
                    line-height: 1.3; letter-spacing: .04em; text-transform: uppercase;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cost-headline dd { color: var(--ink); font: 750 18px/1 var(--mono); margin: 0; }

.plan-cost { width: 100%; margin-bottom: 12px; border-collapse: collapse; }
.plan-cost th, .plan-cost td { padding: 6px 8px; border-bottom: 1px solid var(--line); }
.plan-cost thead th { color: var(--dim); font-size: 9.5px; font-weight: 650;
                      letter-spacing: .04em; text-transform: uppercase; }
.plan-cost tbody th { color: var(--ink); font-size: 12px; font-weight: 650;
                      text-align: left; }
.plan-cost tbody tr:last-child th, .plan-cost tbody tr:last-child td { border-bottom: 0; }
.plan-cost th:not(:first-child), .plan-cost td:not(:first-child) {
  text-align: right; font: 600 11.5px var(--mono); font-variant-numeric: tabular-nums; }
.plan-cost thead th:not(:first-child) { font: 650 9.5px/1.5 var(--mono); }

/* The plan's own settings, so a full-width select is not competing with the
   launch button for a right-aligned wrapping row. */
.plan-settings-grid { display: grid; gap: 10px; }
.plan-settings-grid label { display: grid; gap: 4px; font-size: 12px;
                            font-weight: 650; }
/* The publication window's two ends on one row, stacked where both will not fit. */
.plan-settings-pair { display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.plan-settings-grid select, .plan-settings-grid input {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 7px 9px; font-size: 13px; font-weight: 400;
  width: 100%; }

/* The info rail's shell is a three-row grid with `overflow: hidden`, so the panel
   in its last row is what scrolls. SPIKE 01 set that on the tab-panel variants it
   had; this build has one panel, so the rule goes on the panel itself. */
.resource-info-shell > .resource-info-panel { overflow-y: auto; padding: 0 16px; }

/* Buttons and a form live side by side above the hero. A form is block-level, so
   without this the two actions stack and the row reads as two rows. */
/* SPIKE 01's back-row is a two-child `space-between`: the link on the left, the
   action on the right. This page has two actions, so they are grouped — otherwise
   space-between strands one of them in the middle. */
.back-row-actions { align-items: center; display: flex; flex-wrap: wrap; gap: 10px; }
.back-row-actions form { display: inline-flex; margin: 0; }

/* The library's bulk action bar: a row above the results, quiet until something
   is selected. The checkboxes live in the cards and belong to a separate POST
   form, because the filter form around them is a GET. */
/* The corpus operations, in the row the results header already occupied. */
.library-ops { align-items: center; display: flex; flex-wrap: wrap; gap: 7px;
               flex: 0 0 auto; }
.library-ops-count { color: var(--bad); font: 700 12px var(--mono);
                     padding-right: 3px; white-space: nowrap; }

/* Read by a screen reader, never shown. The selection box in a card's corner has
   no visible label of its own, and "checkbox" on its own is not a choice anyone
   can make. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px;
                   padding: 0; overflow: hidden; white-space: nowrap;
                   clip-path: inset(50%); border: 0; }

/* Selecting is a mode, and in it the card is the control: no checkbox column to
   line up, nothing added to a card that is being read rather than managed. A
   checkbox stays in the page, visually hidden, because it is what the POST
   carries and how the keyboard reaches the selection. */
.oer-item { position: relative; }
.oer-list.is-selecting .oer-item { cursor: pointer; user-select: none; }
.oer-list.is-selecting .oer-item:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
.oer-list.is-selecting .oer-title { cursor: inherit; color: var(--ink); }
.oer-item.is-selected { border-color: var(--accent); background: var(--accent-soft); }
.oer-item.is-selected .oer-card-foot,
.oer-item.is-selected .oer-card-head { background: transparent; }
.oer-select:focus-within { position: static; width: auto; height: auto;
                           margin: 0; clip-path: none; padding: 6px 10px;
                           font-size: 11.5px; color: var(--accent); }
.oer-card-state .check-line { margin: 0; }

/* --- the metadata record, and the two standard projections of it ----------
   An element with no value is still a row. The whole point of showing an empty
   `5.8 Difficulty` is that a reader can tell "LOM has a difficulty rating and
   nothing declared one" from "this export forgot about difficulty", so the
   empty state is styled to be legible rather than hidden. */
.metadata-loss { background: var(--warn-bg); border-radius: 8px; color: var(--ink);
                 font-size: 11px; line-height: 1.45; margin: 0 0 11px;
                 padding: 9px 11px; }
.metadata-actions { align-items: center; display: flex; flex-wrap: wrap; gap: 9px; }
.metadata-actions .btn { font-size: 11px; padding: 6px 10px; }
.metadata-elements { display: grid !important; gap: 0; }
.metadata-element { border-top: 1px solid var(--line); display: grid; gap: 2px;
                    grid-template-columns: minmax(0, 1fr); padding: 9px 0; }
.metadata-element:first-child { border-top: 0; padding-top: 0; }
.resource-info-panel .metadata-element dt { align-items: baseline; clear: none;
  display: flex; float: none; gap: 8px; width: auto; }
.metadata-element dt code { font-size: 10px; }
.metadata-element dt span { color: var(--ink); font-size: 11.5px; font-weight: 650; }
.resource-info-panel .metadata-element dd { display: grid; gap: 4px; margin: 0; }
.metadata-element-empty dt span { color: var(--dim); font-weight: 600; }
.metadata-values { display: grid; gap: 3px; list-style: none; margin: 0; padding: 0; }
.metadata-values li { background: var(--neutral-bg); border-radius: 6px;
                      color: var(--ink); font-size: 12px; line-height: 1.4;
                      overflow-wrap: anywhere; padding: 5px 8px; }
/* A set of short terms — keywords, topics — wraps as tags instead of taking a
   full-width row each. Neutral, not the accent chips: those are filters you
   can click, and these are values you read. */
.metadata-terms { align-items: flex-start; display: flex; flex-wrap: wrap; gap: 4px; }
.metadata-terms li { border-radius: 4px; padding: 2px 8px; }
/* Supporting information, set like it. The element's name is the heading here;
   the provenance used to be upper-case mono across the whole column and read as
   the louder of the two. */
.metadata-source { display: grid; gap: 2px; list-style: none; margin: 1px 0 0;
                   padding: 0; }
.metadata-source li { align-items: baseline; display: flex; flex-wrap: wrap;
                      gap: 5px; line-height: 1.45; }
/* One dot, coloured by the kind of claim: somebody said it, this engine read
   it, or this engine worked it out from something else. */
.metadata-source li::before { background: currentColor; border-radius: 50%;
                              content: ""; flex: 0 0 auto; height: 5px;
                              transform: translateY(-1px); width: 5px; }
.metadata-source .from-declared, .from-declared { color: var(--ok); }
.metadata-source .from-observed, .from-observed { color: var(--accent); }
.metadata-source .from-derived, .from-derived { color: var(--dim); }
/* Read out of the text by an enrichment rule: its own colour, never one of
   the declared ones. */
.metadata-source .from-inferred, .from-inferred { color: var(--theory); }
.metadata-source abbr { color: var(--ink); font-size: 10.5px; font-weight: 600;
                        text-decoration: none; }
/* A dotted underline is the only thing that says "there is more on hover". */
.metadata-source abbr[data-tip] { border-bottom: 1px dotted var(--line); cursor: help; }
/* What the gate read. Plain and dim: in bold accent mono it looked like a link
   or a piece of code, and it was neither. */
.metadata-source i { color: var(--dim); font-size: 10px; font-style: normal; }
.metadata-source i[data-tip] { border-bottom: 1px dotted var(--line); cursor: help; }
.metadata-source a, .metadata-source span { color: var(--dim); font-size: 9.5px;
                                            overflow-wrap: anywhere; }
.metadata-source a { text-decoration: underline; text-decoration-style: dotted;
                     text-underline-offset: 2px; }
.metadata-source a:hover { color: var(--accent); }
.metadata-absent { color: var(--dim); font-size: 11px; font-style: italic; margin: 0; }
.metadata-note { color: var(--dim); font-size: 10.5px; line-height: 1.4; margin: 0; }
/* One table, so the status badges and the field names line up down the page.
   As a list of per-row grids each row sized its own columns, and a row badged
   "declared, not mapped" pushed its field name past every other one. */
.incident-table { border-collapse: collapse; margin-top: 11px; table-layout: fixed;
                  width: 100%; }
.incident-table th { color: var(--dim); font: 750 9px var(--mono); letter-spacing: .07em;
                     padding: 0 10px 6px 0; text-align: left; text-transform: uppercase; }
.incident-table th:first-child { width: 132px; }
.incident-table th:nth-child(2) { width: 130px; }
.incident-table td { border-top: 1px solid var(--line); padding: 9px 10px 9px 0;
                     vertical-align: top; }
.incident-table td:last-child { color: var(--dim); font-size: 11.5px; line-height: 1.45;
                                overflow-wrap: anywhere; padding-right: 0; }
.incident-table td code { color: var(--ink); font-size: 10.5px; overflow-wrap: anywhere; }
.incident-code { border-radius: 999px; display: inline-block; font: 700 9px var(--mono);
                 letter-spacing: .04em; padding: 2px 7px; text-align: center;
                 text-transform: uppercase; white-space: nowrap; }
.incident-table .i-absent .incident-code { background: var(--panel); color: var(--dim); }
.incident-table .i-structure .incident-code { background: var(--accent-soft); color: var(--accent); }
.incident-table .i-unmapped .incident-code { background: var(--warn-bg); color: var(--warn); }
.incident-table .i-conflict .incident-code { background: var(--warn-bg); color: var(--warn); }
.incident-table .i-failed .incident-code { background: var(--bad-bg); color: var(--bad); }

/* --- the metadata record, as a view of the resource ----------------------
   It sits in the reading column beside the extracted text and the original,
   which is what lets an element be a two-column row — a label block with its
   provenance, and the values beside it — instead of the stack of lines it had
   to be in a 420px rail. */
.record-view { display: grid; gap: 18px; padding: 20px 22px 24px; }
.record-head { align-items: flex-start; display: flex; gap: 16px;
               justify-content: space-between; }
.record-head > div { min-width: 0; }
.record-head h2 { color: var(--ink); font-size: 19px; letter-spacing: -.01em;
                  margin: 2px 0 0; text-transform: none; }
.record-head p { color: var(--dim); font-size: 12px; line-height: 1.5;
                 margin: 6px 0 0; max-width: 62ch; }
.record-facts { align-items: start; display: flex; flex-wrap: wrap; gap: 10px 18px;
                justify-content: space-between; }
.record-facts dl { display: grid; gap: 26px; grid-auto-flow: column; margin: 0; }
.record-facts dl > div { min-width: 0; }
.record-facts dt { color: var(--dim); font-size: 9.5px; font-weight: 700;
                   letter-spacing: .055em; text-transform: uppercase; }
.record-facts dd { display: grid; gap: 2px; margin: 4px 0 0; min-width: 0; }
.record-facts dd strong { color: var(--ink); font-size: 13px; overflow-wrap: anywhere; }
.record-facts dd code { font-size: 11.5px; }
.record-facts dd small { color: var(--dim); font-size: 10.5px; line-height: 1.35;
                         overflow-wrap: anywhere; }
.record-downloads { align-items: center; display: flex; flex-wrap: wrap; gap: 6px; }
.record-downloads > span { color: var(--dim); font: 750 9.5px var(--mono);
                           letter-spacing: .055em; margin-right: 2px;
                           text-transform: uppercase; }
.record-downloads .btn { font-size: 11px; padding: 6px 10px; }

/* The switch is also the meter: choosing a projection and seeing how much of it
   is filled are the same question asked twice, and they were two controls. */
.record-switch { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.record-switch-tab { background: var(--neutral-bg); border: 1px solid var(--line);
                     border-radius: 11px; cursor: pointer; display: grid; gap: 7px;
                     padding: 13px 15px; text-align: left; }
.record-switch-tab:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.record-switch-tab.active { background: var(--accent-soft); border-color: var(--accent); }
.record-switch-name { color: var(--dim); font: 750 9.5px var(--mono);
                      letter-spacing: .08em; text-transform: uppercase; }
.record-switch-tab.active .record-switch-name { color: var(--accent); }
.record-switch-count { color: var(--ink); font-size: 21px; font-weight: 700; line-height: 1; }
.record-switch-count small { color: var(--dim); font-size: 12.5px; font-weight: 600; }
.record-switch-tab > small { color: var(--dim); font-size: 10px; line-height: 1.35;
                             overflow-wrap: anywhere; }
.record-meter { background: var(--line); border-radius: 999px; display: block;
                height: 5px; overflow: hidden; }
.record-meter > span { background: var(--accent); display: block; height: 100%; }
.record-switch-tab.active .record-meter { background: color-mix(in srgb, var(--accent) 22%, transparent); }

/* The record is not a third rendering of the resource, so it does not sit flush
   against the two that are. */
.source-view-tab-aside { border-left: 1px solid var(--line); border-radius: 0 7px 7px 0;
                         margin-left: 10px; padding-left: 13px; }
.record-scheme { display: grid; gap: 16px; }
.record-group { display: grid; gap: 9px; }
/* Compact: only what is filled. A group with nothing filled goes with its rows. */
.record-compact .metadata-element-empty,
.record-compact .record-group-empty { display: none; }
.record-empty-toggle { align-items: center; color: var(--dim); cursor: pointer;
                       display: inline-flex; font-size: 12px; gap: 6px;
                       justify-self: end; }
.record-group > h3 { align-items: center; border-bottom: 1px solid var(--line);
                     color: var(--accent); display: flex; font: 750 9.5px var(--mono);
                     gap: 10px; justify-content: space-between; letter-spacing: .08em;
                     margin: 0; padding-bottom: 7px; text-transform: uppercase; }
.record-group > h3 .pill { font-size: 9.5px; margin: 0; }
/* The category's completeness: one segment per element, filled in the accent,
   empty in the rule colour, a 2px gap between them. The count stays beside it
   in ink, so the number never depends on reading a colour. */
.record-group-fill { align-items: center; display: inline-flex; gap: 8px; }
.record-group-meter { align-items: center; display: inline-flex; gap: 2px; }
.record-group-meter > span { background: var(--line); border-radius: 2px;
                             cursor: help; height: 8px; width: 9px; }
.record-group-meter > .is-filled { background: var(--accent); }
/* Not collected at all: hollow, so it reads as "outside the profile" rather
   than as a gap the sources left. */
.record-group-meter > .is-not-collected { background: transparent;
                                          box-shadow: inset 0 0 0 1px var(--line); }
.record-group-meter > .is-none-found { background: var(--line); }
/* Inferred: the inferred colour, so the meter tells a declaration from a
   reading of the text at a glance, as the cards and the summary do. */
.record-group-meter > .is-inferred { background: var(--theory); }
/* An inferred value in its box: a faint wash and a hairline of the inferred
   colour, enough to be seen as one before the provenance line is read. */
.record-view .metadata-inferred li {
  background: color-mix(in srgb, var(--theory) 8%, var(--panel));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--theory) 28%, transparent); }
.record-incidents { margin-top: 2px; }
/* What the enrichment has since read for a field the source left empty: the
   incident stays, and this says it is no longer the end of the story. */
.incident-inferred { display: block; margin-top: 3px; }
.record-view .metadata-elements { display: grid; gap: 0; }
.record-view .metadata-element { border-top: 1px solid var(--line);
                                 display: grid; gap: 4px 18px;
                                 grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
                                 padding: 10px 0; }
.record-view .metadata-element:first-child { border-top: 0; }
.record-view .metadata-element dt { align-content: start; display: grid;
                                    gap: 3px; justify-items: start; }
.record-view .metadata-element dt code { color: var(--dim); font-size: 10.5px;
                                         justify-self: start; overflow-wrap: anywhere;
                                         max-width: 100%; }
.record-view .metadata-element dt span { color: var(--ink); font-size: 12.5px;
                                         font-weight: 650; }
/* The rule above is for the element's name. A trace in the provenance line
   under it is a span too, and without this it was set as a second name. */
.record-view .metadata-element .metadata-source span { color: var(--dim); font-size: 9.5px;
                                                       font-weight: 400; }
/* align-content: start, or a one-line value stretches to the height of the
   name, the identifier and the provenance beside it. */
.record-view .metadata-element dd { align-content: start; display: grid; gap: 5px;
                                    margin: 0; min-width: 0; }
.record-view .metadata-element-empty dt span { color: var(--dim); font-weight: 600; }
/* An empty element: a shorter row, its name dimmed, and the reason as a small
   tag rather than a line of italics that read like a value. The two kinds of
   empty differ in more than words: none found is filled grey, not collected is
   a dashed outline, matching the segments in the category's meter. */
.record-view .metadata-element-empty { padding: 6px 0; }
.record-view .metadata-element-empty dt { align-items: baseline; display: flex;
                                          flex-wrap: wrap; gap: 2px 8px; }
.record-view .metadata-element-empty dt span { font-size: 12px; }
.record-view .metadata-absent { border-radius: 4px; font-size: 11px; font-style: normal;
                                justify-self: start; padding: 2px 8px; }
.record-view .metadata-absent-none-found { background: var(--neutral-bg); color: var(--dim); }
.record-view .metadata-absent-not-collected { border: 1px dashed var(--line); color: var(--dim); }
.record-view .metadata-values li { font-size: 12.5px; padding: 6px 9px; }
.record-view .metadata-terms li { padding: 3px 9px; }
/* The repository's description standing in for the file's: present, readable,
   and visibly not the file's own — dashed and dimmed, under its label. */
.metadata-from-container li { background: transparent; border: 1px dashed var(--line);
                              color: var(--dim); }

.record-view .metadata-note { max-width: 70ch; }
.record-view .metadata-loss { margin-bottom: 0; max-width: 78ch; }
.record-view .metadata-loss a { white-space: nowrap; }

@media (max-width: 620px) {
  .record-view { padding: 16px; }
  .record-switch { grid-template-columns: minmax(0, 1fr); }
  .record-facts dl { grid-auto-flow: row; }
  .record-view .metadata-element { grid-template-columns: minmax(0, 1fr); }
}

/* --- the rail's record summary ------------------------------------------
   Four equal grey boxes gave a count, a count and two language codes the same
   weight, and left the thing a reader wants first — how much of the description
   exists — looking like a footnote. */
.record-summary { display: grid; gap: 9px; grid-template-columns: repeat(2, minmax(0, 1fr));
                  margin-bottom: 13px; }
.record-summary-scheme { background: var(--neutral-bg); border: 1px solid var(--line);
                         border-radius: 10px; display: grid; gap: 6px; min-width: 0;
                         padding: 11px 12px; }
.record-summary-scheme > span:first-child { color: var(--dim); font: 750 9px var(--mono);
                                            letter-spacing: .07em; text-transform: uppercase; }
.record-summary-scheme strong { color: var(--ink); font-size: 19px; line-height: 1; }
.record-summary-scheme strong small { color: var(--dim); font-size: 11.5px; font-weight: 600; }
.resource-info-panel .record-summary-facts { display: grid; gap: 0;
                                             grid-template-columns: minmax(0, 1fr); }
.resource-info-panel .record-summary-facts > div { border-top: 1px solid var(--line);
                                                   display: grid; gap: 1px;
                                                   grid-template-columns: 112px minmax(0, 1fr);
                                                   padding: 8px 0; }
.resource-info-panel .record-summary-facts dt { clear: none; float: none; font-size: 10.5px;
                                                 padding-top: 1px; width: auto; }
.resource-info-panel .record-summary-facts dd { display: grid; gap: 1px; margin: 0; min-width: 0; }
.record-summary-facts dd strong { color: var(--ink); font-size: 12.5px; }
.record-summary-facts dd small { color: var(--dim); font-size: 10.5px; line-height: 1.4; }
.record-summary-note { border-top: 1px solid var(--line); color: var(--dim); font-size: 11px;
                       line-height: 1.5; margin: 0 0 13px; padding-top: 10px; }
.record-summary-note strong { color: var(--warn); }
.resource-info-panel .metadata-actions { gap: 10px; }

@media (max-width: 520px) {
  .record-summary { grid-template-columns: minmax(0, 1fr); }
  .resource-info-panel .record-summary-facts > div { grid-template-columns: minmax(0, 1fr); }
}

/* --- one tab shape, used wherever a set of views is chosen ---------------
   The resource viewer's strip is the reference: a rounded well, the chosen tab
   lifted out of it. Filter links that went bold when selected asked a reader to
   notice a font weight in a row of nine. */
.tab-strip { align-items: center; background: var(--neutral-bg); border: 1px solid var(--line);
             border-radius: 11px; display: flex; flex-wrap: wrap; gap: 3px;
             margin-bottom: 16px; padding: 4px; }
.tab-strip a { align-items: center; border-radius: 8px; color: var(--dim); display: inline-flex;
               gap: 6px; font-size: 12px; font-weight: 650; padding: 7px 11px;
               white-space: nowrap; }
.tab-strip a:hover { background: var(--panel); color: var(--ink); text-decoration: none; }
.tab-strip a.active { background: var(--panel); color: var(--accent);
                      box-shadow: 0 1px 2px rgb(0 0 0 / .10); }
.tab-count { background: var(--panel); border: 1px solid var(--line); border-radius: 999px;
             color: var(--dim); font: 700 9.5px/1.5 var(--mono); padding: 1px 6px; }
.tab-strip a.active .tab-count { border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
                                 color: var(--accent); }
.tab-strip a:hover .tab-count { background: var(--neutral-bg); }
/* Gates on one side, sources on the other: they filter different things. */
.tab-strip-split { align-self: stretch; border-left: 1px solid var(--line);
                   margin: 2px 5px; width: 0; }

/* --- the harvest run's header -------------------------------------------- */
.run-head { display: grid; gap: 16px; }
.run-head-top { align-items: flex-start; display: flex; gap: 18px;
                justify-content: space-between; }
.run-head-identity { display: grid; gap: 8px; min-width: 0; }
.run-head-identity h1 { margin: 0; }
.run-head-meta { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.run-head .chips { margin: 0; }
.run-stats { border-top: 1px solid var(--line); display: grid; gap: 12px; padding-top: 16px;
             grid-template-columns: repeat(4, minmax(120px, 1fr)) minmax(230px, 1.5fr); }
.run-stats .stat { margin: 0; }
.run-progress { display: grid; align-content: center; gap: 7px; }
.run-progress-head { align-items: baseline; display: flex; gap: 10px;
                     justify-content: space-between; }
.run-progress-head strong { color: var(--ink); font-size: 18px; }
.run-progress .bar-track { width: 100%; }

/* --- deleting a run ------------------------------------------------------ */
.run-delete { align-items: center; display: flex; flex-wrap: wrap; gap: 18px;
              justify-content: space-between; }
.run-delete-copy { flex: 1 1 320px; min-width: 0; }
.run-delete-copy h2 { margin: 0 0 5px; }
.run-delete-copy p { margin: 0; max-width: 62ch; }
.run-delete form { align-items: center; display: flex; flex-wrap: wrap; gap: 12px; }

/* --- who is signed in ---------------------------------------------------- */
.auth-avatar { align-items: center; background: var(--accent); border-radius: 50%;
               color: var(--on-accent); display: inline-flex; flex: 0 0 auto;
               font: 700 10.5px var(--mono); height: 22px; justify-content: center;
               width: 22px; }

/* --- the dashboard's two columns ---------------------------------------- */
.dash-grid { display: grid; gap: 14px;
             grid-template-columns: minmax(0, 1.85fr) minmax(290px, 1fr); }
/* The main column is a stack of cards at their own height. The table's card
   used to stretch to the side column's height, and once that column grew with
   the corpus the stretch was a tall empty card; the space now holds the
   resource-type card instead. */
.dash-main { align-content: start; display: grid; gap: 14px; min-width: 0; }
.dash-recent > p:last-child { margin-bottom: 0; padding-top: 6px; }
/* Declared and inferred in one bar: two segments, a 2px gap between them, the
   inferred one in the colour inferred values have everywhere else. */
.dash-types { min-width: 0; }
.dash-types-head { align-items: baseline; display: flex; gap: 12px;
                   justify-content: space-between; }
.dash-legend { align-items: center; color: var(--dim); display: inline-flex;
               font-size: 11.5px; gap: 5px; }
.dash-legend .swatch { background: var(--accent); border-radius: 2px; display: inline-block;
                       height: 9px; width: 9px; }
.dash-legend .swatch-inferred { background: var(--theory); margin-left: 6px; }
a.bar-row { color: inherit; text-decoration: none; }
a.bar-row:hover .bar-label { color: var(--accent); }
.bar-split { display: flex; gap: 2px; }
.bar-split > .bar { flex: 0 0 auto; min-width: 3px; }
.bar-inferred { background: var(--theory); }
.dash-side { align-content: start; display: grid; gap: 14px; min-width: 0; }
.dash-recent { min-width: 0; }
.dash-recent table { table-layout: fixed; width: 100%; }
.dash-recent .title-cell { overflow-wrap: anywhere; }
.dash-recent th:nth-child(2), .dash-recent td:nth-child(2) { width: 92px; }
.dash-recent th:nth-child(3), .dash-recent td:nth-child(3) { width: 132px; }
.dash-recent th:nth-child(4), .dash-recent td:nth-child(4) { width: 76px; }
.num-cell { font-variant-numeric: tabular-nums; text-align: right; }
.stat-n.warn-n { color: var(--warn); }

@media (max-width: 1080px) {
  .dash-grid { grid-template-columns: minmax(0, 1fr); }
  .run-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .run-progress { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .run-head-top { flex-direction: column; }
  .run-stats { grid-template-columns: minmax(0, 1fr); }
}

/* --- the account menu ----------------------------------------------------
   The avatar, the name, the theme toggle and the sign-out button were four
   loose controls at the end of the bar. They are one menu, built on the same
   <details> the nav menus use, so it closes the way they do. */
.account-dropdown > summary .auth-avatar { margin-right: 7px; }
/* A link here (Django admin, signing in) is outside the bar's <nav>, so without
   its own rule it took the page's link colour and stood out in blue among the
   buttons. It looks like them because it is one more item of the same menu. */
.account-dropdown-panel > a,
.account-dropdown-panel .theme-toggle,
.account-dropdown-panel .account-action {
  align-items: flex-start; background: transparent; border: 0; border-radius: 6px;
  color: var(--ink); cursor: pointer; display: flex; font: inherit; gap: 3px;
  min-height: 42px; padding: 7px 9px; text-align: left; width: 100%; }
.account-dropdown-panel > a:hover,
.account-dropdown-panel .theme-toggle:hover,
.account-dropdown-panel .account-action:hover { background: var(--accent-soft);
                                                text-decoration: none; }
.account-dropdown-panel > a .ico,
.account-dropdown-panel .theme-toggle .ico,
.account-dropdown-panel .account-action .ico {
  flex: 0 0 auto; height: 16px; margin: 3px 5px 0 0; width: 16px; }
.account-action-form { margin: 0; }
.account-identity { color: var(--ink); display: grid; font-size: 12.5px; font-weight: 680;
                    gap: 1px; padding: 0 9px 7px; }
.account-identity small { color: var(--dim); font-size: 9.5px; font-weight: 450; }

/* One repository is a GitHub repository: the other two sources are held, not
   hidden, so the screen still shows the whole shape of the plan. */
.source-option.is-locked { opacity: .45; }
.source-option.is-locked input { cursor: not-allowed; }

/* --- the engine's one confirmation dialog -------------------------------
   window.confirm paints the browser's chrome over the page and cannot show what
   is about to be destroyed, which for "empty the store" is the only thing worth
   showing. */
.confirm-dialog { background: var(--panel); border: 1px solid var(--line);
                  border-radius: 14px; box-shadow: 0 24px 60px var(--floating-shadow);
                  color: var(--ink); max-width: 480px; padding: 0; width: calc(100% - 32px); }
.confirm-dialog::backdrop { background: rgb(8 12 20 / .55); backdrop-filter: blur(2px); }
.confirm-dialog form { display: grid; gap: 12px; padding: 20px 22px 18px; }
.confirm-dialog h2 { color: var(--ink); font-size: 17px; letter-spacing: -.01em;
                     margin: 0; text-transform: none; }
.confirm-dialog p { color: var(--dim); font-size: 13px; line-height: 1.5; margin: 0; }
.confirm-list { display: grid; gap: 6px; list-style: none; margin: 0; padding: 0; }
.confirm-list li { background: var(--neutral-bg); border: 1px solid var(--line);
                   border-radius: 8px; color: var(--ink); font-size: 12.5px;
                   padding: 8px 11px; }
.confirm-caveat { background: var(--bad-bg); border-radius: 8px; color: var(--bad) !important;
                  font-size: 12px; padding: 9px 11px; }
.confirm-actions { display: flex; gap: 9px; justify-content: flex-end; margin-top: 2px; }

/* The one control in the viewer strip that leaves the page. At the top of the
   screen beside "back to the library" it read as navigation rather than as the
   way to the source. */
.source-view-open { font-size: 11.5px; margin-left: 10px; padding: 6px 11px;
                    white-space: nowrap; }
.source-viewer-bare .source-view-tabs { border-bottom: 0; padding-bottom: 0; }

/* --- review: a reviewer's rounds, and the screen a resource is read on -------
   The reading screen is the resource page's two columns: the text where the
   viewer is, the grading panel where the information rail is, sticky, so the
   rows stay in view while the text scrolls under them. */
.grading-turns { margin-top: 10px; }
.grading-turns > summary { color: var(--accent); cursor: pointer; font-size: 12px; font-weight: 700; }
.grading-turns[open] > summary { margin-bottom: 8px; }

.grading-pagehead { align-items: flex-start; display: flex; flex-wrap: wrap; gap: 12px 20px;
  justify-content: space-between; }
.grading-pagehead > div { flex: 1 1 520px; }
.grading-subhead { color: var(--ink); font-size: 13px; margin: 18px 0 2px; text-transform: none; }
.grading-figures { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); margin: 12px 0; }
.grading-figures dt[data-tip] { cursor: help; text-decoration: underline dotted; text-underline-offset: 3px; }
/* A round's page: the analysis on the left, the round's state beside it. */
.grading-round-layout { align-items: start; display: grid; gap: 16px;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); }
/* minmax(0, 1fr): an implicit track grows to its widest table's min-content and
   pushes the page sideways; this one lets the table's own scroller take it. */
.grading-round-main, .grading-round-side { display: grid; gap: 16px; grid-template-columns: minmax(0, 1fr);
  min-width: 0; }
.grading-round-main > .card, .grading-round-side > .card { margin: 0; min-width: 0; }
@media (max-width: 1050px) { .grading-round-layout { grid-template-columns: minmax(0, 1fr); } }
.grading-compact th, .grading-compact td { white-space: nowrap; }
.grading-compact td:first-child { white-space: normal; }
.grading-share { align-items: center; display: inline-grid; gap: 8px; grid-template-columns: 80px auto; }
.grading-share .bar-track { height: 8px; }
.grading-share .bar { height: 8px; }
.grading-progress-list { display: grid; gap: 10px; list-style: none; margin: 10px 0 0; padding: 0; }
.grading-progress-list li { display: grid; gap: 4px; }
.grading-progress-list li > div { display: flex; flex-wrap: wrap; font-size: 12.5px; gap: 2px 8px;
  justify-content: space-between; }
.grading-progress-list .bar-track { height: 7px; }
.grading-progress-list .bar { height: 7px; }
.grading-side-note { font-size: 11.5px; line-height: 1.45; margin: 8px 0 0; }
.grading-resources { margin-top: 16px; }
.grading-empty p { margin: 0; }
.grading-resources > summary { color: var(--accent); cursor: pointer; font-size: 13px; font-weight: 700; }
.grading-resources[open] > summary { margin-bottom: 10px; }
.grading-confusion th { white-space: nowrap; }
.grading-confusion th .alignment-level { font-size: 10.5px; height: 19px; margin-right: 4px; width: 19px; }
.grading-confusion { max-width: 720px; }
.grading-confusion td { font-family: var(--mono); text-align: center; }
.grading-confusion td.grading-diagonal { background: var(--ok-bg); color: var(--ok); font-weight: 700; }
.grading-downloads { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 6px; }
.grading-facts { display: grid; font-size: 13px; gap: 6px 16px; grid-template-columns: max-content 1fr;
  margin: 0; }
.grading-facts dt { color: var(--dim); font-weight: 650; }
.grading-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.grading-new-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.grading-new-grid label[hidden] { display: none; }
/* The new round's advanced settings: each a label, its field and why it is there. */
.grading-advanced { display: grid; gap: 4px; margin-top: 10px; max-width: 640px; }
.grading-advanced .field-label { margin: 10px 0 2px; }
.grading-advanced input { background: var(--panel); border: 1px solid var(--line); border-radius: 7px;
  color: var(--ink); font-size: 13px; max-width: 200px; padding: 7px 9px; }
.grading-advanced p { font-size: 12px; line-height: 1.45; margin: 2px 0 0; }
/* The summary rail has no tabs: head, figures, body. */
.compose-rail .grading-plan-shell { grid-template-rows: auto auto minmax(0, 1fr); }
.grading-plan-line { color: var(--ink); font-size: 13px; line-height: 1.5; margin: 0; }
.grading-plan-line:empty { display: none; }
.grading-plan-warnings { display: grid; gap: 6px; list-style: none; margin: 8px 0 0; padding: 0; }
.grading-plan-warnings:empty { display: none; }
.grading-plan-warnings li { background: var(--warn-bg); border-radius: 7px; color: var(--warn);
  font-size: 12px; font-weight: 600; padding: 7px 10px; }
@media (max-width: 680px) {
  .grading-plan-shell .gap-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.grading-shell { grid-template-rows: auto minmax(0, 1fr) auto; }
.grading-body { padding-top: 4px; }
.grading-fields { border: 0; margin: 0; min-width: 0; padding: 0; }
.grading-group { border-bottom: 1px solid var(--line); display: grid; gap: 4px; padding: 16px 0 14px; }
.grading-group:last-child { border-bottom: 0; }
.grading-group-head { align-items: baseline; display: flex; gap: 10px; justify-content: space-between;
  margin-bottom: 4px; }
.grading-group-head h3 { color: var(--ink); font-size: 13.5px; font-weight: 750; letter-spacing: -.005em;
  margin: 0; text-transform: none; }
.grading-group.has-error .grading-group-head h3 { color: var(--bad); }
.grading-count { color: var(--dim); font-size: 11px; white-space: nowrap; }
.grading-count.is-done { color: var(--ok); font-weight: 650; }
.grading-legend { color: var(--dim); display: flex; flex-wrap: wrap; font-size: 11.5px; gap: 4px 14px;
  margin: 0 0 6px; }
.grading-legend > span { align-items: center; display: inline-flex; gap: 5px; }
.grading-legend .alignment-level { font-size: 10px; height: 17px; width: 17px; }
.grading-select { background: var(--panel); border: 1px solid var(--line); border-radius: 7px;
  color: var(--ink); font-size: 12px; min-width: 0; padding: 6px 8px; }
.is-moot { opacity: .4; }

/* A segmented control: one choice of a few, the chosen one tinted by what it
   means — a level in the rubric's colours, an answer green, amber or red. */
.grading-seg { background: var(--neutral-bg); border: 1px solid var(--line); border-radius: 8px;
  display: inline-flex; flex: 0 0 auto; overflow: hidden; }
.grading-seg-option { cursor: pointer; display: flex; flex: 1 1 0; position: relative; }
.grading-seg-option + .grading-seg-option { border-left: 1px solid var(--line); }
/* The hidden radio covers its option, so the pointer is set on it: a radio's
   own cursor is the arrow. */
.grading-seg-option input { cursor: pointer; inset: 0; margin: 0; opacity: 0; position: absolute; }
.grading-seg-option span { color: var(--dim); font-size: 12px; font-weight: 600; padding: 6px 12px;
  text-align: center; white-space: nowrap; width: 100%; }
.grading-levels .grading-seg-option span { font-family: var(--mono); min-width: 38px; padding: 6px 0; }
.grading-seg-option:hover span { background: color-mix(in srgb, var(--ink) 7%, var(--neutral-bg)); color: var(--ink); }
.grading-seg-option input:focus-visible + span { box-shadow: inset 0 0 0 2px var(--accent); }
.grading-seg-option input:checked + span { background: var(--accent-soft); color: var(--accent); font-weight: 750; }
.grading-seg-option.level-0 input:checked + span { background: var(--line); color: var(--ink); }
.grading-seg-option.level-1 input:checked + span { background: var(--warn-bg); color: var(--warn); }
.grading-seg-option.level-2 input:checked + span { background: var(--accent-soft); color: var(--accent); }
.grading-seg-option.level-3 input:checked + span { background: var(--ok); color: var(--panel); }
.grading-seg-option.answer-yes input:checked + span { background: var(--ok-bg); color: var(--ok); }
.grading-seg-option.answer-partly input:checked + span { background: var(--warn-bg); color: var(--warn); }
.grading-seg-option.answer-no input:checked + span { background: var(--bad-bg); color: var(--bad); }
.grading-seg-wide { width: 100%; }
.grading-seg-answers .grading-seg-option span { min-width: 58px; }

/* A question about the resource, and a competency: its code, its name with a
   line under it, and its control on the right. */
.grading-rate { align-items: center; display: grid; gap: 6px 12px; grid-template-columns: minmax(0, 1fr) auto;
  padding: 8px 0; }
.grading-rate + .grading-rate { border-top: 1px solid var(--line); }
.grading-rate:has(> .grading-row-code) { grid-template-columns: 38px minmax(0, 1fr) auto; }
.grading-rate:has(> .grading-seg-wide) { grid-template-columns: minmax(0, 1fr); }
.grading-row-code { background: none; color: var(--accent); font: 750 12px var(--mono); padding: 0; }
.grading-row-title { display: grid; gap: 1px; min-width: 0; }
.grading-row-title strong { color: var(--ink); font-size: 13px; line-height: 1.3; }
.grading-row-sub { color: var(--dim); font-size: 11.5px; line-height: 1.35; }
/* The active row is a soft block with a hairline ring. A thick left border on a
   rounded box curved at its corners into a tab, which read as an ornament. */
.grading-row { border: 0; border-radius: 10px; display: grid; gap: 7px; margin: 0 -8px; min-width: 0;
  padding: 10px 8px 10px; }
.grading-row + .grading-row, .grading-row + [data-added-rows] .grading-row:first-child { border-top: 1px solid var(--line);
  border-top-left-radius: 0; border-top-right-radius: 0; }
.grading-row:focus { outline: none; }
.grading-row.is-active { background: var(--neutral-bg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, var(--line)); }
.grading-row.has-error { box-shadow: inset 0 0 0 1px var(--bad); }
.grading-row-main { align-items: center; display: grid; gap: 4px 12px; grid-template-columns: 38px minmax(0, 1fr) auto; }
/* A mention does nothing for a learner, and reads that way. */
.grading-row.is-mention .grading-row-title strong { color: var(--dim); text-decoration: line-through; }
.grading-link { background: none; border: 0; color: var(--accent); cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 650; padding: 0; }
.grading-link:hover { text-decoration: underline; }
.grading-row-sub .grading-link { font-size: 11.5px; }
.grading-row-terms { color: var(--dim); font-size: 11px; line-height: 1.35; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
/* Why a 1 is only a mention: one line of words, the chosen one tinted, the letter
   that picks each underlined — six pill buttons read as a second control. */
.grading-reasons { align-items: center; display: flex; flex-wrap: wrap; font-size: 11.5px; gap: 2px 2px;
  padding-left: 50px; }
.grading-reasons[hidden] { display: none; }
.grading-reasons-label { color: var(--dim); margin-right: 4px; }
.grading-reason { cursor: pointer; position: relative; }
.grading-reason input { cursor: pointer; inset: 0; margin: 0; opacity: 0; position: absolute; }
.grading-reason span { border-radius: 6px; color: var(--ink); display: inline-block; padding: 2px 7px; }
.grading-reason u { text-decoration-color: var(--dim); text-underline-offset: 2px; }
.grading-reason:hover span { background: var(--neutral-bg); }
.grading-reason input:checked + span { background: var(--warn-bg); color: var(--warn); font-weight: 700; }
.grading-reason input:focus-visible + span { box-shadow: inset 0 0 0 2px var(--accent); }
.grading-descriptor { border-left: 2px solid var(--line); margin-left: 50px; padding: 2px 0 2px 12px; }
.grading-descriptor p { font-size: 11.5px; line-height: 1.45; margin: 6px 0 2px; }
.grading-descriptor .descriptor-list { font-size: 11.5px; line-height: 1.45; }
.grading-row-added .grading-row-title strong { font-weight: 650; }

/* The reading screen's bar: where the reviewer is, how far they have gone, and
   the way to the other resources, together. */
.grading-topbar { align-items: center; background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  display: grid; gap: 10px 22px; grid-template-columns: auto minmax(180px, 1fr) auto; margin: 4px 0 14px;
  padding: 10px 14px; }
.grading-topbar-where { display: grid; gap: 1px; }
.grading-topbar-where strong { color: var(--ink); font-size: 15px; letter-spacing: -.01em; }
.grading-topbar-progress { align-items: center; color: var(--dim); display: flex; font-size: 12px; gap: 12px; }
.grading-topbar-progress .bar-track { flex: 1 1 auto; height: 8px; max-width: 420px; }
.grading-topbar-progress .bar { height: 8px; min-width: 6px; }
.grading-topbar-nav { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.btn.is-off { cursor: default; opacity: .45; pointer-events: none; }
.grading-hero { margin-bottom: 14px; }
@media (max-width: 860px) {
  .grading-topbar { grid-template-columns: minmax(0, 1fr); }
  .grading-topbar-nav { justify-content: flex-start; }
}
/* A third reader's view of a row: what each reader gave, as letters. */
.grading-readings { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.grading-reading { align-items: center; color: var(--dim); display: inline-flex; font-size: 11.5px;
  gap: 5px; }
.grading-reading .alignment-level { font-size: 10.5px; height: 19px; width: 19px; }
.grading-settle { background: var(--accent-soft); border-radius: 8px; color: var(--ink);
  font-size: 12px; line-height: 1.5; margin: 12px 0 0; padding: 9px 11px; }
.grading-settle p { margin: 0; }
.grading-settle p + p { margin-top: 6px; }
.grading-settle-note { color: var(--dim); }
.grading-assign { align-items: end; display: flex; flex-wrap: wrap; gap: 10px; margin: 14px 0 4px; }
.grading-assign .filter-control { min-width: 220px; }
.grading-row-error { color: var(--bad); font-size: 11.5px; font-weight: 650; margin: 0; }
.grading-add { display: grid; gap: 6px; padding-top: 6px; }
.grading-add-controls { display: grid; gap: 6px; grid-template-columns: minmax(0, 1fr) auto auto; }
.grading-add-controls input[type="search"] { width: 100%; }
.grading-note { background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink); font: inherit; font-size: 12.5px; padding: 8px 10px; resize: vertical; width: 100%; }
.grading-error { background: var(--bad-bg); border-radius: 8px; color: var(--bad); font-size: 12px;
  font-weight: 650; margin: 12px 0 0; padding: 8px 11px; }
.grading-notice { background: var(--warn-bg); border-radius: 8px; color: var(--warn); font-size: 12px;
  margin: 12px 0 0; padding: 8px 11px; }
.source-viewer .grading-notice { margin: 12px 18px 0; }
.grading-foot { background: var(--panel); border-top: 1px solid var(--line); display: grid; gap: 8px;
  padding: 10px 16px 12px; }
/* The shortcuts as a list of keys and what each does. An item never breaks, so a
   narrow panel wraps between two of them, never inside one. */
.grading-keys { color: var(--dim); display: flex; flex-wrap: wrap; font-size: 11px; gap: 4px 14px;
  line-height: 1.5; list-style: none; margin: 0; padding: 0; }
.grading-keys li { align-items: center; display: inline-flex; gap: 5px; white-space: nowrap; }
.key-combo { align-items: center; display: inline-flex; gap: 2px; }
.key-combo kbd { font-size: 10px; line-height: 14px; min-width: 18px; padding: 0 4px; text-align: center; }
/* The modifier this keyboard has, read in the page's head: ⌘ on a Mac, Ctrl
   elsewhere and wherever the script did not run. */
.key-mac, [data-keys="mac"] .key-pc { display: none; }
[data-keys="mac"] .key-mac { display: inline-flex; }
/* A monospace face draws ⌘ and ↵ at half the height of a letter. */
.key-mac kbd { font-family: system-ui, -apple-system, sans-serif; font-size: 11px; }
.grading-actions { align-items: center; display: flex; gap: 6px; }
.grading-actions .btn-primary { margin-left: auto; }
.grading-missing { color: var(--dim); font-size: 11px; margin-left: auto; }
.grading-missing:empty { display: none; }
.grading-missing:not(:empty) + .btn-primary { margin-left: 0; }
.grading-page-select { background: var(--panel); border: 1px solid var(--line); border-radius: 7px;
  color: var(--ink); font-size: 12px; max-width: 360px; min-width: 0; padding: 5px 8px; }
/* The evidence of the active row, and its terms wherever they occur. */
.doc-body .grading-lit { background: var(--evidence-bg); border-radius: 4px;
  box-shadow: 0 0 0 4px var(--evidence-bg); scroll-margin: 90px 0; }
.doc-body mark.grading-term { background: transparent; color: inherit;
  text-decoration: underline 2px var(--evidence-line); text-underline-offset: 3px; }

/* --- the alignment page: the steps beside the one picked --------------------
   The catalogue's list and detail. On the left the five steps, each with its
   figures in a line and, in amber, what waits; on the right the step picked:
   what it does, its figures, its one action and what there is to know about it.
   Side by side as a strip, and one under another as a long page, the steps left
   the action far from its text. */
/* The panel opens on how far the way has got, a sentence and a bar; then each
   step, a small marker on a thin track, a tick once it is done and an outline
   in the accent for the next one; its name and, under it, its figures in grey,
   with only what waits or runs in colour. The step picked is lifted in grey,
   not in the accent: filled blue markers, a blue title and a blue background
   pulled the eye from the figures, and an accent edge down its side was one
   more thing to look at. */
.flow-layout { grid-template-columns: minmax(320px, 380px) minmax(0, 1fr); }
@media (max-width: 980px) { .flow-layout { grid-template-columns: minmax(0, 1fr); } }
.flow-layout .catalogue-side { gap: 16px; padding: 20px 10px 10px; }
.flow-progress { display: grid; gap: 10px; padding: 0 14px 6px; }
.flow-progress-head { align-items: baseline; color: var(--dim); display: flex; font-size: 12px;
  justify-content: space-between; margin: 0; }
.flow-progress-head strong { color: var(--ink); font-size: 14px; letter-spacing: -.01em; }
.flow-progress-track { background: var(--neutral-bg); border-radius: 999px; display: block;
  height: 6px; overflow: hidden; }
.flow-progress-track > span { background: var(--ok); border-radius: inherit; display: block;
  height: 100%; transition: width .4s ease; }
.flow-index { display: grid; gap: 6px; }
.flow-index-item { align-items: start; border-radius: 10px; color: var(--ink); display: grid;
  gap: 0 14px; grid-template-columns: 24px minmax(0, 1fr); padding: 16px 14px 17px;
  position: relative; text-decoration: none; }
.flow-index-item:hover { background: var(--neutral-bg); text-decoration: none; }
.flow-index-item.is-selected { background: var(--neutral-bg); }
/* From under one marker to the top of the next: the marker's centre is the
   step's padding and half the marker in, and the next marker starts the gap
   and the next step's padding down. */
.flow-index-item:not(:last-child)::after { background: var(--line); bottom: -18px; content: "";
  left: 25px; position: absolute; top: 44px; width: 1.5px; z-index: 1; }
.flow-index-text { display: grid; gap: 6px; min-width: 0; padding-top: 2px; }
.flow-index-text strong { font-size: 14px; font-weight: 600; line-height: 1.35; }
.flow-index-next { color: var(--accent); font-size: 11.5px; font-weight: 500; margin-left: 4px; }
.flow-index-meta { color: var(--dim); font-size: 12.5px; line-height: 1.5; }
.flow-index-meta .is-warn { color: var(--warn); font-weight: 600; }
.flow-index-meta .is-live { color: var(--accent); font-weight: 600; }
.flow-marker { align-items: center; background: var(--panel); border: 1.5px solid var(--line);
  border-radius: 999px; color: var(--dim); display: inline-flex; font: 700 11.5px/1 var(--mono);
  height: 24px; justify-content: center; position: relative; width: 24px; z-index: 2; }
/* Without the margin every icon of the app keeps to its right, the tick sat
   off the circle's centre. */
.flow-marker .ico { height: 13px; margin: 0; vertical-align: 0; width: 13px; }
.is-done .flow-marker { background: var(--ok-bg); border-color: transparent; color: var(--ok); }
.is-next .flow-marker, .is-running .flow-marker { border-color: var(--accent);
  color: var(--accent); }
.is-running .flow-marker { animation: flow-pulse 1.6s ease-in-out infinite; }
@keyframes flow-pulse { 50% { box-shadow: 0 0 0 5px var(--accent-soft); } }
/* What is running says so in the accent, its dot breathing. */
.status-dot.is-live { color: var(--accent); }
.status-dot.is-live::before { animation: dot-pulse 1.6s ease-in-out infinite; }
@keyframes dot-pulse { 50% { box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 25%, transparent); } }
@media (prefers-reduced-motion: reduce) {
  .is-running .flow-marker, .status-dot.is-live::before { animation: none; }
}
.flow-detail { margin: 0; }
.flow-detail-meta { align-items: center; color: var(--dim); display: flex; flex-wrap: wrap;
  font-size: 12px; gap: 6px 12px; margin: 0 0 4px; }
.flow-detail-meta .status-dot { font-size: 11.5px; font-weight: 600; }
.flow-detail-head h2 { color: var(--ink); font-size: 20px; letter-spacing: -.01em; margin: 0 0 6px;
  text-transform: none; }
.flow-detail-head p:last-child { color: var(--dim); margin: 0; max-width: 820px; }
.flow-tiles { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  margin-top: 16px; }
.flow-tiles .competency-figure { align-content: start; }
/* A table of a step's details says what each column counts in words, so its
   heads may take two lines rather than run off the card. */
.flow-detail .grading-compact th { vertical-align: bottom; white-space: normal; }
.flow-act { align-items: center; display: flex; flex-wrap: wrap; gap: 10px 12px; margin-top: 16px; }
.flow-act form { margin: 0; }
.flow-act .dim { flex-basis: 100%; font-size: 12px; line-height: 1.45; margin: 0; }
.flow-note { background: var(--neutral-bg); border-radius: 8px; color: var(--dim); font-size: 12.5px;
  line-height: 1.45; margin: 14px 0 0; padding: 9px 12px; }
.flow-detail-foot { border-top: 1px solid var(--line); color: var(--dim); font-size: 13px;
  margin-top: 18px; padding-top: 12px; }
.flow-detail-foot a::after { content: " →"; }
/* A pass while it runs, inside its step: its own three phases, the one it is
   in carrying the accent and the ones behind it the colour of done. */
.flow-live { background: var(--panel); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: 10px; margin-top: 14px; padding: 12px 16px; }
.flow-live-title { color: var(--ink); font-size: 13px; font-weight: 650; margin: 0; }
.phase-flow { display: grid; gap: 14px 0; grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none; margin: 12px 0 4px; padding: 0; }
.phase { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding-right: 22px; }
.phase-marker { align-items: center; display: flex; gap: 10px; margin-bottom: 4px; }
.phase-marker::after { background: var(--line); border-radius: 2px; content: ""; flex: 1; height: 2px; }
.phase:last-child .phase-marker::after { visibility: hidden; }
.phase-step { align-items: center; background: var(--panel); border: 2px solid var(--line); border-radius: 999px;
  color: var(--dim); display: inline-flex; flex: 0 0 auto; font: 750 11px/1 var(--mono); height: 26px;
  justify-content: center; width: 26px; }
.phase-here .phase-step { background: var(--accent); border-color: var(--accent); color: var(--on-accent);
  box-shadow: 0 0 0 4px var(--accent-soft); }
.phase-done .phase-step { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.phase-done .phase-marker::after { background: var(--ok); }
.phase h3 { color: var(--ink); font-size: 13.5px; letter-spacing: -.01em; margin: 0; text-transform: none; }
.phase-figure { align-items: baseline; display: flex; flex-wrap: wrap; gap: 6px; }
.phase-figure strong { color: var(--ink); font: 750 18px/1 var(--mono); letter-spacing: -.02em; }
.phase-figure span { color: var(--dim); font-size: 12px; }
.phase-detail { color: var(--dim); font-size: 11.5px; margin: 0; }
.grading-run-bar { display: block; margin: 10px 0 6px; overflow: hidden; position: relative; }
.grading-run-bar .bar { position: relative; transition: width .4s ease; z-index: 1; }
.grading-run-bar .bar-ahead { background: color-mix(in srgb, var(--accent) 28%, transparent);
  inset: 0 auto 0 0; position: absolute; z-index: 0; }
@media (max-width: 640px) {
  .phase-flow { grid-template-columns: minmax(0, 1fr); }
  .phase-marker::after { display: none; }
  .flow-live { padding: 10px 12px; }
}

/* --- the debug view: what each stage and round made of a resource ----------
   Staff only, per session. Dashed, so it never passes for part of the record.
   Its flag in the bar is the app's dot with a word, in the view's amber: a
   dashed box in monospace capitals was the loudest thing in the bar. */
.debug-flag { cursor: help; font-size: 11.5px; font-weight: 600; margin-right: 6px; }
.debug-strip { background: color-mix(in srgb, var(--warn-bg) 45%, var(--panel));
  border-top: 1px dashed color-mix(in srgb, var(--warn) 55%, var(--line)); display: grid; gap: 4px;
  padding: 8px 18px 9px; }
.debug-line { align-items: baseline; display: flex; flex-wrap: wrap; font-size: 11.5px; gap: 3px 12px; }
/* The library's debug filters: the view's dashed amber, around a group of
   filters like the others. */
.debug-filters { background: color-mix(in srgb, var(--warn-bg) 35%, var(--panel));
  border: 1px dashed color-mix(in srgb, var(--warn) 55%, var(--line)); border-radius: 9px;
  padding: 10px 12px 12px; }
.debug-label { color: var(--dim); cursor: help; flex: 0 0 auto; font: 750 9.5px var(--mono); letter-spacing: .07em;
  min-width: 62px; text-transform: uppercase; }
.debug-code { color: var(--accent); font: 750 11.5px var(--mono); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent); text-underline-offset: 3px; }
.debug-level { cursor: help; text-decoration: none; }
.debug-level.level-3 { color: var(--ok); }
.debug-level.level-2 { color: var(--accent); }
.debug-level.level-1 { color: var(--warn); }
.debug-level.level-0 { color: var(--dim); }
/* Not decided is not wrong: dim, like the rest of what is still open. */
.debug-level.level-open { color: var(--dim); }
/* A code and its word, kept together on a wrap: the code in ink, the word in
   its level's colour. */
.debug-pair { align-items: baseline; cursor: help; display: inline-flex; gap: 5px; white-space: nowrap; }
.debug-pair .debug-code { color: var(--ink); text-decoration: none; }
.debug-pair .debug-level { font-size: 11.5px; font-weight: 650; }
.debug-none { color: var(--dim); }
/* The resource page's Debug tab: each competency a button that lights its
   evidence in the text. */
.resource-info-tab-debug { color: var(--warn); }
.resource-info-tab-debug.active { border-bottom-color: var(--warn); color: var(--warn); }
.debug-section .info-section-head h3 { margin: 2px 0; }
.debug-heading { align-items: baseline; color: var(--ink); display: flex; flex-wrap: wrap; font-size: 12px;
  gap: 4px 10px; justify-content: space-between; margin: 16px 0 6px; }
.debug-heading a { font-size: 11px; font-weight: 600; }
.debug-list { display: grid; gap: 2px; list-style: none; margin: 0; padding: 0; }
.debug-row { align-items: start; background: none; border: 0; border-radius: 8px; color: inherit; cursor: pointer;
  display: grid; font: inherit; gap: 2px 10px; grid-template-columns: 38px minmax(0, 1fr) auto; padding: 7px 8px;
  text-align: left; width: 100%; }
.debug-row:hover { background: var(--neutral-bg); }
.debug-row.is-active { background: var(--neutral-bg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 45%, var(--line)); }
.debug-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.debug-row-main { display: grid; gap: 1px; min-width: 0; }
.debug-row-main strong { color: var(--ink); font-size: 12.5px; line-height: 1.3; }
.debug-row-main small { color: var(--dim); font-size: 11px; line-height: 1.35; }
.debug-row .alignment-level { font-size: 10.5px; height: 20px; width: 20px; }
.debug-open { color: var(--bad); font: 750 12px var(--mono); }
.debug-row-main .debug-terms { color: var(--theory); }
.debug-list-muted .debug-row-main strong { color: var(--dim); font-weight: 600; }
.debug-row .debug-code { padding-top: 1px; text-decoration: none; }

/* --- the rounds list and a reviewer's list --------------------------------- */
.grading-figures dd small { color: var(--dim); font: 600 11px var(--mono); }
/* The rounds together, as one line of facts with an icon each, as a library
   card's foot reads: no tiles, no labels in capitals over the figures. */
.grading-summary { align-items: center; color: var(--dim); display: flex; flex-wrap: wrap; font-size: 13px;
  gap: 6px 24px; margin: 0 0 22px; }
.grading-list-heading { color: var(--ink); font-size: 15px; font-weight: 700; letter-spacing: normal;
  margin: 22px 0 10px; text-transform: none; }
.grading-roundlist { display: grid; gap: 12px; }
.grading-roundcard { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; display: grid;
  gap: 12px; padding: 16px 18px; transition: border-color .15s; }
.grading-roundcard:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.grading-roundcard.is-closed { background: color-mix(in srgb, var(--neutral-bg) 45%, var(--panel)); }
.grading-roundcard-head { align-items: flex-start; display: flex; flex-wrap: wrap; gap: 10px 18px;
  justify-content: space-between; }
.grading-roundcard-head > div { display: grid; flex: 1 1 380px; gap: 3px; min-width: 0; }
.grading-roundcard-head p { font-size: 12.5px; margin: 0; }
/* A round's name with its state beside it as a word in a badge, where a
   kicker in capitals above it used to say "Normal round · open". */
.grading-roundcard-name { align-items: center; display: flex; flex-wrap: wrap; font-size: inherit; gap: 6px 10px;
  letter-spacing: normal; margin: 0; text-transform: none; }
.grading-roundcard-name .badge { letter-spacing: .02em; }
.grading-roundcard-title { color: var(--ink); font-size: 18px; font-weight: 750; letter-spacing: -.01em; }
a.grading-roundcard-title:hover { color: var(--accent); }
.grading-roundcard-body { border-top: 1px solid var(--line); display: grid; gap: 14px 28px;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1.4fr) minmax(0, .8fr) minmax(0, 1fr); padding-top: 14px; }
/* A figure is a sentence over its bar: the words say what the bar is. */
.grading-meter { align-content: start; display: grid; gap: 6px; min-width: 0; }
.grading-meter .bar-track { height: 8px; }
.grading-meter .bar { height: 8px; min-width: 4px; }
.grading-meter-value { color: var(--dim); font-size: 13px; font-variant-numeric: tabular-nums; line-height: 1.4; }
.grading-meter-value strong { color: var(--ink); }
.grading-meter-value strong[data-tip] { cursor: help; }
.grading-meter-note { color: var(--dim); font-size: 11.5px; line-height: 1.35; }
.grading-stack { background: var(--neutral-bg); border-radius: 999px; display: flex; height: 8px; overflow: hidden; }
.grading-stack > span { display: block; height: 100%; }
.grading-stack .is-settled, .grading-key.is-settled { background: var(--ok); }
.grading-stack .is-waiting, .grading-key.is-waiting { background: var(--warn); }
.grading-key { border-radius: 2px; display: inline-block; height: 8px; margin-right: 4px; width: 8px; }
.grading-people { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.grading-people li { align-items: center; background: var(--neutral-bg); border-radius: 999px; color: var(--ink);
  cursor: default; display: inline-flex; font-size: 12px; gap: 6px; padding: 2px 9px 2px 2px; }
.grading-people li.dim { background: none; padding: 0; }
.grading-people small { color: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums; }
.grading-avatar { align-items: center; background: var(--accent); border-radius: 50%; color: var(--on-accent); display: inline-flex;
  font-size: 11px; font-weight: 750; height: 22px; justify-content: center; width: 22px; }
.grading-avatar.is-done { background: var(--ok); color: var(--on-ok); }
@media (max-width: 1100px) {
  .grading-roundcard-body { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .grading-roundcard-body { grid-template-columns: minmax(0, 1fr); }
}
.grading-alldone { color: var(--ok); font-weight: 650; margin: 0 0 16px; }
/* A reviewer's list (reviews.html): what comes next, then each round as a
   table whose columns line up — the resource, and what reading it takes. The
   whole row opens the resource; the title is the link and stretches over it. */
.review-next { align-items: center; display: grid; gap: 14px 32px;
  grid-template-columns: minmax(0, 1fr) auto; }
.review-next-copy { display: grid; gap: 4px; min-width: 0; }
.review-next-where { color: var(--dim); font-size: 12.5px; margin: 0; }
.review-next h2 { color: var(--ink); font-size: 20px; letter-spacing: -.01em; line-height: 1.25;
  margin: 0; text-transform: none; }
.review-next h2 a { color: var(--ink); }
.review-next h2 a:hover { color: var(--accent); }
.review-facts { color: var(--dim); font-size: 13px; margin: 0; }
.review-next-action { display: grid; gap: 7px; justify-items: end; text-align: right; }
.review-next-action p { font-size: 12px; margin: 0; }
.review-round { display: grid; gap: 12px; }
.review-round.is-closed { background: color-mix(in srgb, var(--neutral-bg) 45%, var(--panel)); }
.review-round-head { align-items: center; display: flex; flex-wrap: wrap; gap: 10px 32px;
  justify-content: space-between; }
.review-round-head > div:first-child { display: grid; flex: 1 1 420px; gap: 3px; min-width: 0; }
.review-round-head h2 { color: var(--ink); font-size: 18px; letter-spacing: -.01em; margin: 0;
  text-transform: none; }
.review-round-head p { font-size: 12.5px; line-height: 1.45; margin: 0; }
.review-state::before { background: var(--dim); border-radius: 50%; content: ""; display: inline-block;
  height: 7px; margin-right: 6px; vertical-align: 1px; width: 7px; }
.review-state.is-open::before { background: var(--ok); }
.review-round-progress { align-items: center; display: grid; font-size: 12.5px; gap: 12px;
  grid-template-columns: auto minmax(160px, 260px); white-space: nowrap; }
.review-round-progress .bar-track, .review-round-progress .bar { height: 8px; }
/* Fixed columns, so the list still to read and the list read line up. */
.review-table { table-layout: fixed; }
.review-c-num { width: 52px; }
.review-c-format { width: 120px; }
.review-c-length, .review-c-asks { width: 130px; }
.review-c-state { width: 120px; }
.review-table th { font-size: 11.5px; padding: 6px 12px; white-space: nowrap; }
.review-table td { padding: 10px 12px; vertical-align: middle; }
.review-table tbody tr { position: relative; }
.review-table tbody tr:hover { background: var(--neutral-bg); }
.review-table tbody tr:last-child td { border-bottom: 0; }
.review-title a { color: var(--ink); font-weight: 600; }
.review-title a::after { content: ""; inset: 0; position: absolute; }
.review-table tbody tr:hover .review-title a { color: var(--accent); }
.review-title a:focus-visible { outline: none; }
.review-table tbody tr:has(a:focus-visible) { box-shadow: inset 0 0 0 2px var(--accent); }
.review-where { color: var(--dim); display: block; font-size: 11.5px; margin-top: 2px; }
.review-num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.review-table tr.is-next { background: color-mix(in srgb, var(--accent-soft) 60%, transparent); }
.review-state-cell { text-align: right; white-space: nowrap; }
.review-settle { color: var(--warn); font-weight: 650; position: relative; z-index: 1; }
.review-next-mark { background: var(--accent); border-radius: 999px; color: var(--on-accent);
  font-size: 11px; font-weight: 700; padding: 2px 10px; }
.review-done { color: var(--ok); font-size: 12px; font-weight: 650; }
.review-table.is-read .review-title a { color: var(--dim); font-weight: 500; }
.review-read > summary { color: var(--accent); cursor: pointer; font-size: 12.5px; font-weight: 700;
  padding: 2px 0; }
.review-read[open] > summary { margin-bottom: 6px; }
@media (max-width: 760px) {
  .review-next { grid-template-columns: minmax(0, 1fr); }
  .review-next-action { justify-items: start; text-align: left; }
  .review-round-progress { grid-template-columns: auto minmax(0, 1fr); width: 100%; }
  .review-table .review-col { display: none; }
  .review-table col.review-col { width: 0; }
  .review-c-num { width: 36px; }
  .review-narrow strong { color: var(--accent); }
  .review-narrow { color: var(--dim); display: block; font-size: 11.5px; margin-top: 2px; }
}
@media (min-width: 761px) { .review-narrow { display: none; } }
