/* ============================================================
   CE Radar - shared stylesheet
   ============================================================ */

:root {
    --navy:        #0f3d64;
    --navy-dark:   #0a2b47;
    --navy-light:  #1a5687;
    --accent:      #f0a020;
    --bg:          #eef2f7;
    --panel:       #ffffff;
    --line:        #dde6ee;
    --line-soft:   #eaf0f6;
    --ink:         #16232f;
    --ink-soft:    #5a6b7c;
    --ink-faint:   #8a97a5;
    --green:       #0a7d55;
    --green-bg:    #e2f5ec;
    --amber:       #8a6100;
    --amber-bg:    #fdf3dd;
    --red:         #b3261e;
    --red-bg:      #fdeceb;
    --blue-bg:     #e7f0f9;
    --radius:      10px;
    --shadow:      0 1px 3px rgba(16,32,64,.08), 0 6px 18px rgba(16,32,64,.05);
    --mono:        ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
}

body {
    background: var(--bg);
    color: var(--ink);
    font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--navy-light); }

/* ---------------- header / nav ---------------- */

.topbar {
    background: var(--navy);
    background-image: linear-gradient(180deg, var(--navy-light) 0%, var(--navy) 100%);
    color: #fff;
    box-shadow: 0 2px 12px rgba(10,43,71,.25);
    position: sticky;
    top: 0;
    z-index: 50;
}

.topbar-inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: 0 20px;
    display: flex;
    align-items: center;
    gap: 26px;
    min-height: 62px;
    flex-wrap: wrap;
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    font-size: 18px;
    letter-spacing: .3px;
    text-decoration: none;
    color: #fff;
    white-space: nowrap;
}

.brand-mark {
    width: 30px; height: 30px;
    border-radius: 8px;
    background: var(--accent);
    color: var(--navy-dark);
    display: grid;
    place-items: center;
    font-size: 15px;
    font-weight: 800;
}

.brand small {
    display: block;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 1.4px;
    color: #9fc4e4;
    text-transform: uppercase;
    margin-top: -2px;
}

.nav {
    display: flex;
    gap: 4px;
    flex: 1;
    flex-wrap: wrap;
}

.nav a {
    color: #cfe1f2;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    padding: 8px 13px;
    border-radius: 7px;
    white-space: nowrap;
    transition: background .15s, color .15s;
}

.nav a:hover { background: rgba(255,255,255,.12); color: #fff; }

.nav a.active {
    background: rgba(255,255,255,.18);
    color: #fff;
    font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--accent);
}

.nav a .pill {
    background: var(--accent);
    color: var(--navy-dark);
    font-size: 11px;
    font-weight: 800;
    border-radius: 20px;
    padding: 1px 6px;
    margin-left: 5px;
}

.topbar-status {
    font-size: 12px;
    color: #a9cbe8;
    display: flex;
    align-items: center;
    gap: 7px;
    white-space: nowrap;
}

.dot { width: 8px; height: 8px; border-radius: 50%; background: #6ee7b7; }
.dot.bad  { background: #fb7185; }
.dot.warn { background: #fbbf24; }

/* ---------------- layout ---------------- */

.wrap {
    max-width: 1280px;
    margin: 0 auto;
    padding: 26px 20px 70px;
}

.page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 18px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

.page-head h1 {
    margin: 0;
    font-size: 25px;
    letter-spacing: -.4px;
    color: var(--navy-dark);
}

.page-head p {
    margin: 5px 0 0;
    color: var(--ink-soft);
    font-size: 14px;
    max-width: 720px;
}

.panel {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    margin-bottom: 20px;
    overflow: hidden;
}

.panel-head {
    padding: 14px 18px;
    border-bottom: 1px solid var(--line-soft);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    background: #fbfdff;
}

.panel-head h2 {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--navy-dark);
    letter-spacing: .2px;
}

.panel-head .sub {
    font-size: 12.5px;
    color: var(--ink-faint);
    margin-top: 2px;
}

.panel-body { padding: 18px; }
.panel-body.tight { padding: 0; }

.grid { display: grid; gap: 18px; }
.grid.c2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid.c4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.grid.side { grid-template-columns: minmax(0,2fr) minmax(0,1fr); align-items: start; }

/* ---------------- stat cards ---------------- */

.stat {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow);
}

.stat .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.1px;
    color: var(--ink-faint);
    font-weight: 700;
}

.stat .value {
    font-size: 29px;
    font-weight: 700;
    color: var(--navy-dark);
    line-height: 1.15;
    margin-top: 5px;
    font-variant-numeric: tabular-nums;
}

.stat .foot { font-size: 12px; color: var(--ink-soft); margin-top: 3px; }
.stat.accent { border-left: 3px solid var(--accent); }
.stat.good   { border-left: 3px solid var(--green); }
.stat.bad    { border-left: 3px solid var(--red); }

/* ---------------- buttons ---------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    background: var(--navy);
    color: #fff;
    border: 1px solid var(--navy);
    border-radius: 8px;
    padding: 8px 15px;
    font-size: 14px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
    transition: background .15s, box-shadow .15s, transform .05s;
    white-space: nowrap;
}

.btn:hover  { background: var(--navy-light); box-shadow: 0 2px 8px rgba(15,61,100,.25); }
.btn:active { transform: translateY(1px); }

.btn[disabled], .btn.is-busy {
    opacity: .55;
    cursor: not-allowed;
    pointer-events: none;
}

.btn.ghost      { background: #fff; color: var(--navy); border-color: var(--line); }
.btn.ghost:hover{ background: #f4f8fc; }
.btn.accent     { background: var(--accent); border-color: var(--accent); color: #4a2f00; }
.btn.accent:hover { background: #ffb434; }
.btn.danger     { background: #fff; color: var(--red); border-color: #f0c9c6; }
.btn.danger:hover { background: var(--red-bg); }
.btn.sm         { padding: 5px 11px; font-size: 13px; border-radius: 7px; }
.btn.lg         { padding: 11px 22px; font-size: 15px; }
.btn.block      { width: 100%; }

.btn-row { display: flex; gap: 9px; flex-wrap: wrap; align-items: center; }

/* ---------------- forms ---------------- */

label.field { display: block; margin-bottom: 14px; }

label.field > span {
    display: block;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ink-soft);
    margin-bottom: 5px;
    letter-spacing: .2px;
}

label.field .hint {
    display: block;
    font-size: 11.5px;
    font-weight: 400;
    color: var(--ink-faint);
    margin-top: 4px;
    letter-spacing: 0;
}

input[type=text], input[type=url], input[type=email], input[type=number],
input[type=password], input[type=search], select, textarea {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: #fff;
    transition: border-color .15s, box-shadow .15s;
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--navy-light);
    box-shadow: 0 0 0 3px rgba(26,86,135,.13);
}

textarea { resize: vertical; min-height: 110px; font-family: var(--mono); font-size: 13px; }

input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--navy); cursor: pointer; vertical-align: -3px; }

.inline-check {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    font-size: 14px;
    margin-bottom: 12px;
    cursor: pointer;
}

.inline-check .hint { display: block; font-size: 11.5px; color: var(--ink-faint); margin-top: 2px; }

.toolbar {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
    padding: 13px 18px;
    background: #f7fafd;
    border-bottom: 1px solid var(--line-soft);
}

.toolbar input[type=search], .toolbar select { width: auto; min-width: 150px; }
.toolbar .grow { flex: 1; min-width: 200px; }
.toolbar .spacer { flex: 1; }

/* ---------------- tables ---------------- */

.table-scroll { overflow-x: auto; }

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 13.5px;
}

table.data th {
    text-align: left;
    padding: 10px 12px;
    background: #f7fafd;
    border-bottom: 1px solid var(--line);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .9px;
    color: var(--ink-soft);
    font-weight: 700;
    white-space: nowrap;
    position: sticky;
    top: 0;
}

table.data td {
    padding: 9px 12px;
    border-bottom: 1px solid var(--line-soft);
    vertical-align: top;
}

table.data tbody tr:hover { background: #f9fcff; }
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.data td.mono { font-family: var(--mono); font-size: 12px; }

.url-cell {
    max-width: 420px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.url-cell a { color: var(--navy-light); text-decoration: none; }
.url-cell a:hover { text-decoration: underline; }

/* ---------------- badges ---------------- */

.badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 20px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .3px;
    white-space: nowrap;
    background: var(--blue-bg);
    color: var(--navy);
}

.badge.green  { background: var(--green-bg); color: var(--green); }
.badge.amber  { background: var(--amber-bg); color: var(--amber); }
.badge.red    { background: var(--red-bg);   color: var(--red); }
.badge.grey   { background: #eef1f4;         color: var(--ink-soft); }
.badge.solid  { background: var(--navy);     color: #fff; }

/* ---------------- console / live log ---------------- */

.console {
    background: #0b1c2c;
    color: #cfe3f5;
    font-family: var(--mono);
    font-size: 12.5px;
    line-height: 1.65;
    padding: 14px 16px;
    border-radius: 8px;
    max-height: 460px;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

.console .l-info { color: #9ec7ea; }
.console .l-ok   { color: #6ee7b7; }
.console .l-warn { color: #fcd34d; }
.console .l-err  { color: #fda4af; }
.console .l-dim  { color: #6b8299; }
.console .l-head { color: #fff; font-weight: 700; }

/* ---------------- progress ---------------- */

.progress {
    height: 8px;
    background: var(--line-soft);
    border-radius: 20px;
    overflow: hidden;
}

.progress > i {
    display: block;
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--navy-light), var(--accent));
    border-radius: 20px;
    transition: width .35s ease;
}

/* ---------------- pipeline steps ---------------- */

.steps {
    display: grid;
    grid-template-columns: repeat(4, minmax(0,1fr));
    gap: 12px;
}

.step {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 14px 16px;
    position: relative;
}

.step.active { border-color: var(--navy-light); box-shadow: 0 0 0 3px rgba(26,86,135,.12); }
.step.done   { border-color: #b7e4cd; background: #f5fdf9; }

.step .n {
    width: 24px; height: 24px;
    border-radius: 50%;
    background: var(--line-soft);
    color: var(--ink-soft);
    display: grid; place-items: center;
    font-size: 12px; font-weight: 800;
    margin-bottom: 8px;
}

.step.active .n { background: var(--navy); color: #fff; }
.step.done .n   { background: var(--green); color: #fff; }
.step h3 { margin: 0 0 3px; font-size: 14px; color: var(--navy-dark); }
.step p  { margin: 0; font-size: 12.5px; color: var(--ink-soft); }

/* ---------------- news / update cards ---------------- */

.news-item {
    border: 1px solid var(--line);
    border-left: 3px solid var(--navy-light);
    border-radius: var(--radius);
    background: #fff;
    padding: 15px 17px;
    margin-bottom: 12px;
    box-shadow: var(--shadow);
    transition: box-shadow .15s, transform .05s;
}

.news-item:hover { box-shadow: 0 3px 14px rgba(16,32,64,.10); }
.news-item.is-remote  { border-left-color: var(--green); }
.news-item.is-onsite  { border-left-color: var(--ink-faint); }
.news-item.is-hybrid  { border-left-color: var(--accent); }
.news-item.is-read    { opacity: .62; }

.news-item h3 {
    margin: 0 0 7px;
    font-size: 16px;
    line-height: 1.35;
    font-weight: 650;
}

.news-item h3 a { color: var(--navy-dark); text-decoration: none; }
.news-item h3 a:hover { color: var(--navy-light); text-decoration: underline; }

.news-meta {
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 8px;
}

.news-snippet {
    font-size: 13.5px;
    color: var(--ink-soft);
    line-height: 1.6;
    margin: 0 0 10px;
}

.news-actions {
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
    align-items: center;
    border-top: 1px solid var(--line-soft);
    padding-top: 9px;
}

.news-actions .src {
    margin-left: auto;
    font-size: 11.5px;
    color: var(--ink-faint);
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.star-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 16px;
    color: var(--line);
    padding: 0 3px;
    line-height: 1;
}

.star-btn.on { color: var(--accent); }

.day-head {
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--ink-faint);
    margin: 22px 0 11px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--line);
}

.day-head:first-child { margin-top: 0; }

/* ---------------- misc ---------------- */

.empty {
    text-align: center;
    padding: 46px 20px;
    color: var(--ink-faint);
}

.empty .big { font-size: 34px; margin-bottom: 10px; opacity: .5; }
.empty h3 { margin: 0 0 6px; color: var(--ink-soft); font-size: 16px; }
.empty p { margin: 0 auto; max-width: 420px; font-size: 13.5px; }

.note {
    background: var(--blue-bg);
    border: 1px solid #c9dcf0;
    border-left: 3px solid var(--navy-light);
    border-radius: 8px;
    padding: 12px 15px;
    font-size: 13.5px;
    color: #1c3d5c;
    margin-bottom: 16px;
}

.note.warn   { background: var(--amber-bg); border-color: #f0dfae; border-left-color: var(--accent); color: #5c4405; }
.note.danger { background: var(--red-bg);   border-color: #f2ccc8; border-left-color: var(--red);    color: #7a1c15; }
.note.good   { background: var(--green-bg); border-color: #b7e4cd; border-left-color: var(--green);  color: #04543a; }
.note strong { font-weight: 700; }
.note code   { font-family: var(--mono); font-size: 12.5px; background: rgba(255,255,255,.65); padding: 1px 5px; border-radius: 4px; }

.pager {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: center;
    padding: 14px;
    font-size: 13.5px;
    color: var(--ink-soft);
    border-top: 1px solid var(--line-soft);
    flex-wrap: wrap;
}

/* ---------------- modal dialogs ---------------- */

.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: rgba(10, 27, 44, .55);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 4vh 16px;
    overflow-y: auto;
    animation: overlayIn .16s ease;
}

@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }

.modal-overlay > .panel {
    width: 100%;
    max-width: 1080px;
    margin: 0;
    max-height: 92vh;
    display: flex;
    flex-direction: column;
    box-shadow: 0 18px 60px rgba(6, 20, 35, .4);
    animation: modalIn .2s cubic-bezier(.2, .8, .3, 1);
}

@keyframes modalIn {
    from { opacity: 0; transform: translateY(-12px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

/* The head and tabs stay put; only the body scrolls. */
.modal-overlay > .panel > .panel-head,
.modal-overlay > .panel > .tabs { flex: 0 0 auto; }

/* One scroll region for the whole modal body. Panes used to scroll
 * individually, which broke once a shared panel sat beside them: two flex
 * children both claiming the free height squeezed the active pane to a sliver
 * and its content slid under the sticky tab bar. */
.modal-overlay > .panel > .modal-scroll {
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
}

.modal-overlay > .panel > .modal-scroll > .panel-body { overflow-y: visible; }

.modal-overlay > .panel > .panel-head h2 { font-size: 17px; }

.modal-close {
    background: none;
    border: none;
    font-size: 22px;
    line-height: 1;
    color: var(--ink-faint);
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 6px;
}

.modal-close:hover { background: var(--line-soft); color: var(--ink); }

body.modal-open { overflow: hidden; }

@media (max-width: 720px) {
    .modal-overlay { padding: 0; }
    .modal-overlay > .panel { max-height: 100vh; border-radius: 0; }
}

.toast-wrap {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: 9px;
    max-width: 380px;
}

.toast {
    background: var(--navy-dark);
    color: #fff;
    padding: 11px 15px;
    border-radius: 9px;
    font-size: 13.5px;
    box-shadow: 0 6px 22px rgba(10,43,71,.3);
    animation: toastIn .2s ease;
    border-left: 3px solid var(--accent);
}

.toast.ok  { border-left-color: #34d399; }
.toast.err { border-left-color: #fb7185; }

@keyframes toastIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.spinner {
    width: 14px; height: 14px;
    border: 2px solid rgba(255,255,255,.35);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin .7s linear infinite;
    display: inline-block;
}

.spinner.dark { border-color: rgba(15,61,100,.25); border-top-color: var(--navy); }

@keyframes spin { to { transform: rotate(360deg); } }

.kv { display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: 6px 14px; font-size: 13.5px; }
.kv dt { color: var(--ink-faint); font-weight: 600; }
.kv dd { margin: 0; color: var(--ink); word-break: break-word; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); padding: 0 18px; background: #fbfdff; flex-wrap: wrap; }

.tabs button {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 11px 13px;
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink-soft);
    cursor: pointer;
}

.tabs button.active { color: var(--navy); border-bottom-color: var(--accent); }

.chip-row { display: flex; gap: 7px; flex-wrap: wrap; }

.chip {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 20px;
    padding: 4px 12px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-soft);
    cursor: pointer;
}

.chip.on { background: var(--navy); border-color: var(--navy); color: #fff; }

.mailframe {
    width: 100%;
    height: 640px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
}

.hide { display: none !important; }

/* ---------------- responsive ---------------- */

@media (max-width: 1000px) {
    .grid.c4   { grid-template-columns: repeat(2, minmax(0,1fr)); }
    .grid.side { grid-template-columns: 1fr; }
    .steps     { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

@media (max-width: 720px) {
    .grid.c2, .grid.c3, .grid.c4 { grid-template-columns: 1fr; }
    .steps { grid-template-columns: 1fr; }
    .topbar-inner { min-height: 0; padding: 10px 14px; }
    .nav { order: 3; width: 100%; }
    .wrap { padding: 18px 14px 60px; }
    .page-head h1 { font-size: 21px; }
    .url-cell { max-width: 200px; }
}

/* ---------------- source folders ---------------- */
/* The list is built to hold thousands of URLs, which is far too many to browse
   flat. Folders are the distinct values of sources.category: one card per
   folder, click to drill in, and "Move to folder" re-files what you select. */

.folders {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
    gap: 10px;
}

.folder {
    display: block;
    width: 100%;
    text-align: left;
    font: inherit;
    cursor: pointer;
    background: var(--panel);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line);
    border-radius: var(--radius);
    padding: 12px 14px;
    transition: border-color .12s, box-shadow .12s, transform .12s;
}

.folder:hover {
    border-color: var(--navy-light);
    border-left-color: var(--navy-light);
    box-shadow: var(--shadow);
    transform: translateY(-1px);
}

.folder.on {
    border-color: var(--navy);
    border-left-color: var(--accent);
    background: var(--blue-bg);
}

.folder .fname {
    display: flex;
    align-items: center;
    gap: 7px;
    font-weight: 650;
    color: var(--navy-dark);
    font-size: 14px;
    word-break: break-word;
}

.folder .fcount {
    font-size: 22px;
    font-weight: 700;
    color: var(--navy-dark);
    font-variant-numeric: tabular-nums;
    margin-top: 4px;
    line-height: 1.1;
}

.folder .ffoot {
    font-size: 11.5px;
    color: var(--ink-soft);
    margin-top: 2px;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.folder .ffoot .bad  { color: var(--red); font-weight: 600; }
.folder .ffoot .due  { color: var(--amber); font-weight: 600; }

.crumb {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    color: var(--ink-soft);
    margin-bottom: 12px;
}

.crumb b { color: var(--navy-dark); }

/* ---------------- why-was-this-kept keyword chips ---------------- */

.kw-row {
    display: flex;
    align-items: center;
    gap: 5px;
    flex-wrap: wrap;
    margin-bottom: 9px;
}

.kw-lead {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .8px;
    font-weight: 700;
    color: var(--ink-faint);
    margin-right: 2px;
}

.kw {
    font: inherit;
    font-size: 11.5px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 20px;
    border: 1px solid var(--line);
    background: var(--panel);
    color: var(--ink-soft);
    transition: background .12s, border-color .12s, color .12s;
}

.kw:hover        { border-color: var(--navy-light); color: var(--navy-dark); }
.kw.disc         { background: var(--blue-bg); border-color: #c4dcf2; color: var(--navy); font-weight: 600; }
.kw.disc:hover   { border-color: var(--navy); }
.kw.on           { background: var(--navy); border-color: var(--navy); color: #fff; }

/* ---------------- per-item "never email" panel ---------------- */

.xrow {
    margin-top: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-left: 3px solid var(--amber);
    border-radius: var(--radius);
    background: var(--amber-bg);
}

.xlead {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .8px;
    font-weight: 700;
    color: var(--amber);
    margin-bottom: 7px;
}

.xrow .kw         { background: #fff; }
.xrow .kw.on      { background: var(--red); border-color: var(--red); color: #fff; }
.xhint            { font-size: 11.5px; color: var(--ink-soft); margin-top: 7px; }
.news-actions .btn.on { background: var(--amber-bg); border-color: var(--amber); color: var(--amber); }

/* ---------------- per-source filter panel ---------------- */
/* The panel grew three controls that all decided the same thing. Headings keep
   the remaining groups apart so it reads as two questions, not eight switches. */

.ov-head {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: 700;
    color: var(--ink-faint);
    margin: 0 0 9px;
    padding-top: 4px;
}

.ov-head + .grid { margin-bottom: 4px; }
.ov-head:not(:first-child) { margin-top: 16px; border-top: 1px solid var(--line-soft); padding-top: 16px; }

/* Nothing above matters when everything is being kept. */
#ovPanel.keep-all .ov-head,
#ovPanel.keep-all .grid { opacity: .4; pointer-events: none; }

/* ------------------------------------------------------------------
   Collapsible sections in the source edit form. The add flow needs
   only a URL; method and skip rules are opened on demand, and are
   auto-opened when the source already has something set in them.
   ------------------------------------------------------------------ */
details.sec {
  border: 1px solid var(--line);
  border-radius: 8px;
  margin: 14px 0;
  background: var(--bg-soft, #fbfcfd);
}
details.sec > summary {
  cursor: pointer;
  padding: 11px 14px;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ink-soft);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
details.sec > summary::-webkit-details-marker { display: none; }
details.sec > summary::before {
  content: "\25B8";                 /* right-pointing triangle */
  font-size: 11px;
  transition: transform .15s;
  color: var(--ink-faint);
}
details.sec[open] > summary::before { transform: rotate(90deg); }
details.sec > summary:hover { color: var(--navy-dark, #123); }
details.sec[open] > summary { border-bottom: 1px solid var(--line-soft); }
details.sec .sec-body { padding: 14px; }
details.sec .sec-note {
  margin-left: auto;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  font-size: 12px;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------------
   Scrape page: compact run figures, and a source picker that works
   whether the list holds 3 URLs or 5,000.
   ------------------------------------------------------------------ */
.stat.hero .value { font-size: 34px; line-height: 1.1; }

.run-line {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.run-line.sub { font-size: 12.5px; color: var(--ink-faint); margin-bottom: 10px; }
.run-line strong { color: var(--navy-dark, #123); }
.run-line .bad, .run-line .bad strong { color: var(--red); }

/* the server-side alternative, sitting under the main run buttons */
.run-alt {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* search-as-you-type source picker */
.typeahead {
  position: absolute;
  z-index: 30;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 2px;
  max-height: 268px;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 22px rgba(16, 32, 56, .13);
}
.typeahead .ta-row {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 11px;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  background: none;
  cursor: pointer;
  font: inherit;
}
.typeahead .ta-row:last-child { border-bottom: 0; }
.typeahead .ta-row:hover { background: var(--bg-soft, #f4f7fa); }
.typeahead .ta-name {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--navy-dark, #123);
}
.typeahead .ta-name em { font-weight: 500; color: var(--ink-faint); font-style: normal; }
.typeahead .ta-url {
  display: block;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.typeahead .ta-empty {
  padding: 9px 11px;
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* per-source audit rows on the Scrape page */
.audit-row {
  padding: 9px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 12.5px;
}
.audit-row:last-of-type { border-bottom: 0; }
.audit-row.blank { background: rgba(200, 80, 60, .045); border-radius: 6px; padding: 9px 8px; }
.audit-head { display: flex; flex-wrap: wrap; gap: 2px 10px; justify-content: space-between; }
.audit-name { font-weight: 600; color: var(--navy-dark, #123); }
.audit-nums { color: var(--ink-faint); white-space: nowrap; }
.audit-nums strong { color: var(--ink-soft); }
.audit-why { margin-top: 4px; color: var(--ink-soft); line-height: 1.55; }
.audit-why strong { color: var(--navy-dark, #123); }
.audit-flag { margin-top: 5px; color: var(--red); font-weight: 500; }

/* step-by-step setup blocks (cron, and anything else with real instructions) */
.setup {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  margin-bottom: 14px;
  background: var(--bg-soft, #fbfcfd);
}
.setup-title {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--navy-dark, #123);
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.setup-steps { margin: 0; padding-left: 20px; font-size: 13.5px; line-height: 1.75; }
.setup-steps > li { margin-bottom: 7px; }
.setup-note {
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.6;
}
.setup-note code, .bin-row code {
  font-family: var(--mono);
  font-size: 11.5px;
  background: rgba(20, 40, 70, .06);
  padding: 1px 5px;
  border-radius: 4px;
}
.bin-row {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  padding: 4px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
table.data tr.row-bad td { background: rgba(200, 80, 60, .05); }

/* inspector rows: two lines by default, expandable, so page length no longer
   depends on how much text each scraped block happens to carry */
.blk-text {
  font-size: 12px;
  color: var(--ink-soft);
  margin-top: 4px;
  line-height: 1.5;
}
.blk-text.clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.blk-more {
  border: 0;
  background: none;
  padding: 2px 0;
  margin-top: 2px;
  font: inherit;
  font-size: 11.5px;
  color: var(--navy-dark, #123);
  text-decoration: underline;
  cursor: pointer;
}

/* matched-keyword chips in the Extract inspector */
.kw-chips { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 3px; }
.kw-chip {
  font: inherit;
  font-size: 11px;
  font-family: var(--mono);
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
}
.kw-chip:hover { border-color: var(--navy-dark, #123); color: var(--navy-dark, #123); }

/* the two counters: weighted score, and breadth of dictionary terms */
td.counters { line-height: 1.3; }
.ctr-score { font-size: 14px; font-weight: 600; color: var(--navy-dark, #123); }
.ctr-terms {
  font-size: 11px;
  color: var(--ink-faint);
  white-space: nowrap;
  cursor: help;
}
.ctr-terms.good { color: var(--green, #167a4a); font-weight: 600; }
.ctr-terms.thin { color: var(--red); }

/* a dropped block that nonetheless matches several dictionary terms */
.verdict-odd {
  margin-top: 5px;
  padding: 4px 7px;
  border-left: 2px solid var(--amber, #d08700);
  background: rgba(208, 135, 0, .07);
  color: var(--ink-soft);
  font-size: 11.5px;
  line-height: 1.5;
}

/* ------------------------------------------------------------------
   "Why content was dropped" - one card per rule, written out, with the
   setting that governs it. Replaces a run-on list of reason strings.
   ------------------------------------------------------------------ */
.drop-head { margin: 6px 0 12px; }
.drop-head h3 {
  margin: 0 0 4px;
  font-size: 15px;
  color: var(--navy-dark, #123);
}
.drop-head p {
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.6;
}
.drop-rule {
  border: 1px solid var(--line);
  border-radius: 8px;
  margin-bottom: 10px;
  overflow: hidden;
  background: #fff;
}
.drop-rule.stale { border-color: rgba(200, 80, 60, .45); }
.drop-rule-head {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  align-items: baseline;
  justify-content: space-between;
  padding: 10px 13px;
  background: var(--bg-soft, #fbfcfd);
  border-bottom: 1px solid var(--line-soft);
}
.drop-rule-title {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--navy-dark, #123);
}
.drop-rule-count { font-size: 12.5px; color: var(--ink-soft); white-space: nowrap; }
.drop-rule-count span { color: var(--ink-faint); }
.drop-rule-body { padding: 11px 13px; }
.drop-rule-body p {
  margin: 0 0 7px;
  font-size: 13px;
  line-height: 1.65;
  color: var(--ink-soft);
}
.drop-rule-body p strong { color: var(--navy-dark, #123); }
.drop-suspect {
  padding: 6px 9px;
  border-left: 2px solid var(--amber, #d08700);
  background: rgba(208, 135, 0, .07);
}
.drop-keep { color: var(--ink-faint) !important; font-size: 12.5px !important; }
.drop-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 9px 0 7px;
}
.drop-effect { font-size: 12px; color: var(--ink-faint); }

/* ------------------------------------------------------------------
   Why one item was dropped, stated in the row itself rather than in a
   summary the reader has to carry back from elsewhere on the page.
   ------------------------------------------------------------------ */
.why-cell { font-size: 12px; color: var(--ink-soft); vertical-align: top; }
.why-kept { color: var(--green, #167a4a); font-weight: 500; }
.why-none { color: var(--red); }
.why-title {
  font-weight: 600;
  font-size: 12.5px;
  color: var(--navy-dark, #123);
  line-height: 1.4;
  margin-bottom: 3px;
}
.why-what { line-height: 1.55; }
.why-odd {
  margin-top: 5px;
  padding: 4px 7px;
  border-left: 2px solid var(--amber, #d08700);
  background: rgba(208, 135, 0, .07);
  line-height: 1.5;
  font-size: 11.5px;
}
.why-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 6px;
}
.why-actions .btn { font-size: 11.5px; padding: 3px 8px; }
.why-raw {
  margin-top: 5px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-faint);
  cursor: help;
  overflow-wrap: anywhere;
}
.why-saved, .why-failed {
  margin-top: 6px;
  padding: 5px 7px;
  border-radius: 5px;
  font-size: 11.5px;
  line-height: 1.5;
}
.why-saved { background: rgba(22, 122, 74, .09); color: var(--ink-soft); }
.why-failed { background: rgba(200, 80, 60, .09); color: var(--red); }

/* ------------------------------------------------------------------
   Which of the six dictionaries decided a verdict, per row.
   ------------------------------------------------------------------ */
details.dict-det { margin-top: 7px; }
details.dict-det > summary {
  cursor: pointer;
  font-size: 11.5px;
  color: var(--navy-dark, #123);
  text-decoration: underline;
  list-style: none;
}
details.dict-det > summary::-webkit-details-marker { display: none; }
.dict-grid { margin-top: 6px; }
.dict-row {
  border-left: 3px solid var(--line);
  padding: 6px 0 6px 8px;
  margin-bottom: 7px;
}
.dict-row.dict-discipline  { border-left-color: #2f6fb3; }
.dict-row.dict-opportunity { border-left-color: #7a4fb3; }
.dict-row.dict-remote      { border-left-color: #167a4a; }
.dict-row.dict-hybrid      { border-left-color: #1f8a86; }
.dict-row.dict-onsite      { border-left-color: #d08700; }
.dict-row.dict-exclude     { border-left-color: #c8503c; }
.dict-row-head {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 8px;
  justify-content: space-between;
  align-items: baseline;
}
.dict-name { font-weight: 600; font-size: 11.5px; color: var(--navy-dark, #123); }
.dict-w { font-size: 11px; color: var(--ink-faint); white-space: nowrap; }
.dict-terms { display: flex; flex-wrap: wrap; gap: 3px; margin: 4px 0 3px; }
.dict-more { font-size: 10.5px; color: var(--ink-faint); align-self: center; }
.dict-role { font-size: 11px; color: var(--ink-soft); line-height: 1.5; }
.dict-gate {
  margin-top: 4px;
  font-size: 11px;
  color: var(--ink-faint);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}
.dict-gate code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: rgba(20, 40, 70, .06);
  padding: 1px 4px;
  border-radius: 3px;
}
.dict-gate .btn { font-size: 10.5px; padding: 2px 7px; }
.dict-none, .dict-caveat { font-size: 11px; color: var(--ink-faint); line-height: 1.5; }
.dict-caveat { margin-top: 4px; font-style: italic; }

/* ------------------------------------------------------------------
   The condition builder: groups of AND lines, ORed together.
   ------------------------------------------------------------------ */
.cond-group {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--bg-soft, #fbfcfd);
}
.cond-group-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--ink-faint);
  margin-bottom: 8px;
}
.cond-line {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.cond-line select, .cond-line input {
  padding: 4px 7px;
  font-size: 12.5px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: #fff;
}
/* the global form rules stretch selects to 100%, which would stack these */
.cond-line select, .cond-line input { flex: 0 0 auto; width: auto; }
.cond-line select[data-cfield] { flex: 1 1 180px; min-width: 160px; max-width: 240px; }
.cond-line select[data-cop] { flex: 1 1 150px; min-width: 130px; max-width: 190px; }
.cond-line input[data-cval], .cond-line select[data-cval] { flex: 0 0 130px; width: 130px; }
.cond-novalue { flex: 0 0 130px; }
.cond-stats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.cond-stats .stat { flex: 1 1 140px; }
.cond-hits { border-top: 1px solid var(--line-soft); }
.cond-hit { padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
.cond-hit-meta { font-size: 11.5px; color: var(--ink-faint); margin-top: 3px; }

/* ------------------------------------------------------------------
   The exclusion inventory: every rule that can remove content, in the
   order it runs, with the value in force.
   ------------------------------------------------------------------ */
.inv-stage { margin-bottom: 14px; }
.inv-stage-name {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .9px;
  color: var(--ink-faint);
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 8px;
}
.inv-row {
  padding: 8px 10px;
  border-left: 3px solid var(--line);
  margin-bottom: 6px;
  background: var(--bg-soft, #fbfcfd);
  border-radius: 0 6px 6px 0;
}
.inv-row.on  { border-left-color: #2f6fb3; }
.inv-row.off { border-left-color: var(--line); opacity: .72; }
.inv-row.hot { border-left-color: #d08700; background: rgba(208, 135, 0, .06); opacity: 1; }
.inv-main { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.inv-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: #2f6fb3; flex: 0 0 auto;
}
.inv-row.off .inv-dot { background: var(--line); }
.inv-row.hot .inv-dot { background: #d08700; }
.inv-name { font-weight: 600; font-size: 13px; color: var(--navy-dark, #123); }
.inv-value {
  font-size: 11.5px;
  color: var(--ink-soft);
  background: rgba(20, 40, 70, .06);
  padding: 1px 6px;
  border-radius: 9px;
}
.inv-what { font-size: 12px; color: var(--ink-soft); line-height: 1.55; margin-top: 4px; }
.inv-reason, .inv-where {
  font-size: 11px;
  color: var(--ink-faint);
  margin-top: 3px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}
.inv-reason code, .inv-where code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: rgba(20, 40, 70, .07);
  padding: 1px 4px;
  border-radius: 3px;
}
.inv-where .btn { font-size: 10.5px; padding: 2px 7px; }

/* built-in rules shown as read-only conditions, with their cross-check */
.cond-ro {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--ink-faint);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 1px 7px;
}
.cond-line select:disabled, .cond-line input:disabled {
  background: rgba(20, 40, 70, .04);
  color: var(--ink-soft);
  cursor: default;
}
.cond-cross {
  margin-top: 8px;
  padding: 6px 9px;
  border-radius: 5px;
  font-size: 12px;
  line-height: 1.55;
}
.cond-cross.ok   { background: rgba(22, 122, 74, .09); }
.cond-cross.warn { background: rgba(208, 135, 0, .10); }
.cond-cross code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: rgba(20, 40, 70, .07);
  padding: 1px 4px;
  border-radius: 3px;
}

/* ------------------------------------------------------------------
   Extract page: one card that states what to press next, the rules
   read as chips rather than one long sentence, and the power tools
   folded into a section that stays shut until it is wanted.
   ------------------------------------------------------------------ */
.section-h {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ink-faint);
  margin: 26px 0 10px;
}

.next-step {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 4px solid var(--navy-light);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 20px;
  margin-bottom: 20px;
}
.next-step.is-done { border-left-color: var(--green); }

.next-step .ns-n {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.next-step.is-done .ns-n { background: var(--green); }

.next-step .ns-body { flex: 1 1 auto; min-width: 0; }
.next-step .ns-body h2 { margin: 0; font-size: 16px; color: var(--navy-dark); }
.next-step .ns-body p {
  margin: 3px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}
.next-step .ns-act { flex: none; }

@media (max-width: 760px) {
  .next-step { flex-wrap: wrap; }
  .next-step .ns-act { width: 100%; }
  .next-step .ns-act .btn { width: 100%; }
}

/* the filter settings, readable at a glance instead of as one run-on line */
.rule-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; }
.rule-chip {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 2px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: help;
}
.rule-chip b { color: var(--navy-dark); font-weight: 700; }

/* a note that belongs to one panel, sitting under its body */
.panel-tip {
  border-top: 1px solid var(--line-soft);
  background: var(--amber-bg);
  padding: 11px 18px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--amber);
  border-radius: 0 0 var(--radius) var(--radius);
}
.panel-tip strong { color: var(--amber); }

/* the advanced tools: each one says what it does before you press it */
.tool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(235px, 1fr));
  gap: 12px;
}
.tool {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 13px 14px;
}
.tool h4 { margin: 0; font-size: 13.5px; color: var(--navy-dark); }
.tool p {
  margin: 0;
  flex: 1 1 auto;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}
.tool .btn { align-self: flex-start; }

/* ------------------------------------------------------------------
   Editing a dictionary from the row that named it, and the arithmetic
   behind a verdict written out rather than implied.
   ------------------------------------------------------------------ */
.dict-edit-row { margin-top: 8px; }

.dict-sum {
  margin-top: 10px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
}
.dict-sum strong { color: var(--navy-dark); }
.dict-sum-note {
  display: block;
  margin-top: 4px;
  font-family: inherit;
  font-size: 11.5px;
  color: var(--ink-faint);
}

/* the phrase / weight / effect table */
.dict-in {
  width: 100%;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
}
.dict-in:focus { outline: none; border-color: var(--navy-light); box-shadow: 0 0 0 3px rgba(26,86,135,.12); }
.dict-in-w { text-align: right; }

.dict-eff { font-family: var(--mono); font-size: 12.5px; font-weight: 600; color: var(--green); }
.dict-eff.is-neg { color: var(--red); }
.dict-eff.is-off { color: var(--ink-faint); font-weight: 500; }

.dict-add {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 12px 0;
  flex-wrap: wrap;
}
.dict-add input[type=text] { flex: 1 1 240px; min-width: 0; }
.dict-add input[type=number] { width: 96px; text-align: right; }
.dict-add input {
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 7px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
}
.dict-add input:focus { outline: none; border-color: var(--navy-light); box-shadow: 0 0 0 3px rgba(26,86,135,.12); }

/* a modal footer that stays put while the body scrolls */
.modal-foot {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: none;
  padding: 12px 18px;
  border-top: 1px solid var(--line);
  background: #fbfdff;
  border-radius: 0 0 var(--radius) var(--radius);
}
.modal-foot .spacer { flex: 1 1 auto; }
.modal-foot-note { font-size: 12.5px; font-weight: 600; color: var(--amber); }

/* ------------------------------------------------------------------
   Extract page, second pass: drop reasons you can click, and a
   minimum score you can try before you commit to it.
   ------------------------------------------------------------------ */
.reason-bar {
  display: block;
  width: 100%;
  margin: 0 0 9px;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.reason-bar:hover { background: var(--blue-bg); border-color: var(--line); }
.reason-bar:last-child { margin-bottom: 0; }
.reason-bar-head { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 3px; }
.reason-bar-name { font-size: 12.5px; color: var(--ink-soft); }
.reason-bar-n { font-size: 12.5px; color: var(--ink-faint); flex: none; }
.reason-bar .progress { display: block; }

.tuner-lead { margin: 0 0 12px; font-size: 13px; line-height: 1.6; color: var(--ink-soft); }

.tuner {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.tuner label { font-size: 12.5px; font-weight: 600; color: var(--ink-soft); }
.tuner input[type=range] { flex: 1 1 220px; min-width: 160px; accent-color: var(--navy-light); }
.tuner output {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--navy-dark);
  min-width: 2.2em;
  text-align: center;
}
.tuner .spacer { flex: 1 1 auto; }

.tune-bar {
  height: 8px;
  border-radius: 5px;
  background: var(--line-soft);
  overflow: hidden;
  margin-bottom: 12px;
}
.tune-bar > i { display: block; height: 100%; background: var(--navy-light); transition: width .12s; }

.tune-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px;
  margin-bottom: 10px;
}
.tune-cell {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  padding: 10px 12px;
}
.tune-cell strong {
  display: block;
  font-size: 19px;
  line-height: 1.2;
  color: var(--navy-dark);
}
.tune-cell span { display: block; margin-top: 2px; font-size: 12px; line-height: 1.45; color: var(--ink-soft); }
.tune-cell.good { border-color: var(--green); background: var(--green-bg); }
.tune-cell.good strong { color: var(--green); }
.tune-cell.bad { border-color: var(--red); background: var(--red-bg); }
.tune-cell.bad strong { color: var(--red); }

.tune-caveat { font-size: 12px; line-height: 1.6; color: var(--ink-faint); }
.tune-caveat strong { color: var(--amber); }

/* ------------------------------------------------------------------
   Score and weight, explained side by side, and one switch per
   dictionary.
   ------------------------------------------------------------------ */
.se-two {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
  margin: 10px 0;
}
.se-half {
  display: block;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 11px 13px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-soft);
}
.se-half b { display: block; margin-bottom: 3px; color: var(--navy-dark); font-size: 12px; letter-spacing: .4px; }
.se-foot { display: block; font-size: 12px; line-height: 1.6; color: var(--ink-faint); }

.dict-switches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 4px 14px;
  margin-top: 10px;
}
.dict-switches .inline-check { margin: 0; }

.kw-format {
  margin: 0 0 14px;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--ink-soft);
}
.kw-format code {
  background: var(--blue-bg);
  border-radius: 4px;
  padding: 1px 5px;
  font-family: var(--mono);
  font-size: 11.5px;
}

/* score and weight shown as a pair wherever a verdict is explained */
.sw-pair { display: inline-flex; gap: 5px; align-items: center; }
.sw-chip {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 600;
  border-radius: 5px;
  padding: 1px 6px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-soft);
  white-space: nowrap;
}
.sw-chip b { color: var(--navy-dark); }
.sw-chip.is-zero { border-color: var(--red); background: var(--red-bg); }
.sw-chip.is-zero b { color: var(--red); }

/* score above weight above the term count, in the audit table */
.counters .ctr-weight {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.counters .ctr-score.thin { color: var(--red); }

/* one editor per dictionary, however many there are */
.kw-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}
.kw-cell textarea { font-family: var(--mono); font-size: 12px; }
.kw-key {
  background: var(--blue-bg);
  border-radius: 4px;
  padding: 0 5px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--navy);
}
.kw-count { color: var(--ink-faint); font-weight: 500; font-size: 11.5px; }

/* the CGPA, shown wherever a verdict is explained */
.ctr-cgpa {
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--navy-dark);
  margin-top: 1px;
}
.ctr-cgpa.low { color: var(--red); }
.ctr-cgpa.mid { color: var(--amber); }
.ctr-cgpa.high { color: var(--green); }
.calc-transcript {
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #fff;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--ink-soft);
}

/* the transcript: each matched term, its grade, and what they average to */
.calc-transcript .tr-units { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.tr-unit {
  background: var(--blue-bg);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 6px;
  font-size: 11px;
  color: var(--ink-soft);
}
.tr-unit b { color: var(--navy-dark); }
.tr-unit i { color: var(--ink-faint); font-style: normal; }
.tr-unit.failed { background: var(--red-bg); border-color: var(--red); }
.tr-unit.failed b { color: var(--red); }
.calc-transcript .tr-sum { color: var(--ink); padding-top: 4px; border-top: 1px solid var(--line-soft); }
.calc-transcript .tr-note {
  margin-top: 5px;
  font-family: inherit;
  font-size: 11px;
  line-height: 1.6;
  color: var(--ink-faint);
}

/* merit sits above the CGPA: the ranking figure first */
.counters .ctr-merit {
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--navy);
  margin-top: 1px;
}

/* the per-dictionary contribution table */
#ruleTable .dict-in { width: 100%; }
#ruleTable select.dict-in { padding: 5px 6px; }
.rule-effect { font-size: 11.5px; line-height: 1.5; color: var(--ink-soft); }

/* merit can be negative, which is a real answer and should read as one */
.counters .ctr-merit.neg { color: var(--red); }
.tr-unit.off { opacity: .6; }
.tr-unit i { font-style: normal; font-size: 10px; color: var(--ink-faint); margin-left: 3px; }

/* ------------------------------------------------------------------
   Settings is a long page. A jump nav to get down it, and a Save that
   follows you so the button is never a scroll away from the change.
   ------------------------------------------------------------------ */
.jump-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 22px;
}
.jump-nav a {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 5px 13px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  transition: border-color .12s, color .12s;
}
.jump-nav a:hover { border-color: var(--navy-light); color: var(--navy-dark); }

/* anchored panels must not hide under the sticky topbar */
.panel[id] { scroll-margin-top: 78px; }

.save-bar {
  position: sticky;
  bottom: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 22px -16px -18px;
  padding: 11px 20px;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(6px);
  border-top: 1px solid var(--line);
  box-shadow: 0 -2px 12px rgba(16, 32, 64, .06);
}
.save-bar .spacer { flex: 1 1 auto; }
.save-bar-note { font-size: 12.5px; color: var(--ink-soft); }

@media (max-width: 700px) {
  .save-bar { margin: 22px -12px -14px; padding: 10px 14px; }
  .save-bar-note { display: none; }
}

/* the contribution table has room to breathe at full width */
#ruleTable th { white-space: nowrap; }
#ruleTable td:first-child { min-width: 190px; }
#ruleTable td:last-child { white-space: normal; }

/* the worked example: the arithmetic, and the four totals it lands on */
#wkTable td { vertical-align: middle; }
#wkTable .wk-neg { color: var(--red); font-weight: 600; }
.wk-totals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px;
  margin-top: 12px;
}
.wk-total {
  border: 1px solid var(--line);
  border-left: 3px solid var(--navy-light);
  border-radius: 8px;
  background: #fff;
  padding: 9px 12px;
}
.wk-total strong { display: block; font-size: 15px; color: var(--navy-dark); }
.wk-total span { display: block; margin-top: 2px; font-size: 11.5px; color: var(--ink-soft); }
.wk-total.good { border-left-color: var(--green); background: var(--green-bg); }
.wk-total.good strong { color: var(--green); }
.wk-total.bad { border-left-color: var(--red); background: var(--red-bg); }
.wk-total.bad strong { color: var(--red); }

/* ---------- per-dictionary conditions (settings) ---------- */
.cond-group {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 12px 14px 10px;
    margin-bottom: 10px;
    background: var(--paper-2);
}
.cond-group + .cond-group { position: relative; }
/* Spell the OR out between the boxes rather than relying on the reader to infer it. */
.cond-group + .cond-group::before {
    content: 'or, alternatively';
    position: absolute; top: -18px; left: 14px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-faint);
}
.cond-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 8px;
}
.cond-head strong { font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-soft); }
.cond-line {
    display: grid;
    grid-template-columns: minmax(0,1.4fr) minmax(0,1fr) 96px 92px 32px;
    gap: 8px; align-items: center; margin-bottom: 6px;
}
.cond-line + .cond-line { position: relative; }
.cond-line + .cond-line::after {
    content: 'and'; position: absolute; left: -30px; top: 9px;
    font-size: 10.5px; font-weight: 700; color: var(--ink-faint);
}
.cond-group { padding-left: 46px; }
.cond-x {
    border: 1px solid var(--line); background: #fff; border-radius: 7px;
    width: 30px; height: 30px; cursor: pointer; color: var(--ink-faint);
    font-size: 15px; line-height: 1;
}
.cond-x:hover { border-color: var(--red); color: var(--red); }
.cond-actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 2px 0 4px; }
.cond-empty { color: var(--ink-faint); font-size: 12.5px; padding: 2px 0 8px; }
@media (max-width: 860px) {
    .cond-line { grid-template-columns: 1fr 1fr; }
    .cond-group { padding-left: 14px; }
    .cond-line + .cond-line::after { display: none; }
}

/* The worked example's reconciliation rows, so a reader can see the totals add up. */
.data tfoot .wk-foot td {
    background: var(--paper-2);
    border-top: 1px solid var(--line);
    color: var(--ink-soft);
    font-size: 12.5px;
}
.data tfoot .wk-foot:last-child td { border-top: 2px solid var(--line); color: var(--ink); }

/* ---------- project switcher (header) ---------- */
.proj-switch {
    display: inline-flex; align-items: center; gap: 7px;
    margin-right: 12px;
}
.proj-label {
    font-size: 10px; font-weight: 700; letter-spacing: .07em;
    text-transform: uppercase; color: rgba(255,255,255,.62);
}
.proj-switch select {
    font: inherit; font-size: 12.5px; font-weight: 600;
    color: #fff;
    background: rgba(255,255,255,.12);
    border: 1px solid rgba(255,255,255,.22);
    border-radius: 7px; padding: 4px 8px; max-width: 190px;
    cursor: pointer;
}
.proj-switch select:hover  { background: rgba(255,255,255,.19); }
.proj-switch select:focus  { outline: none; box-shadow: 0 0 0 3px rgba(255,255,255,.18); }
/* The dropdown list itself is painted by the OS, so it needs readable colours. */
.proj-switch select option { color: var(--ink); background: #fff; }
@media (max-width: 720px) {
    .proj-label { display: none; }
    .proj-switch select { max-width: 120px; }
}

/* ---------- Verify: the agreement matrix ---------- */
.vf-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 12px;
}
.vf-cell {
    border: 1px solid var(--line);
    border-left: 4px solid var(--line);
    border-radius: 10px;
    padding: 12px 14px;
    background: var(--paper-2);
}
.vf-cell strong { display: block; font-size: 26px; line-height: 1.1; color: var(--ink); }
.vf-cell span {
    display: block; margin-top: 4px; font-size: 11.5px; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--ink-soft);
}
.vf-cell em {
    display: block; margin-top: 6px; font-size: 12px; font-style: normal;
    color: var(--ink-faint); line-height: 1.45;
}
/* The two mistake cells are the ones worth noticing, so they are coloured by
   consequence rather than all four being decorative. */
.vf-cell.good { border-left-color: var(--green); background: var(--green-bg); }
.vf-cell.good strong { color: #04543a; }
.vf-cell.bad  { border-left-color: var(--red);   background: var(--red-bg); }
.vf-cell.bad strong { color: #7a1c15; }

/* The exact request text, in a preview that must not stretch the page. */
.pre-wrap {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 320px;
    overflow: auto;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 10px 12px;
    font-family: var(--mono);
    font-size: 12px;
    margin: 8px 0 0;
}

/* ---------- Verify: the two jobs this page does ---------- */
.two-jobs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 14px;
    margin: 0 0 18px;
}
.job-card {
    border: 1px solid var(--line);
    border-left: 4px solid var(--line);
    border-radius: 10px;
    padding: 14px 16px;
    background: var(--paper-2);
}
/* The eligibility check is the one that decides what reaches Updates, so it is
   the one that looks primary rather than the two reading as equals. */
.job-card.main { border-left-color: var(--navy); background: #fff; }
.job-tag {
    display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-faint); margin-bottom: 4px;
}
.job-card.main .job-tag { color: var(--navy); }
.job-card h3 { margin: 0 0 6px; font-size: 16px; color: var(--ink); }
.job-card p { margin: 0 0 6px; font-size: 13px; line-height: 1.5; color: var(--ink-soft); }
.job-where { font-size: 12px !important; color: var(--ink-faint) !important; margin: 8px 0 0 !important; }

/* ---------- the pace countdown ---------- */
.pace-clock {
    display: inline-block;
    font-family: var(--mono);
    font-size: 19px;
    font-weight: 700;
    letter-spacing: .02em;
    /* Tabular figures so the digits do not jitter as the seconds tick. */
    font-variant-numeric: tabular-nums;
    padding: 1px 8px;
    border-radius: 6px;
    background: rgba(255,255,255,.7);
    border: 1px solid var(--line);
    margin-top: 6px;
}
.pace-label { font-size: 12.5px; color: var(--ink-soft); }

/* ============================================================
   Verify: the always-visible countdown
   ============================================================
   It sits outside .page-head and directly inside main.wrap on purpose. A
   sticky element can only stick inside its own parent's box, and .page-head is
   barely taller than the heading - so put inside it, the clock scrolled out of
   view after twenty pixels, which is exactly the moment it becomes useful.
*/
.pace-now {
    position: sticky;
    /* Measured, not assumed: the top bar wraps to two rows on a narrow window
       and a hardcoded 62px hid the clock underneath it. */
    top: calc(var(--topbar-h, 62px) + 8px);
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin: 0 0 18px;
    padding: 12px 18px;
    border: 1px solid var(--line);
    border-left: 5px solid var(--ink-faint);
    border-radius: var(--radius);
    background: var(--panel);
    box-shadow: var(--shadow);
}
.pace-now .clk {
    font-family: var(--mono);
    font-size: 27px;
    font-weight: 700;
    line-height: 1.15;
    /* Tabular figures, so the digits do not jitter sideways every second. */
    font-variant-numeric: tabular-nums;
    color: var(--navy-dark);
    white-space: nowrap;
}
.pace-now .txt { display: flex; flex-direction: column; gap: 2px; min-width: 220px; flex: 1; }
.pace-now .lbl { font-weight: 700; font-size: 14.5px; color: var(--ink); }
.pace-now .sub { font-size: 12.5px; color: var(--ink-soft); line-height: 1.45; }

.pace-now.go   { border-left-color: var(--green); background: var(--green-bg); }
.pace-now.wait { border-left-color: var(--amber); background: var(--amber-bg); }
.pace-now.run  { border-left-color: var(--navy);  background: var(--blue-bg); }
.pace-now.done { border-left-color: var(--green); }
.pace-now.off  { border-left-color: var(--ink-faint); }

/* A slow pulse only while a batch is genuinely in flight, so a working run is
   never mistaken for a stopped clock. */
.pace-now.run .clk { animation: pacePulse 1.7s ease-in-out infinite; }
@keyframes pacePulse { 50% { opacity: .4; } }
@media (prefers-reduced-motion: reduce) { .pace-now.run .clk { animation: none; } }

@media (max-width: 700px) {
    .pace-now { position: static; }   /* too little screen to spend on a fixed strip */
}

/* ============================================================
   Verify: the model browser
   ============================================================ */
.model-tools {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
    margin: 10px 0;
}
.model-tools input[type="search"] {
    flex: 1;
    min-width: 240px;
    padding: 9px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 14px;
}
.chip {
    border: 1px solid var(--line);
    background: #fff;
    color: var(--ink-soft);
    border-radius: 999px;
    padding: 5px 13px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}
.chip:hover { border-color: var(--navy-light); color: var(--navy); }
.chip.on { background: var(--navy); border-color: var(--navy); color: #fff; }

/* The chain position shown against a model already in the list, so adding a
   duplicate is visibly pointless rather than an error you find out by pressing. */
.in-chain {
    font-size: 12px;
    font-weight: 700;
    color: var(--green);
    white-space: nowrap;
}

/* ============================================================
   Verify: the status strip - the gate switch and where things stand
   ============================================================ */
.fit-strip {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 16px 18px;
    margin-bottom: 18px;
}
.fit-strip-top {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--line-soft);
}
.fit-strip-top .why { flex: 1; min-width: 260px; font-size: 13px; color: var(--ink-soft); }

/* A real switch rather than a checkbox: this one decides whether an entire
   stage of the pipeline runs, and a 13px tickbox did not look like it. */
.switch { display: inline-flex; align-items: center; gap: 11px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
    width: 52px; height: 29px; border-radius: 999px;
    background: #c3cedb; position: relative; transition: background .16s;
    flex: none;
}
.switch .track::after {
    content: ''; position: absolute; top: 3px; left: 3px;
    width: 23px; height: 23px; border-radius: 50%;
    background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.3);
    transition: transform .16s;
}
.switch input:checked + .track { background: var(--green); }
.switch input:checked + .track::after { transform: translateX(23px); }
.switch input:focus-visible + .track { outline: 2px solid var(--navy-light); outline-offset: 2px; }
.switch .words { font-weight: 700; font-size: 15px; white-space: nowrap; }
.switch .words small { display: block; font-weight: 400; font-size: 12px; color: var(--ink-soft); }

/* The counters. Numbers alone were unreadable as a pipeline, so each tile
   says what stage it is and they are laid out left to right in that order. */
.tiles { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.tile {
    flex: 1 1 130px;
    border: 1px solid var(--line);
    border-radius: 9px;
    padding: 11px 13px;
    background: var(--bg);
    border-left: 4px solid var(--ink-faint);
}
.tile .n { font-size: 25px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.tile .k { font-size: 12px; font-weight: 700; color: var(--ink); margin-top: 2px; }
.tile .d { font-size: 11.5px; color: var(--ink-soft); line-height: 1.35; margin-top: 2px; }
.tile.in   { border-left-color: var(--navy);  }
.tile.wait { border-left-color: var(--amber); }
.tile.good { border-left-color: var(--green); }
.tile.bad  { border-left-color: var(--red);   }
.tile.grey { border-left-color: var(--ink-faint); }

/* How far through the queue this project is, at a glance. */
.progress { height: 8px; border-radius: 999px; background: var(--line-soft); overflow: hidden;
            margin-top: 14px; display: flex; }
.progress i { display: block; height: 100%; }
.progress i.good { background: var(--green); }
.progress i.bad  { background: var(--red); }
.progress i.grey { background: #b9c4d0; }

/* ============================================================
   Pop-out windows, for the settings that used to crowd the page
   ============================================================ */
dialog.ce {
    border: none;
    border-radius: 12px;
    padding: 0;
    width: min(920px, 94vw);
    max-height: 88vh;
    box-shadow: 0 20px 60px rgba(10,32,64,.35);
    color: var(--ink);
    background: var(--panel);
}
dialog.ce::backdrop { background: rgba(10,32,64,.45); }
dialog.ce .dlg-head {
    display: flex; align-items: flex-start; gap: 16px;
    padding: 16px 20px; border-bottom: 1px solid var(--line);
    position: sticky; top: 0; background: var(--panel); z-index: 2;
}
dialog.ce .dlg-head h3 { margin: 0; font-size: 18px; color: var(--navy-dark); }
dialog.ce .dlg-head .sub { font-size: 13px; color: var(--ink-soft); margin-top: 3px; }
dialog.ce .dlg-body { padding: 18px 20px; overflow: auto; max-height: calc(88vh - 132px); }
dialog.ce .dlg-foot {
    display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap;
    padding: 13px 20px; border-top: 1px solid var(--line); background: var(--bg);
    position: sticky; bottom: 0;
}
.dlg-x {
    margin-left: auto; border: 1px solid var(--line); background: #fff;
    width: 32px; height: 32px; border-radius: 8px; cursor: pointer;
    font-size: 19px; line-height: 1; color: var(--ink-soft); flex: none;
}
.dlg-x:hover { border-color: var(--red); color: var(--red); }

/* The folded-away advanced block. */
details.adv { border: 1px solid var(--line); border-radius: 9px; padding: 0; margin: 16px 0; }
details.adv > summary {
    cursor: pointer; padding: 11px 14px; font-weight: 700; font-size: 13.5px;
    color: var(--navy); list-style: none;
}
details.adv > summary::-webkit-details-marker { display: none; }
details.adv > summary::before { content: '\25B8  '; color: var(--ink-faint); }
details.adv[open] > summary::before { content: '\25BE  '; }
details.adv[open] > summary { border-bottom: 1px solid var(--line-soft); }
details.adv > *:not(summary) { padding: 0 14px; }
details.adv > *:last-child { padding-bottom: 14px; }

/* ============================================================
   One save button for the whole page
   ============================================================
   Splitting Save across panels meant a field could be edited with its own Save
   three screens away - and once the pace controls moved into a window, the
   profile box was left with no visible Save at all. One bar, always in reach,
   saves everything on the page.
*/
.save-bar {
    position: sticky;
    bottom: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 22px 0 0;
    padding: 13px 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--panel);
    box-shadow: 0 -3px 14px rgba(16,32,64,.10);
}
.save-bar .what { flex: 1; min-width: 220px; font-size: 13px; color: var(--ink-soft); }
.save-bar.dirty { border-color: var(--amber); background: var(--amber-bg); }
.save-bar.dirty .what { color: var(--amber); font-weight: 600; }
.save-dot {
    display: inline-block; width: 9px; height: 9px; border-radius: 50%;
    background: var(--green); margin-right: 7px; vertical-align: baseline;
}
.save-bar.dirty .save-dot { background: var(--amber); }

/* ============================================================
   Verify: a two-column working layout
   ============================================================
   The page had grown to five stacked panels and roughly four screens. Reading
   the queue meant scrolling past every setting; changing a setting meant losing
   sight of the queue. Splitting it puts the thing you look at on the left and
   the thing you act with on the right, and each side scrolls on its own so the
   PAGE stops growing however much is in either.
*/
.vgrid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 372px;
    gap: 18px;
    align-items: start;
}
.vgrid > * { min-width: 0; }   /* or a wide table forces the column open */

/* The right column.
   ---------------------------------------------------------------------------
   No internal scrollbars here, by request. Every panel takes the height its
   content needs and the PAGE grows instead. That is the trade: one scrollbar
   for the whole document rather than a scroller inside a scroller inside a
   column, which is fiddly to use and hides things you did not know were there.

   Kept from the version that did scroll: nothing shrinks. These are flex items,
   and a flex item defaults to flex-shrink:1 - which is what crushed the panels
   to a third of their height and clipped the content instead of scrolling it.
   With natural heights that cannot happen, but the rule stays as a guard. */
.vside {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}
.vside > * { flex: 0 0 auto; }
.vside .panel { margin: 0; }
/* A hidden panel takes no space, in either layout. Stated after the panel rules
   and marked important because the stacked layout sets `display: block` on
   them, which would otherwise beat the [hidden] attribute and show an empty
   "Failed" panel with nothing in it. */
.vside > [hidden] { display: none !important; }

/* Below this there is not enough width for two useful columns. */
@media (max-width: 1080px) {
    .vgrid { grid-template-columns: 1fr; }
    /* Stacked, there is no shared height to divide, so every constraint above is
       undone - otherwise the panels stay capped for no reason. */
    .vside { display: block; }
    .vside .panel { margin-bottom: 14px; }
}

/* A table that scrolls inside itself rather than lengthening the page. */
.pane-scroll {
    max-height: 58vh;
    overflow: auto;
    border: 1px solid var(--line-soft);
    border-radius: 8px;
}
.pane-scroll table.data { margin: 0; }
.pane-scroll thead th {
    position: sticky; top: 0; z-index: 1;
    background: var(--bg);
    box-shadow: inset 0 -1px 0 var(--line);
}

/* ---------- what is next in the queue ---------- */
.upnext { display: flex; flex-direction: column; gap: 0; }
.upnext-group {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .04em; color: var(--ink-faint);
    padding: 10px 0 6px;
}
.upnext-group.retry { color: var(--amber); }
.up {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 8px 0; border-top: 1px solid var(--line-soft);
    font-size: 12.5px;
}
.up .pos {
    flex: none; width: 22px; height: 22px; border-radius: 50%;
    background: var(--line-soft); color: var(--ink-soft);
    font-size: 11px; font-weight: 700; line-height: 22px; text-align: center;
}
/* The ones that go in the very next run, marked so the batch size is visible
   rather than something you work out from a number in another panel. */
.up.now .pos { background: var(--navy); color: #fff; }
.up.retryrow .pos { background: var(--amber); color: #fff; }
.up .t { min-width: 0; }
.up .t b { font-weight: 600; color: var(--ink); display: block; }
.up .t small { color: var(--ink-soft); }
.up .t small.bad { color: var(--red); }

/* ---------- a compact panel for the sidebar ---------- */
/* Compact heads. In a 372px column a two-line description plus a button wrapped
   to 126px of heading on a 150px panel - leaving 24px for the list itself. */
.panel.tight .panel-head { padding: 9px 12px; gap: 8px; }
.panel.tight .panel-head h2 { font-size: 14.5px; }
.panel.tight .panel-body { padding: 10px 12px; }
.panel.tight .sub { font-size: 11.5px; line-height: 1.35; }
.panel.tight .btn.sm { padding: 4px 9px; font-size: 11.5px; }

/* ---------- the queue's own toolbar ---------- */
.qbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}
.panel-head input[type="search"] {
    width: 190px;
    padding: 6px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 13px;
}
/* One row of tabs rather than two: eight full sentences wrapped to 69px of
   height, which is two rows of the table it was pushing down. */
.btn-row.tabs { gap: 5px; margin-bottom: 12px; }
/* Measured: at 11px padding the eight tabs wanted 867px in an 812px column and
   still wrapped. These numbers are chosen to fit, not by eye. */
.btn-row.tabs .btn { padding: 6px 8px; font-size: 12px; }
.btn-row.tabs .btn .badge { margin-left: 3px; padding: 1px 5px; font-size: 10.5px; }

/* Keep the two columns the same height, so the page scrolls once rather than
   the left side running on past the end of the right. */
.pane-scroll { max-height: clamp(280px, calc(100vh - 330px), 760px); }

/* ---- how long the fit queue takes, each way (Verify) ----------------------
   Sits under the pace summary in a panel that shares its height with two
   lists, so it is built as tight rows rather than cards: name, rate, time,
   caveat. The finishing time is the point, so it is the only bold thing. */
.eta {
  margin: 0 0 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  font-size: 12px;
  line-height: 1.5;
}
.eta-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  padding: 7px 11px;
  background: var(--line-soft);
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  color: var(--ink);
}
.eta-now {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-faint);
}
.eta-row {
  display: grid;
  /* Name and rate sized to their content, the time given whatever is left, and
     the caveat dropped onto its own full-width line beneath. */
  grid-template-columns: minmax(0, auto) minmax(0, auto) 1fr;
  gap: 2px 10px;
  align-items: baseline;
  padding: 8px 11px;
  border-bottom: 1px solid var(--line-soft);
}
.eta-row:last-child { border-bottom: 0; }
.eta-row.eta-self { border-left: 3px solid var(--green); }
.eta-row.eta-cron { border-left: 3px solid var(--navy-light); }
.eta-row.eta-off  { border-left: 3px solid var(--ink-faint); }
.eta-name { font-weight: 600; color: var(--ink); }
.eta-rate {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.eta-time { justify-self: end; text-align: right; white-space: nowrap; }
.eta-time strong { color: var(--ink); }
.eta-at {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-soft);
}
.eta-note {
  grid-column: 1 / -1;
  color: var(--ink-faint);
  font-size: 11.5px;
}
.eta-none { display: block; padding: 9px 11px; color: var(--ink-soft); }
.eta-warn {
  margin: 0;
  padding: 8px 11px;
  background: var(--amber-bg);
  border-top: 1px solid var(--line);
  color: var(--amber);
  font-size: 11.5px;
  line-height: 1.55;
}

/* One column is unreadable at this width; let the time fall under the name. */
@media (max-width: 560px) {
  .eta-row { grid-template-columns: 1fr; }
  .eta-time { justify-self: start; text-align: left; }
}

/* An item that never went through the Verify gate. Deliberately the most
   noticeable badge in the row: the others report a judgement, this one reports
   that no judgement was made, which is the easier thing to miss. */
.badge.unchecked {
  background: #fff;
  color: var(--ink-soft);
  border: 1px dashed var(--ink-faint);
}

/* ---- the digest designer (Email) -----------------------------------------
   Controls on the left, a live render on the right. Side by side is the whole
   point: the preview is what tells you whether a colour or a dropped field was
   a good idea, and a preview you have to scroll to is one you stop looking at. */
.design-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
}
.design-preview { position: sticky; top: 78px; }
.design-preview-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 7px;
  font-size: 12.5px;
  color: var(--ink);
}
.design-preview-head .hint { margin: 0; }
.mailframe.tall { height: 560px; }

/* The swatch and the hex box are one control in two halves. */
.colour-row { display: flex; gap: 8px; align-items: center; }
.colour-row input[type="color"] {
  width: 42px;
  height: 34px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  flex: 0 0 auto;
}
.colour-row input[type="text"] { flex: 1; min-width: 0; font-family: var(--mono); }

/* Six switches read as a list at full width; two columns keeps them together. */
.chk-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 14px;
  margin-top: 2px;
}
.field-label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 5px;
}

@media (max-width: 900px) {
  .design-grid { grid-template-columns: 1fr; }
  .design-preview { position: static; }
  .chk-grid { grid-template-columns: 1fr; }
}

/* The next send, called out inside the schedule explainer. */
.sched-next {
  display: inline-block;
  margin-top: 5px;
  padding: 3px 9px;
  background: var(--blue-bg);
  border-radius: 5px;
  font-size: 12px;
  color: var(--navy);
}


/* ---- the cPanel setup guide (Email) -------------------------------------- */
.setup-route h3 {
  margin: 0 0 6px;
  font-size: 14px;
  color: var(--navy);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.setup-table { width: 100%; margin: 4px 0 10px; }
.setup-table th {
  width: 38%;
  text-align: left;
  vertical-align: top;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid var(--line-soft);
  white-space: nowrap;
}
.setup-table td {
  font-size: 12.5px;
  color: var(--ink);
  padding: 6px 0;
  border-bottom: 1px solid var(--line-soft);
}
.setup-table code {
  background: var(--blue-bg);
  border-radius: 4px;
  padding: 1px 5px;
  font-family: var(--mono);
  font-size: 11.5px;
}
/*
 * A command in a header cell must not be uppercased.
 *
 * `.data th` uppercases, which is right for a label and wrong for anything
 * meant to be copied: the deploy table rendered "SH DEPLOY/FOLDERS.SH", and
 * that does not run. Scoped to code so ordinary labels keep the house style.
 */
.setup-table th code { text-transform: none; }
.setup-table .hint { display: block; margin-top: 3px; }

/* Today's AI allowance, above the throughput estimate on Verify. It sits first
   because it outranks the numbers below it: once the provider stops answering,
   no pace or batch setting means anything. */
.eta-cap {
  padding: 7px 11px;
  background: var(--blue-bg);
  border-bottom: 1px solid var(--line);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--navy);
}
.eta-cap.out { background: var(--red-bg); color: var(--red); }

/* ---- extra AI services (Verify -> the reader) -----------------------------
   A grid rather than a table: the name and the allowance are narrow and fixed,
   the URL and key take what is left, and it collapses to stacked rows on a
   narrow window without a horizontal scrollbar. */
.svc-row {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr) minmax(0, 1fr) 84px 30px;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.svc-row input { width: 100%; min-width: 0; }
.svc-row.svc-head {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--ink-faint);
  margin-bottom: 3px;
}
.svc-row .svc-del { padding: 4px 8px; line-height: 1; }
.svc-empty {
  padding: 9px 11px;
  background: var(--line-soft);
  border-radius: 6px;
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
@media (max-width: 760px) {
  .svc-row { grid-template-columns: 1fr 1fr; }
  .svc-row.svc-head { display: none; }
}

/* A feed-backed source is marked on its category badge. The suffix carries the
   meaning; the colour only makes it findable while scanning the list. */
.badge .badge-mark {
  margin-left: 5px;
  padding-left: 5px;
  border-left: 1px solid currentColor;
  opacity: .75;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .4px;
}

/* ---- developer panel (Settings) ------------------------------------------
   Config meant to be copied out, so it is monospaced, selectable and scrolls
   rather than wrapping - a wrapped JSON path is one people mis-paste. */
.dev-code {
  margin: 6px 0 12px;
  padding: 11px 13px;
  background: var(--ink);
  color: #dbe7f2;
  border-radius: 7px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.55;
  overflow-x: auto;
  white-space: pre;
  user-select: text;
}
.dev-code .dev-dim { color: var(--ink-faint); }

/* ---- Changes page ---------------------------------------------------------
   One card per watched URL, with its diffs folded away underneath. Folded by
   default because a redesigned page can produce forty changed lines, and the
   question on arriving is "which pages moved", not "show me every line". */
.chg {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: 12px;
  background: var(--panel);
  overflow: hidden;
}
.chg:last-child { margin-bottom: 0; }

.chg-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  flex-wrap: wrap;
}
.chg-title { flex: 1 1 320px; min-width: 0; }
.chg-title a { font-weight: 600; text-decoration: none; }
.chg-title a:hover { text-decoration: underline; }

/* The URL is the identity of the thing being watched, so it is always shown -
   but it must not push the card wide, hence the clip. */
.chg-url {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chg-meta { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.chg-when { color: var(--ink-soft); font-size: 12.5px; }
.chg-act  { display: flex; gap: 6px; }

.chg-body {
  border-top: 1px solid var(--line-soft);
  background: var(--bg);
  padding: 10px 14px 14px;
}
.chg-one { margin-top: 10px; }
.chg-one:first-child { margin-top: 0; }
.chg-one-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 5px;
}

/* The diff itself. Monospaced and pre-wrapped: these are lines lifted verbatim
   off a page, and re-flowing them loses which line was which. Capped in height
   because forty changed lines should not push the next card off screen. */
pre.diff {
  margin: 0;
  padding: 9px 11px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 7px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.6;
  max-height: 340px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}
/* An edit in place gets its own colour - it is neither an addition nor a
   removal, and it is the kind of change a watched page is watched for. */
pre.diff .mod { color: var(--amber); display: block; }
pre.diff .add { color: var(--green); display: block; }
pre.diff .del { color: var(--red);   display: block; }
pre.diff .hd  { color: var(--ink-soft); font-weight: 600; display: block; margin-top: 4px; }

/* A compact label+select for a panel header, where a full form label would
   double the header's height. */
.inline-mini {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.inline-mini select { margin: 0; }

/* A row whose subject is broken rather than merely quiet. */
tr.row-bad td { background: var(--red-bg); }

/* ==========================================================================
   MATERIAL DESIGN 3
   ==========================================================================
   Scoped to main.md, so pages opt in one at a time and the other eight keep
   the original stylesheet exactly as it was. The token block is global because
   tokens cost nothing unused, and because the next page brought over should
   not have to redefine them.

   The palette is derived from the two colours the app already had - the navy
   #0f3d64 as the primary seed and the amber #f0a020 as the tertiary - rather
   than from Material's default purple. A dashboard that suddenly looked like a
   different product would be a worse outcome than one that looks like this app
   built properly.

   No web fonts and no icon font. Roboto is named first and falls back to the
   system UI stack, and the icons are inline SVG. This app has to run on shared
   hosting with no build step and no external requests; pulling a font off a
   CDN would add a dependency and a render-blocking round trip to buy something
   the system font already does.
   ========================================================================== */

:root {
    /* ---- colour roles ---- */
    --md-primary:                    #10456f;
    --md-on-primary:                 #ffffff;
    --md-primary-container:          #d3e4f7;
    --md-on-primary-container:       #001d33;

    --md-secondary:                  #4f616e;
    --md-secondary-container:        #dce7f0;
    --md-on-secondary-container:     #1a2c38;

    --md-tertiary:                   #7a5300;
    --md-tertiary-container:         #ffdeac;
    --md-on-tertiary-container:      #271900;

    --md-error:                      #b3261e;
    --md-error-container:            #f9dedc;
    --md-on-error-container:         #410e0b;

    --md-success:                    #0a6c4a;
    --md-success-container:          #c8f0dd;
    --md-on-success-container:       #00210f;

    /* Surfaces, lightest to most tinted. Elevation in M3 is carried as much by
       these tonal steps as by shadow, which is why there are five of them. */
    --md-surface:                    #f7f9fc;
    --md-surface-lowest:             #ffffff;
    --md-surface-low:                #f1f4f8;
    --md-surface-mid:                #ebeff4;
    --md-surface-high:               #e5eaf0;

    --md-on-surface:                 #191c1f;
    --md-on-surface-variant:         #42474e;
    --md-outline:                    #72777f;
    --md-outline-variant:            #c3c7cf;

    /* ---- elevation ---- */
    --md-elev-1: 0 1px 2px rgba(0,0,0,.16), 0 1px 3px 1px rgba(0,0,0,.08);
    --md-elev-2: 0 1px 2px rgba(0,0,0,.16), 0 2px 6px 2px rgba(0,0,0,.08);
    --md-elev-3: 0 4px 8px 3px rgba(0,0,0,.10), 0 1px 3px rgba(0,0,0,.16);

    /* ---- shape ---- */
    --md-r-xs: 4px;
    --md-r-sm: 8px;
    --md-r-md: 12px;
    --md-r-lg: 16px;
    --md-r-xl: 28px;
    --md-r-full: 999px;

    /* ---- type ---- */
    --md-font: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

    /* ---- the 8dp grid ---- */
    --md-sp-1: 4px;
    --md-sp-2: 8px;
    --md-sp-3: 12px;
    --md-sp-4: 16px;
    --md-sp-6: 24px;
    --md-sp-8: 32px;
}

main.md {
    background: var(--md-surface);
    color: var(--md-on-surface);
    font-family: var(--md-font);
    padding: var(--md-sp-6) var(--md-sp-6) var(--md-sp-8);
    margin: 0 auto;
}

/* ---------------- type scale ---------------- */

main.md h1 {                       /* headline-large */
    font-size: 32px;
    line-height: 40px;
    letter-spacing: 0;
    font-weight: 400;
    margin: 0 0 var(--md-sp-2);
    color: var(--md-on-surface);
}
main.md .md-head > div > p {       /* body-large */
    font-size: 16px;
    line-height: 24px;
    letter-spacing: .15px;
    color: var(--md-on-surface-variant);
    margin: 0;
    max-width: 62ch;
}
main.md h2 {                       /* title-large */
    font-size: 20px;
    line-height: 28px;
    letter-spacing: 0;
    font-weight: 500;
    margin: 0;
    color: var(--md-on-surface);
}
main.md h3 {                       /* title-medium */
    font-size: 16px;
    line-height: 24px;
    letter-spacing: .15px;
    font-weight: 500;
    margin: 0 0 var(--md-sp-1);
    color: var(--md-on-surface);
}
main.md .md-sub {                  /* body-medium */
    font-size: 14px;
    line-height: 20px;
    letter-spacing: .25px;
    color: var(--md-on-surface-variant);
    margin-top: 2px;
}

/* ---------------- page header ---------------- */

.md-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--md-sp-6);
    flex-wrap: wrap;
    margin-bottom: var(--md-sp-6);
}
.md-actions { display: flex; gap: var(--md-sp-2); flex-wrap: wrap; }

/* ---------------- buttons ---------------- */
/* One shape, three emphases - filled, tonal, text - which is the whole M3
   button system. The state layer is a ::before overlay at a fixed opacity
   rather than a hand-mixed hover colour, so it works on every variant. */

.md-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--md-sp-2);
    height: 40px;
    padding: 0 var(--md-sp-6);
    border: none;
    border-radius: var(--md-r-full);
    font-family: var(--md-font);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    text-decoration: none;
    cursor: pointer;
    overflow: hidden;
    white-space: nowrap;
    transition: box-shadow .15s ease;
}
.md-btn::before {
    content: "";
    position: absolute;
    inset: 0;
    background: currentColor;
    opacity: 0;
    transition: opacity .15s ease;
}
.md-btn:hover::before         { opacity: .08; }
.md-btn:focus-visible::before { opacity: .12; }
.md-btn:active::before        { opacity: .12; }
.md-btn:focus-visible {
    outline: 3px solid var(--md-primary);
    outline-offset: 2px;
}
.md-btn > svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
    flex: none;
}

.md-btn.filled { background: var(--md-primary); color: var(--md-on-primary); }
.md-btn.filled:hover { box-shadow: var(--md-elev-1); }
.md-btn.tonal  { background: var(--md-secondary-container); color: var(--md-on-secondary-container); }
.md-btn.text   { background: transparent; color: var(--md-primary); padding: 0 var(--md-sp-3); }

/* ---------------- cards ---------------- */

.md-card {
    background: var(--md-surface-lowest);
    border-radius: var(--md-r-md);
    box-shadow: var(--md-elev-1);
    margin-bottom: var(--md-sp-6);
    overflow: hidden;
}
.md-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--md-sp-4);
    padding: var(--md-sp-4) var(--md-sp-6) 0;
    flex-wrap: wrap;
}
.md-card-body { padding: var(--md-sp-4) var(--md-sp-6) var(--md-sp-6); }
/* Lists and tables run to the card's own edge; only prose gets the inset. */
.md-card-body.flush { padding-left: 0; padding-right: 0; padding-bottom: 0; }

/* ---------------- KPI cards ---------------- */
/* Filled cards on a tonal container, which is how M3 shows a number that
   matters without giving it a border. The colour is the state: amber wants
   attention, green is fine, plain is neutral. */

.md-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--md-sp-4);
    margin-bottom: var(--md-sp-6);
}
.md-kpi {
    background: var(--md-surface-lowest);
    border-radius: var(--md-r-md);
    padding: var(--md-sp-4) var(--md-sp-4) var(--md-sp-3);
    box-shadow: var(--md-elev-1);
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.md-kpi .label {                   /* label-large */
    font-size: 14px;
    line-height: 20px;
    letter-spacing: .1px;
    font-weight: 500;
    color: var(--md-on-surface-variant);
    display: flex;
    align-items: center;
    gap: var(--md-sp-2);
}
.md-kpi .label svg { width: 18px; height: 18px; fill: currentColor; flex: none; }
.md-kpi .value {                   /* display-small, tabular so digits do not jump */
    font-size: 36px;
    line-height: 44px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    color: var(--md-on-surface);
}
.md-kpi .foot {                    /* body-small */
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .4px;
    color: var(--md-on-surface-variant);
}
.md-kpi.accent {
    background: var(--md-tertiary-container);
    color: var(--md-on-tertiary-container);
}
.md-kpi.good {
    background: var(--md-success-container);
    color: var(--md-on-success-container);
}
.md-kpi.bad {
    background: var(--md-error-container);
    color: var(--md-on-error-container);
}
/* The tonal variants set their own text colour on the card, so the children
   inherit it instead of keeping the neutral roles above. */
.md-kpi.accent .label, .md-kpi.accent .value, .md-kpi.accent .foot,
.md-kpi.good   .label, .md-kpi.good   .value, .md-kpi.good   .foot,
.md-kpi.bad    .label, .md-kpi.bad    .value, .md-kpi.bad    .foot { color: inherit; }

/* ---------------- the stepper ---------------- */

.md-steps {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--md-sp-6) var(--md-sp-4);
}
.md-step { display: flex; gap: var(--md-sp-3); position: relative; min-width: 0; }

/* The connector, drawn from each marker towards the next. Hidden on the last
   step, and below the wrap width where a horizontal line would point at
   nothing. */
.md-step::after {
    content: "";
    position: absolute;
    top: 19px;
    left: 40px;
    right: calc(-1 * var(--md-sp-4));
    height: 2px;
    background: var(--md-outline-variant);
}
.md-step:last-child::after { display: none; }

.md-step-mark {
    width: 40px;
    height: 40px;
    border-radius: var(--md-r-full);
    background: var(--md-surface-high);
    color: var(--md-on-surface-variant);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    z-index: 1;
    transition: background .2s ease, color .2s ease, box-shadow .2s ease;
}
.md-step-mark svg { width: 20px; height: 20px; fill: currentColor; }

.md-step-txt { min-width: 0; }
.md-step-txt p {
    font-size: 14px;
    line-height: 20px;
    letter-spacing: .25px;
    color: var(--md-on-surface-variant);
    margin: 0 0 var(--md-sp-2);
}
.md-step-txt a {
    font-size: 14px;
    font-weight: 500;
    color: var(--md-primary);
    text-decoration: none;
}
.md-step-txt a:hover { text-decoration: underline; }

/* Done: the stage has produced something. Active: it is the one waiting on
   you, so it is ringed rather than filled - M3 uses the outline for "current",
   and filling both states identically is what made the old steps unreadable. */
.md-step.done .md-step-mark {
    background: var(--md-primary);
    color: var(--md-on-primary);
}
.md-step.active .md-step-mark {
    background: var(--md-tertiary-container);
    color: var(--md-on-tertiary-container);
    box-shadow: 0 0 0 3px var(--md-tertiary-container), 0 0 0 5px var(--md-tertiary);
}
.md-step.done::after { background: var(--md-primary); }

@media (max-width: 700px) {
    .md-step::after { display: none; }
}

/* ---------------- two-column body ---------------- */

.md-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
    gap: var(--md-sp-6);
    align-items: start;
}
.md-col { min-width: 0; }
.md-col .md-card:last-child { margin-bottom: 0; }

@media (max-width: 1000px) {
    .md-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------- lists, tables and bars inside cards ---------------- */

main.md .md-table th {
    font-size: 12px;
    font-weight: 500;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    background: var(--md-surface-low);
    border-bottom: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .md-table td {
    font-size: 14px;
    line-height: 20px;
    border-bottom: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
    color: var(--md-on-surface);
}
main.md .md-table tbody tr:last-child td { border-bottom: none; }
main.md .md-table tbody tr:hover td { background: var(--md-surface-low); }

/* M3 linear progress: a full-width track with the indicator over it, so a
   zero-length bar still shows where the scale is. */
main.md .progress {
    height: 4px;
    border-radius: var(--md-r-full);
    background: var(--md-surface-high);
    overflow: hidden;
}
main.md .progress > i {
    display: block;
    height: 100%;
    border-radius: var(--md-r-full);
    background: var(--md-primary);
}

main.md .md-kv { margin: 0; }
main.md .md-kv dt {
    font-size: 14px;
    letter-spacing: .25px;
    color: var(--md-on-surface-variant);
}
main.md .md-kv dd {
    font-size: 14px;
    font-weight: 500;
    color: var(--md-on-surface);
}

/* News items become M3 list items: separated by a divider rather than boxed,
   with the work-mode colour kept as a leading edge so the existing is-remote
   and is-hybrid classes still mean something. */
main.md .news-item {
    border: none;
    border-bottom: 1px solid var(--md-outline-variant);
    border-left: 4px solid transparent;
    border-radius: 0;
    margin: 0;
    padding: var(--md-sp-4) var(--md-sp-6);
    background: transparent;
    transition: background .12s ease;
}
main.md .news-item:hover { background: var(--md-surface-low); }
main.md .news-item:last-child { border-bottom: none; }
main.md .news-item h3 { font-size: 15px; line-height: 22px; font-weight: 500; }
main.md .news-item h3 a { color: var(--md-on-surface); text-decoration: none; }
main.md .news-item h3 a:hover { color: var(--md-primary); text-decoration: underline; }
main.md .news-item.is-remote { border-left-color: var(--md-success); }
main.md .news-item.is-hybrid { border-left-color: var(--md-tertiary); }
main.md .news-item.is-onsite { border-left-color: var(--md-outline); }
main.md .news-snippet {
    font-size: 14px;
    line-height: 20px;
    color: var(--md-on-surface-variant);
}

main.md .empty { padding: var(--md-sp-8) var(--md-sp-6); color: var(--md-on-surface-variant); }
main.md .empty h3 { font-size: 16px; }

/* Badges keep their meaning but take the M3 chip shape, so a row of them under
   a list item reads as chips rather than as tags from another design. */
main.md .badge {
    border-radius: var(--md-r-sm);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: .5px;
    padding: 3px 8px;
    border: 1px solid var(--md-outline-variant);
    background: var(--md-surface-low);
    color: var(--md-on-surface-variant);
}

/* ==========================================================================
   MATERIAL DESIGN 3 - the existing component set
   ==========================================================================
   The dashboard got bespoke md-* markup because it is a read-only page of nine
   cards. Sources is 563 lines with 115 ids and 1,539 lines of JS reading them,
   and Extract, Verify and Settings are the same shape. Rewriting that markup
   to match the dashboard's would mean touching every one of those ids to buy
   nothing the user can see.

   So the components the pages already use are restyled in place instead:
   .panel becomes a Material card, .btn the Material button system, .field a
   filled text field, .tabs a tab bar with an indicator, and so on. Adding `md`
   to a page's <main> converts it, and nothing in its markup or its JavaScript
   changes.

   Everything is under main.md, so a page without that class is untouched.
   ========================================================================== */

/* ---------------- page header ---------------- */

main.md .page-head {
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: var(--md-sp-6);
    align-items: flex-end;
    gap: var(--md-sp-6);
}
main.md .page-head h1 {
    font-size: 32px;
    line-height: 40px;
    font-weight: 400;
    letter-spacing: 0;
    color: var(--md-on-surface);
}
main.md .page-head p {
    font-size: 16px;
    line-height: 24px;
    letter-spacing: .15px;
    color: var(--md-on-surface-variant);
    max-width: 68ch;
}

main.md .section-h {
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    text-transform: none;
    color: var(--md-primary);
    border-bottom: 1px solid var(--md-outline-variant);
    padding-bottom: var(--md-sp-2);
    margin: var(--md-sp-8) 0 var(--md-sp-4);
}

main.md .crumb { color: var(--md-on-surface-variant); font-size: 14px; }

/* ---------------- panels as Material cards ---------------- */

main.md .panel {
    background: var(--md-surface-lowest);
    border: none;
    border-radius: var(--md-r-md);
    box-shadow: var(--md-elev-1);
    margin-bottom: var(--md-sp-6);
}
main.md .panel-head {
    background: transparent;
    border-bottom: none;
    padding: var(--md-sp-4) var(--md-sp-6) 0;
    gap: var(--md-sp-4);
}
main.md .panel-head h2 {
    font-size: 20px;
    line-height: 28px;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--md-on-surface);
}
main.md .panel-head .sub {
    font-size: 14px;
    line-height: 20px;
    letter-spacing: .25px;
    color: var(--md-on-surface-variant);
}
main.md .panel-body { padding: var(--md-sp-4) var(--md-sp-6) var(--md-sp-6); }
main.md .panel-body.tight { padding: 0; }

/* A panel that opens beneath a tab bar has the bar as its top edge, so it must
   not also carry the card's rounded top or it shows a sliver of white. */
main.md .tabs + .panel-body,
main.md .tabs ~ .panel-body { border-top: none; }

/* ---------------- stat cards ---------------- */

main.md .stat {
    background: var(--md-surface-lowest);
    border: none;
    border-left: none;
    border-radius: var(--md-r-md);
    box-shadow: var(--md-elev-1);
    padding: var(--md-sp-4) var(--md-sp-4) var(--md-sp-3);
}
main.md .stat .label {
    font-size: 14px;
    line-height: 20px;
    font-weight: 500;
    letter-spacing: .1px;
    text-transform: none;
    color: var(--md-on-surface-variant);
}
main.md .stat .value {
    font-size: 32px;
    line-height: 40px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    color: var(--md-on-surface);
}
main.md .stat .foot { font-size: 12px; letter-spacing: .4px; color: var(--md-on-surface-variant); }

/* State by tonal container rather than by a coloured left border, which is how
   M3 says "this number wants attention" - and reads at a glance instead of
   needing you to notice a 3px stripe. */
main.md .stat.accent { background: var(--md-tertiary-container); color: var(--md-on-tertiary-container); }
main.md .stat.good   { background: var(--md-success-container);  color: var(--md-on-success-container); }
main.md .stat.bad    { background: var(--md-error-container);    color: var(--md-on-error-container); }
main.md .stat.accent .label, main.md .stat.accent .value, main.md .stat.accent .foot,
main.md .stat.good   .label, main.md .stat.good   .value, main.md .stat.good   .foot,
main.md .stat.bad    .label, main.md .stat.bad    .value, main.md .stat.bad    .foot { color: inherit; }

/* ---------------- buttons ---------------- */
/* The three emphases map onto the classes the pages already use:
     .btn         filled    - the primary action
     .btn.ghost   outlined  - a secondary action, of which these pages have many
     .btn.danger  outlined in the error role
   The state layer is a ::before overlay so hover, focus and press behave the
   same on all of them without a hand-mixed colour each. */

main.md .btn {
    position: relative;
    overflow: hidden;
    border: none;
    border-radius: var(--md-r-full);
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-family: var(--md-font);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    padding: 10px 24px;
    box-shadow: none;
    transition: box-shadow .15s ease;
}
main.md .btn::before {
    content: "";
    position: absolute;
    inset: 0;
    background: currentColor;
    opacity: 0;
    transition: opacity .15s ease;
}
main.md .btn:hover::before         { opacity: .08; }
main.md .btn:focus-visible::before { opacity: .12; }
main.md .btn:active::before        { opacity: .12; }
main.md .btn:hover  { background: var(--md-primary); box-shadow: var(--md-elev-1); }
main.md .btn:active { transform: none; }
main.md .btn:focus-visible { outline: 3px solid var(--md-primary); outline-offset: 2px; }

main.md .btn.ghost {
    background: transparent;
    color: var(--md-primary);
    border: 1px solid var(--md-outline);
    box-shadow: none;
}
main.md .btn.ghost:hover { background: transparent; box-shadow: none; }

main.md .btn.accent {
    background: var(--md-tertiary-container);
    color: var(--md-on-tertiary-container);
}
main.md .btn.accent:hover { background: var(--md-tertiary-container); }

main.md .btn.danger {
    background: transparent;
    color: var(--md-error);
    border: 1px solid var(--md-error);
}
main.md .btn.danger:hover { background: transparent; }

main.md .btn.sm { padding: 6px 16px; font-size: 13px; border-radius: var(--md-r-full); }
main.md .btn.lg { padding: 13px 28px; font-size: 15px; }

main.md .btn[disabled], main.md .btn.is-busy { opacity: .38; box-shadow: none; }
main.md .btn[disabled]::before, main.md .btn.is-busy::before { opacity: 0; }

main.md .btn-row { gap: var(--md-sp-2); }

/* A row of buttons used as tabs keeps the pill shape but drops the fill, so the
   selected one is the only filled thing in the row. */
main.md .btn-row.tabs { border-bottom: none; padding: 0; background: none; }
main.md .btn-row.tabs .btn {
    padding: 6px 14px;
    font-size: 13px;
    background: transparent;
    color: var(--md-on-surface-variant);
    border: 1px solid var(--md-outline-variant);
}
main.md .btn-row.tabs .btn.active {
    background: var(--md-secondary-container);
    color: var(--md-on-secondary-container);
    border-color: transparent;
}

/* ---------------- form fields ---------------- */
/* M3 outlined text fields. Outlined rather than filled because these pages put
   many inputs in a grid, and a row of filled boxes reads as a solid block. */

main.md label.field { margin-bottom: var(--md-sp-4); }
main.md label.field > span {
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    text-transform: none;
    color: var(--md-on-surface);
    margin-bottom: var(--md-sp-2);
}
main.md label.field .hint,
main.md .hint {
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .4px;
    color: var(--md-on-surface-variant);
}

main.md input[type=text], main.md input[type=url], main.md input[type=email],
main.md input[type=number], main.md input[type=password], main.md input[type=search],
main.md select, main.md textarea {
    font-family: var(--md-font);
    font-size: 14px;
    line-height: 20px;
    color: var(--md-on-surface);
    background: var(--md-surface-lowest);
    border: 1px solid var(--md-outline);
    border-radius: var(--md-r-xs);
    padding: 10px 14px;
    box-shadow: none;
    transition: border-color .12s ease, box-shadow .12s ease;
}
main.md textarea { font-family: var(--mono); font-size: 13px; }

/* Two pixels of the primary colour, drawn as an inset shadow so the field does
   not change size on focus - a 2px border would shift every label beside it. */
main.md input:focus, main.md select:focus, main.md textarea:focus {
    outline: none;
    border-color: var(--md-primary);
    box-shadow: inset 0 0 0 1px var(--md-primary);
}
main.md input[type=checkbox] { accent-color: var(--md-primary); }

main.md .inline-check {
    font-size: 14px;
    line-height: 20px;
    color: var(--md-on-surface);
}

/* ---------------- tabs ---------------- */

main.md .tabs {
    background: transparent;
    border-bottom: 1px solid var(--md-outline-variant);
    padding: 0 var(--md-sp-6);
    gap: 0;
}
main.md .tabs button {
    position: relative;
    font-family: var(--md-font);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    color: var(--md-on-surface-variant);
    border-bottom: none;
    padding: var(--md-sp-4) var(--md-sp-4) var(--md-sp-3);
    background: transparent;
}
main.md .tabs button:hover { color: var(--md-on-surface); }
/* The indicator is a rounded bar under the label, which is the M3 shape, and it
   is a ::after so it cannot affect the button's height when it appears. */
main.md .tabs button.active { color: var(--md-primary); }
main.md .tabs button.active::after {
    content: "";
    position: absolute;
    left: var(--md-sp-2);
    right: var(--md-sp-2);
    bottom: 0;
    height: 3px;
    border-radius: 3px 3px 0 0;
    background: var(--md-primary);
}

/* ---------------- tables ---------------- */

main.md .data th {
    font-size: 12px;
    font-weight: 500;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    background: var(--md-surface-low);
    border-bottom: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .data td {
    font-size: 14px;
    line-height: 20px;
    color: var(--md-on-surface);
    border-bottom: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .data tbody tr:hover td { background: var(--md-surface-low); }
main.md .data tbody tr:last-child td { border-bottom: none; }

/*
 * Row actions are text buttons, which is the M3 idiom for an action inside a
 * list row - and the only shape that fits three of them here. At Material's
 * button padding an outlined pill is 74px wide in a 110px column, so the three
 * wrapped into a vertical stack and the row went from 40px tall to 118px.
 */
main.md .data .btn.sm {
    padding: 4px 9px;
    font-size: 12.5px;
    background: transparent;
    color: var(--md-primary);
    border-color: transparent;
    box-shadow: none;
}
main.md .data .btn.sm:hover { background: transparent; box-shadow: none; }
main.md .data .btn.sm.danger { color: var(--md-error); }
main.md .data .btn-row { gap: 2px; }

main.md .toolbar {
    background: var(--md-surface-low);
    border-bottom: 1px solid var(--md-outline-variant);
    gap: var(--md-sp-2);
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .pager {
    border-top: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
    font-size: 14px;
    color: var(--md-on-surface-variant);
}

/* ---------------- chips ---------------- */

main.md .badge, main.md .pill {
    border-radius: var(--md-r-sm);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: .5px;
    padding: 3px 8px;
    border: 1px solid var(--md-outline-variant);
    background: var(--md-surface-low);
    color: var(--md-on-surface-variant);
}
main.md .badge.green { background: var(--md-success-container); color: var(--md-on-success-container); border-color: transparent; }
main.md .badge.amber { background: var(--md-tertiary-container); color: var(--md-on-tertiary-container); border-color: transparent; }
main.md .badge.red   { background: var(--md-error-container);   color: var(--md-on-error-container);   border-color: transparent; }
main.md .badge.grey  { background: var(--md-surface-high);      color: var(--md-on-surface-variant);   border-color: transparent; }
main.md .badge.solid { background: var(--md-primary);           color: var(--md-on-primary);           border-color: transparent; }
main.md .chip-row { gap: var(--md-sp-2); }

/* ---------------- notes as M3 banners ---------------- */
/* Tonal container plus a matching leading edge. The edge is kept because these
   notes carry real warnings and the colour alone is easy to skim past. */

main.md .note {
    border: none;
    border-left: 4px solid var(--md-primary);
    border-radius: var(--md-r-xs);
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    font-size: 14px;
    line-height: 20px;
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .note.warn {
    background: var(--md-tertiary-container);
    border-left-color: var(--md-tertiary);
    color: var(--md-on-tertiary-container);
}
main.md .note.danger {
    background: var(--md-error-container);
    border-left-color: var(--md-error);
    color: var(--md-on-error-container);
}
main.md .note.good {
    background: var(--md-success-container);
    border-left-color: var(--md-success);
    color: var(--md-on-success-container);
}
main.md .note strong { font-weight: 500; }
main.md .note code {
    background: rgba(255,255,255,.6);
    border-radius: var(--md-r-xs);
    font-size: 12.5px;
}

/* ---------------- dialogs ---------------- */

main.md .modal-overlay > .panel,
.modal-overlay > .panel {
    border-radius: var(--md-r-xl);
    box-shadow: var(--md-elev-3);
    border: none;
}

/* ---------------- console ---------------- */
/* Left dark on purpose. It is a log, the one place a terminal surface is the
   right answer, and M3 has no role that says "machine output". */
main.md .console {
    border-radius: var(--md-r-sm);
    border: none;
}

/* --------------------------------------------------------------------------
   Material Design 3 - the components Scrape and Extract add
   --------------------------------------------------------------------------
   Same approach as the block above: restyle in place, change no markup. These
   are the pieces those two pages use that Sources did not.
   -------------------------------------------------------------------------- */

/* ---- disclosure sections (details.sec) ---- */
/* An M3 list item that opens. Filled rather than outlined, because these sit in
   a stack of three or four and a column of outlines reads as a table. */

main.md details.sec {
    background: var(--md-surface-low);
    border: none;
    border-radius: var(--md-r-sm);
    margin-bottom: var(--md-sp-2);
}
main.md details.sec > summary {
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .1px;
    text-transform: none;
    color: var(--md-on-surface-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
    border-radius: var(--md-r-sm);
}
main.md details.sec > summary:hover {
    background: var(--md-surface-mid);
    color: var(--md-on-surface);
}
main.md details.sec[open] > summary { color: var(--md-on-surface); }
main.md .sec-body { padding: 0 var(--md-sp-4) var(--md-sp-4); }
main.md .sec-note {
    font-size: 12px;
    letter-spacing: .4px;
    color: var(--md-on-surface-variant);
}

/* ---- the next-step banner ---- */
/* Tonal container with a filled marker, which is how M3 shows a step you are
   on. The old version was a white card with a coloured left edge, so the step
   number - the one thing that says where you are - was the quietest part of it. */

main.md .next-step {
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    border: none;
    border-left: 4px solid var(--md-primary);
    border-radius: var(--md-r-md);
    box-shadow: none;
    padding: var(--md-sp-4) var(--md-sp-6);
    margin-bottom: var(--md-sp-6);
    gap: var(--md-sp-4);
}
main.md .next-step .ns-n {
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-weight: 500;
}
main.md .next-step .ns-body h2 { font-size: 16px; font-weight: 500; color: inherit; }
main.md .next-step .ns-body p  { font-size: 14px; line-height: 20px; color: inherit; opacity: .85; }

main.md .next-step.is-done {
    background: var(--md-success-container);
    color: var(--md-on-success-container);
    border-left-color: var(--md-success);
}
main.md .next-step.is-done .ns-n { background: var(--md-success); color: #fff; }

/* ---- chips ---- */
/* M3 filter chips: outlined when off, filled with the secondary container when
   on, which is the pair M3 uses for a toggle you can see the state of. */

main.md .chip {
    border-radius: var(--md-r-sm);
    border: 1px solid var(--md-outline);
    background: transparent;
    color: var(--md-on-surface-variant);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .1px;
    padding: 5px 12px;
}
main.md .chip:hover { border-color: var(--md-primary); color: var(--md-primary); }
main.md .chip.on {
    background: var(--md-secondary-container);
    border-color: transparent;
    color: var(--md-on-secondary-container);
}

/* ---- key/value lists ---- */

main.md .kv { font-size: 14px; gap: var(--md-sp-2) var(--md-sp-4); }
main.md .kv dt { font-weight: 500; letter-spacing: .1px; color: var(--md-on-surface-variant); }
main.md .kv dd { color: var(--md-on-surface); }

/* ---- the threshold tuner ---- */

main.md .tuner-lead { font-size: 14px; line-height: 20px; color: var(--md-on-surface-variant); }
main.md .tuner label {
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    color: var(--md-on-surface-variant);
}
main.md .tuner input[type=range] { accent-color: var(--md-primary); }
main.md .tuner output {
    font-family: var(--md-font);
    font-size: 20px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--md-primary);
}

/* ---- the advanced tool cards ---- */

main.md .tool {
    background: var(--md-surface-low);
    border: none;
    border-radius: var(--md-r-md);
    padding: var(--md-sp-4);
}
main.md .tool h4 {
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    color: var(--md-on-surface);
}
main.md .tool p {
    font-size: 13px;
    line-height: 18px;
    color: var(--md-on-surface-variant);
}

/* ---- a tip along the bottom of a card ---- */

main.md .panel-tip {
    background: var(--md-tertiary-container);
    color: var(--md-on-tertiary-container);
    border-top: none;
    border-radius: 0 0 var(--md-r-md) var(--md-r-md);
    font-size: 13px;
    line-height: 18px;
    padding: var(--md-sp-3) var(--md-sp-6);
}
main.md .panel-tip strong { color: inherit; font-weight: 500; }

/* ---- run log lines ---- */

main.md .run-line {
    font-size: 14px;
    line-height: 20px;
    color: var(--md-on-surface);
    border-color: var(--md-outline-variant);
}
main.md .run-line.sub { font-size: 12px; letter-spacing: .4px; color: var(--md-on-surface-variant); }
main.md .run-line strong { color: var(--md-on-surface); font-weight: 500; }
main.md .run-line .bad, main.md .run-line .bad strong { color: var(--md-error); }

main.md .run-alt {
    background: var(--md-surface-low);
    border: none;
    border-radius: var(--md-r-sm);
    color: var(--md-on-surface-variant);
    font-size: 13px;
}

/* ---- the setup guide ---- */

main.md .setup {
    background: var(--md-surface-low);
    border: none;
    border-radius: var(--md-r-md);
}
main.md .setup-title {
    font-size: 14px;
    font-weight: 500;
    letter-spacing: .1px;
    color: var(--md-on-surface);
}
main.md .setup-steps { font-size: 14px; line-height: 22px; color: var(--md-on-surface-variant); }
main.md .setup-note {
    font-size: 13px;
    line-height: 18px;
    color: var(--md-on-surface-variant);
}
main.md .setup-note code, main.md .bin-row code {
    background: var(--md-surface-high);
    border-radius: var(--md-r-xs);
    font-size: 12.5px;
}

/* ---- the hero stat ---- */

main.md .stat.hero .value { font-size: 40px; line-height: 48px; font-weight: 400; }

/* ---- dialog footer ---- */

main.md .modal-foot,
.modal-overlay .modal-foot {
    border-top: 1px solid var(--md-outline-variant);
    background: var(--md-surface-low);
    padding: var(--md-sp-3) var(--md-sp-6);
    gap: var(--md-sp-2);
}
main.md .modal-foot-note,
.modal-overlay .modal-foot-note {
    font-size: 13px;
    font-weight: 500;
    color: var(--md-tertiary);
}

/* ---- the dictionary add row ---- */
/* Its inputs are styled separately from the ordinary field, so they need the
   same outlined treatment or they stay visibly from the old design. */

main.md .dict-add { gap: var(--md-sp-2); }
main.md .dict-add input {
    border: 1px solid var(--md-outline);
    border-radius: var(--md-r-xs);
    font-family: var(--md-font);
    font-size: 14px;
    padding: 9px 12px;
}
main.md .dict-add input:focus {
    outline: none;
    border-color: var(--md-primary);
    box-shadow: inset 0 0 0 1px var(--md-primary);
}

/* ---- the source typeahead ---- */
/* An M3 menu: elevated, no border, rounded, with a hover state layer. */

main.md .typeahead {
    background: var(--md-surface-lowest);
    border: none;
    border-radius: var(--md-r-sm);
    box-shadow: var(--md-elev-2);
}
main.md .typeahead .ta-row {
    border-bottom: 1px solid var(--md-outline-variant);
    padding: var(--md-sp-3) var(--md-sp-4);
}
main.md .typeahead .ta-row:hover { background: var(--md-surface-low); }
main.md .typeahead .ta-name { font-size: 14px; font-weight: 500; color: var(--md-on-surface); }
main.md .typeahead .ta-name em { color: var(--md-on-surface-variant); }
main.md .typeahead .ta-url {
    font-size: 12px;
    color: var(--md-on-surface-variant);
}
main.md .typeahead .ta-empty {
    font-size: 14px;
    color: var(--md-on-surface-variant);
    padding: var(--md-sp-4);
}
