:root {
	--bg: #f2f2f2;
	--panel: #ffffff;
	--topbar: #ffffff;
	--fg: #1a1a1a;
	--accent: #d50000;
	--grid-line: rgba(0, 0, 0, 0.08);
	--grid-size: 0.75in;
}

:root[data-theme="dark"] {
	--bg: #121212;
	--panel: #1e1e1e;
	--topbar: #191919;
	--fg: #eaeaea;
	--grid-line: rgba(190, 190, 190, 0.16);
}

* {
	box-sizing: border-box;
}

.hidden {
	display: none !important;
}

body {
	margin: 0;
	min-height: 100vh;
	background-color: var(--bg);
	background-image:
		linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
		linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
	background-size: var(--grid-size) var(--grid-size);
	color: var(--fg);
	font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.topbar {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	padding: 0.75rem 1.25rem;
	background: var(--topbar);
	border-bottom: 1px solid var(--accent);
}

.brand {
	display: flex;
	align-items: center;
	font-size: 1.5rem;
	font-weight: 700;
	color: var(--accent);
	text-decoration: none;
	justify-self: start;
}

/* Logo mark sitting to the left of the brand text. A background-image on
   an empty span (rather than an <img>) keeps it purely decorative -- it's
   aria-hidden, since the adjacent "QA Portal" text already names the link. */
.brand-logo {
	display: inline-block;
	height: 1.75rem;
	width: 1.75rem;
	margin-right: 0.5rem;
	background-image: url("/img/logo.png");
	background-size: contain;
	background-repeat: no-repeat;
	background-position: center;
	flex-shrink: 0;
}

.topbar-center {
	justify-self: center;
}

.topbar-nav {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	justify-self: end;
}

.icon-btn {
	margin-left: auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	background: none;
	border: 1px solid var(--accent);
	border-radius: 50%;
	color: var(--fg);
	font-size: 1.3rem;
	line-height: 1;
	padding: 0;
	cursor: pointer;
	text-decoration: none;
}

.icon-btn:hover {
	color: var(--accent);
	background: rgba(213, 0, 0, 0.12);
}

main {
	display: flex;
	justify-content: center;
	align-items: center;
	min-height: calc(100vh - 58px);
	padding: 2rem 1rem;
}

.card {
	width: fit-content;
	max-width: 90vw;
	background: var(--panel);
	border: 1px solid var(--accent);
	border-radius: 8px;
	padding: 1.5rem 2rem;
	box-shadow: 0 4px 18px rgba(0, 0, 0, 0.2);
}

.card h1 {
	margin: 0 0 1rem 0;
	text-align: left;
	color: var(--fg);
}

.card hr {
	border: none;
	border-top: 1px solid var(--accent);
	margin: 1rem 0;
}

.card p {
	line-height: 1.5;
}

.form-group {
	margin-bottom: 1rem;
	text-align: left;
}

.form-group label {
	display: block;
	margin-bottom: 0.35rem;
	font-size: 0.9rem;
	color: var(--fg);
	opacity: 0.85;
}

.password-field {
	position: relative;
}

.password-field .form-input {
	padding-right: 2.4rem;
}

.password-toggle-btn {
	position: absolute;
	right: 0.4rem;
	top: 50%;
	transform: translateY(-50%);
	background: none;
	border: none;
	color: var(--fg);
	opacity: 0.6;
	cursor: pointer;
	padding: 0.25rem;
	font-size: 1rem;
}

.password-toggle-btn:hover {
	opacity: 1;
	color: var(--accent);
}

.form-input {
	width: 100%;
	padding: 0.5rem 0.65rem;
	background: var(--bg);
	color: var(--fg);
	border: 1px solid var(--accent);
	border-radius: 4px;
	font-size: 1rem;
}

.form-input:focus {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

.btn {
	display: inline-block;
	padding: 0.55rem 1.25rem;
	background: var(--accent);
	color: #fff;
	border: none;
	border-radius: 4px;
	cursor: pointer;
	font-size: 0.95rem;
	text-decoration: none;
	text-align: center;
}

.btn:hover {
	filter: brightness(1.15);
}

.btn-block {
	display: block;
	width: 100%;
}

.btn-secondary {
	background: transparent;
	border: 1px solid var(--accent);
	color: var(--accent);
}

.btn:disabled {
	opacity: 0.4;
	cursor: not-allowed;
	filter: none;
}

.btn-row {
	display: flex;
	gap: 0.5rem;
	align-items: center;
}

.message {
	padding: 0.65rem 0.9rem;
	border-radius: 4px;
	margin-bottom: 1rem;
	font-size: 0.9rem;
}

.message-error {
	background: rgba(213, 0, 0, 0.15);
	border: 1px solid var(--accent);
	color: var(--fg);
}

.message-success {
	background: rgba(46, 204, 64, 0.15);
	border: 1px solid #2ecc40;
	color: var(--fg);
}

.form-footer {
	margin-top: 1rem;
	font-size: 0.9rem;
	text-align: center;
	color: var(--fg);
	opacity: 0.85;
}

.form-footer a {
	color: var(--accent);
}

.auth-card {
	width: 100%;
	max-width: 380px;
}

/* Home grid: 4 wide x 3 high tiles. A real, wired-up tile ("Wire Testing"
   today) gets a solid border; everything else is a dashed placeholder for
   a future button -- same visual distinction as the tile's own
   .index-tile-placeholder modifier below. */
.index-grid {
	display: grid;
	grid-template-columns: repeat(4, 170px);
	grid-auto-rows: 170px;
	gap: 1.5rem;
}

.index-tile {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.6rem;
	background: var(--panel);
	border: 1px solid var(--accent);
	border-radius: 10px;
	color: var(--fg);
	font-size: 0.95rem;
	text-decoration: none;
	cursor: pointer;
}

.index-tile:hover {
	filter: brightness(1.05);
}

.index-tile-icon {
	font-size: 1.8rem;
	color: var(--accent);
}

.index-tile-placeholder {
	border-style: dashed;
	opacity: 0.45;
	cursor: default;
	pointer-events: none;
}

/* -- Admin panel ------------------------------------------------------ */

.stack {
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
	align-items: stretch;
	width: min(1100px, 95vw);
}

.admin-card {
	width: 100%;
}

/* Lets a wide table scroll horizontally on narrow screens instead of
   forcing the whole card wider than the viewport. */
.table-scroll {
	overflow-x: auto;
}

.admin-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.9rem;
}

.admin-table th,
.admin-table td {
	padding: 0.5rem 0.6rem;
	text-align: left;
	border-bottom: 1px solid var(--grid-line);
	vertical-align: middle;
	white-space: nowrap;
}

.admin-table th {
	font-weight: 600;
	opacity: 0.8;
	border-bottom: 1px solid var(--accent);
}

.admin-table tfoot td {
	border-bottom: none;
	padding-top: 0.9rem;
}

.admin-table .form-input {
	font-size: 0.9rem;
	padding: 0.35rem 0.5rem;
}

.empty-state {
	text-align: center;
	opacity: 0.6;
	padding: 1.5rem 0;
}

/* -- Modal ------------------------------------------------------------ */

.modal-overlay {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.55);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1rem;
	z-index: 50;
}

.modal {
	position: relative;
	background: var(--panel);
	border: 1px solid var(--accent);
	border-radius: 8px;
	padding: 1.5rem 2rem;
	width: 100%;
	max-width: 560px;
	box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
}

.modal h2 {
	margin: 0 0 1rem 0;
}

.modal-icon-corner {
	position: absolute;
	top: 0.75rem;
	right: 0.75rem;
}

.icon-btn-sm {
	width: 1.9rem;
	height: 1.9rem;
	font-size: 0.95rem;
	margin-left: 0;
}

/* ===================================================================
   Wire Test Reports (Wire_Test_Reports.php)
   -------------------------------------------------------------------
   Ported from the standalone offline Wire Test Report HTML. EVERY rule
   below is scoped under .wire-test-app on purpose: the original defines
   .card, .btn, .modal, .hidden, .badge and .toolbar, all of which
   already exist in this stylesheet with different styling. Unscoped,
   importing it would silently restyle index.php and admin.php.

   The palette is remapped rather than rewritten -- the original is
   fully CSS-variable driven, so pointing --ink/--brand at the portal's
   --fg/--accent retints the whole thing. --panel and --bg are
   deliberately NOT redefined here so they inherit the portal's own
   values and keep following the light/dark toggle. Pass/fail/review
   colours are kept as-is: they carry meaning, not branding.
   =================================================================== */

.wire-test-app{
	--ink: var(--fg);
	--muted:#6b7280;
	--line:#dcdcdc;
	--brand: var(--accent);
	--brand2:#b00000;
	--input:#fff;
	--pass:#176b3b; --passbg:#e8f6ee;
	--fail:#a62525; --failbg:#fdeaea;
	--review:#955700; --reviewbg:#fff3d5;
	--screen:#4c3f87; --screenbg:#f0edff;
	--shadow:0 4px 18px rgba(0,0,0,.10);
}

/* Keeps the ported greys/borders legible if someone flips the portal's
   dark toggle, without touching the status colours. */
:root[data-theme="dark"] .wire-test-app{
	--muted:#9aa5ad;
	--line:#3a3a3a;
	--input:#2a2a2a;
	--shadow:0 4px 18px rgba(0,0,0,.5);
}

/* The app lays itself out full width; the portal's default centring
   `main` (display:flex + align-items:center) would shrink-wrap it and
   collapse its two-column grid. Applied via a class on <main> rather than
   main:has(> .wire-test-app) so it does not depend on :has() support. */
.wire-test-main{
	display:block;
	padding:1rem;
	align-items:initial;
	justify-content:initial;
}

.wire-test-app *{box-sizing:border-box}
/* Background intentionally left transparent so the portal's own page
   backdrop shows between the cards -- the cards themselves are opaque
   via .card{background:var(--panel)} below. */
.wire-test-app{margin:0;font:14px/1.42 "Segoe UI",Arial,sans-serif;color:var(--ink);background:transparent}
.wire-test-app header{background:linear-gradient(135deg,var(--brand),#8a0000);color:#fff;padding:18px 22px;box-shadow:0 2px 12px rgba(0,0,0,.14)}
.wire-test-app .header-wrap{max-width:1440px;margin:auto;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.wire-test-app h1{font-size:24px;margin:0;letter-spacing:.2px}
.wire-test-app .sub{opacity:.85}
.wire-test-app .offline{margin-left:auto;background:rgba(255,255,255,.13);border:1px solid rgba(255,255,255,.22);padding:6px 10px;border-radius:999px;font-size:12px}
.wire-test-app .app{max-width:1440px;margin:16px auto 28px;padding:0 14px}
.wire-test-app .tabs{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:10px}
.wire-test-app .tab{border:1px solid var(--line);background:#f8fafb;padding:9px 15px;border-radius:9px 9px 0 0;cursor:pointer;font-weight:600;color:#49616d}
.wire-test-app .tab.active{background:#fff;color:var(--brand);border-bottom-color:#fff}
.wire-test-app .page{display:none}
.wire-test-app .page.active{display:block}
.wire-test-app .grid{display:grid;grid-template-columns:minmax(360px, .92fr) minmax(520px,1.35fr);gap:14px}
@media(max-width:980px){.wire-test-app .grid{grid-template-columns:1fr}
.wire-test-app .offline{margin-left:0}}
.wire-test-app .card{background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);padding:14px;margin-bottom:14px}
.wire-test-app .card h2{font-size:15px;margin:-2px 0 12px;color:var(--brand);letter-spacing:.2px}
.wire-test-app .card h3{font-size:13px;margin:8px 0;color:#435965}
.wire-test-app .form-grid{display:grid;grid-template-columns:190px 1fr;gap:8px 10px;align-items:center}
.wire-test-app .form-grid label{font-weight:600;color:#405460}
.wire-test-app .input,.wire-test-app select,.wire-test-app textarea{width:100%;border:1px solid #b9c7ce;border-radius:7px;padding:8px 9px;font:inherit;background:var(--input);color:var(--ink);outline:none}
.wire-test-app .input:focus,.wire-test-app select:focus,.wire-test-app textarea:focus{border-color:var(--brand2);box-shadow:0 0 0 3px rgba(10,113,128,.12)}
.wire-test-app textarea{min-height:92px;resize:vertical}
.wire-test-app .small{font-size:12px;color:var(--muted)}
.wire-test-app .btnrow{display:flex;gap:8px;flex-wrap:wrap}
.wire-test-app .btn{border:1px solid #a8bbc3;background:#fff;border-radius:7px;padding:8px 11px;font:600 13px inherit;cursor:pointer;color:#304853}
.wire-test-app .btn:hover{background:#f3f7f8}
.wire-test-app .btn.primary{background:var(--brand2);border-color:var(--brand2);color:#fff}
.wire-test-app .btn.danger{color:#9b2525;border-color:#e3b6b6}
.wire-test-app .btn.ghost{background:transparent}
.wire-test-app .file-button input{display:none}
.wire-test-app .detail-grid,.wire-test-app .metric-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px 14px}
.wire-test-app .kv{display:flex;gap:7px;min-width:0}
.wire-test-app .kv span:first-child{color:var(--muted);white-space:nowrap}
.wire-test-app .kv strong{overflow-wrap:anywhere}
.wire-test-app .resultbox{border-left:6px solid #8da1aa;padding:12px 14px;background:#f7fafb;border-radius:8px;margin-bottom:10px}
.wire-test-app .result-main{font-size:24px;font-weight:800;letter-spacing:.3px}
.wire-test-app .resultbox.pass{border-color:var(--pass);background:var(--passbg)}
.wire-test-app .resultbox.pass .result-main{color:var(--pass)}
.wire-test-app .resultbox.fail{border-color:var(--fail);background:var(--failbg)}
.wire-test-app .resultbox.fail .result-main{color:var(--fail)}
.wire-test-app .resultbox.review{border-color:var(--review);background:var(--reviewbg)}
.wire-test-app .resultbox.review .result-main{color:var(--review)}
.wire-test-app .resultbox.screen{border-color:var(--screen);background:var(--screenbg)}
.wire-test-app .resultbox.screen .result-main{color:var(--screen)}
.wire-test-app .result-grid{display:grid;grid-template-columns:150px 1fr 160px 1fr;gap:6px 10px}
.wire-test-app .result-grid .lab{color:var(--muted)}
@media(max-width:650px){.wire-test-app .form-grid{grid-template-columns:1fr}
.wire-test-app .result-grid{grid-template-columns:130px 1fr}
.wire-test-app .detail-grid,.wire-test-app .metric-grid{grid-template-columns:1fr}}
.wire-test-app .upload{border:2px dashed #b7c9cf;border-radius:10px;padding:13px;background:#f9fbfc}
.wire-test-app .upload.drag{border-color:var(--brand2);background:#eefbfc}
.wire-test-app .upload-title{font-weight:700;margin-bottom:7px}
.wire-test-app .pastebox{min-height:84px;background:#fff}
.wire-test-app .status{margin-top:8px;padding:7px 9px;border-radius:6px;background:#eef4f6;color:#435965;font-size:12px}
.wire-test-app .status.warn{background:#fff0d7;color:#8a5200}
.wire-test-app canvas{width:100%;height:300px;border:1px solid #dce4e8;border-radius:8px;background:#fff;display:block}
.wire-test-app .table-wrap{overflow:auto;border:1px solid var(--line);border-radius:9px;background:#fff}
.wire-test-app table{border-collapse:collapse;width:100%;min-width:900px}
.wire-test-app th{position:sticky;top:0;background:#b00000;color:#fff;text-align:left;font-size:12px;padding:8px;border-right:1px solid rgba(255,255,255,.13);z-index:1}
.wire-test-app td{padding:7px 8px;border-bottom:1px solid #e5ecef;font-size:12px;vertical-align:top}
.wire-test-app tr:hover td{background:#f5fafb}
.wire-test-app tr.selected td{background:#e5f4f6}
.wire-test-app .pct.pass{background:#dff3e7;color:#145e34;font-weight:700}
.wire-test-app .pct.fail{background:#fce2e2;color:#962525;font-weight:700}
.wire-test-app .toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px}
.wire-test-app .toolbar .search{max-width:360px;background:#fff}
.wire-test-app .spacer{flex:1}
.wire-test-app .notice{background:#fff7dd;border:1px solid #edd799;border-radius:9px;padding:10px 12px;color:#695214;margin-bottom:12px}
.wire-test-app .oknotice{background:#eaf7ef;border-color:#b7dcc6;color:#245a39}
.wire-test-app .mutedbox{background:#f5f8f9;border:1px solid var(--line);border-radius:8px;padding:10px}
.wire-test-app .right{margin-left:auto}
.wire-test-app .hidden{display:none!important}
.wire-test-app .badge{display:inline-block;border-radius:999px;padding:2px 7px;font-size:11px;font-weight:700;background:#e8eef0;color:#4a5e66}
.wire-test-app .badge.pass{background:var(--passbg);color:var(--pass)}
.wire-test-app .badge.fail{background:var(--failbg);color:var(--fail)}
.wire-test-app .badge.review{background:var(--reviewbg);color:var(--review)}
.wire-test-app .modal{position:fixed;inset:0;background:rgba(0,0,0,.36);display:none;align-items:center;justify-content:center;padding:20px;z-index:20}
.wire-test-app .modal.open{display:flex}
.wire-test-app .modal-card{background:#fff;max-width:760px;width:100%;max-height:86vh;overflow:auto;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.25);padding:18px}
.wire-test-app .modal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.wire-test-app .modal-head h2{margin:0;color:var(--brand)}
.wire-test-app .footer-note{color:#71838c;font-size:11px;text-align:center;margin:15px 0 0}
.wire-test-app .compare-toolbar{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;margin-bottom:12px}
.wire-test-app .compare-toolbar .field{display:flex;flex-direction:column;gap:4px;min-width:180px}
.wire-test-app .compare-toolbar label{font-size:12px;font-weight:700;color:#45606c}
.wire-test-app .compare-toolbar .btn{height:37px}
.wire-test-app .compare-stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:12px}
.wire-test-app .compare-stat{border:1px solid var(--line);border-radius:11px;background:linear-gradient(180deg,#f8fbfc,#fff);padding:10px 12px}
.wire-test-app .compare-stat .k{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.wire-test-app .compare-stat .v{font-size:22px;font-weight:800;color:var(--brand);margin-top:2px}
.wire-test-app .compare-note{margin-bottom:12px}
.wire-test-app .compare-groups{display:grid;gap:12px}
.wire-test-app .compare-empty{padding:18px;border:1px dashed #bfd0d6;border-radius:10px;background:#f9fbfc;color:#5d727d}
.wire-test-app .compare-group{background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);overflow:hidden}
.wire-test-app .compare-head{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;padding:12px 14px;background:linear-gradient(180deg,#f8fbfc,#eef6f8);border-bottom:1px solid var(--line)}
.wire-test-app .compare-title{font-size:16px;font-weight:800;color:var(--brand)}
.wire-test-app .compare-sub{font-size:12px;color:var(--muted);margin-top:2px}
.wire-test-app .compare-chips{display:flex;gap:6px;flex-wrap:wrap;align-content:flex-start}
.wire-test-app .compare-chip{display:inline-block;padding:4px 8px;border-radius:999px;border:1px solid #d9e5ea;background:#eef5f7;color:#35505d;font-size:11px;font-weight:700}
.wire-test-app .compare-group .table-wrap{border:0;border-radius:0}
.wire-test-app .compare-group table{min-width:980px}
.wire-test-app .compare-group th{background:#b00000}
.wire-test-app .leadcell{background:#eaf7ef!important;color:#1a6b3c;font-weight:800}
.wire-test-app .metric-sub{display:block;font-size:10px;color:#6f8088;margin-top:2px}
.wire-test-app .leader-badge{display:inline-block;margin-left:6px;padding:2px 6px;border-radius:999px;background:#dff3e7;color:#155f33;font-size:10px;font-weight:800}
.wire-test-app .delta.good{color:#1a6b3c;font-weight:700}
.wire-test-app .delta.bad{color:#8e3e00;font-weight:700}
.wire-test-app .passrate.good{color:#176b3b;font-weight:800}
.wire-test-app .passrate.mid{color:#8c5e00;font-weight:800}
.wire-test-app .passrate.low{color:#a62525;font-weight:800}
@media(max-width:980px){.wire-test-app .compare-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
.wire-test-app .compare-toolbar .field{min-width:140px}}
@media(max-width:650px){.wire-test-app .compare-stats{grid-template-columns:1fr}}
@media print{.wire-test-app header,.wire-test-app .tabs,.wire-test-app .no-print{display:none!important}
.wire-test-app .app{max-width:none;margin:0;padding:0}
.wire-test-app .card{box-shadow:none;border:0}
.wire-test-app .page{display:block!important}
.wire-test-app .page:not(.print-active){display:none!important}}
/* NOTE: the source HTML contains a second <style> block, but it is a
   template string inside the JavaScript that printRecord() uses to build
   its separate print/PDF window -- not a page stylesheet. It must NOT be
   imported here: its `.grid{grid-template-columns:180px 1fr}` overrides
   the real two-column layout and collapses the left column. It still
   lives, correctly, inside js/Wire_Test_Reports.js. */

/* -------------------------------------------------------------------
   Wire Test Reports -- portal-side adjustments layered ON TOP of the
   ported rules above. Kept separate so the ported block stays a faithful
   copy of the original and every deliberate change is visible here.
   ------------------------------------------------------------------- */

/* Navigation: index-page-style tiles instead of the original tab strip. */
.wire-test-app .wt-nav{
	display:grid;
	grid-template-columns:repeat(4,1fr);
	gap:.6rem;
	margin-bottom:.6rem;
}

.wire-test-app .wt-tile{
	display:flex;
	flex-direction:column;
	align-items:center;
	justify-content:center;
	gap:.35rem;
	padding:.7rem .5rem;
	background:var(--panel);
	border:1px solid var(--accent);
	border-radius:10px;
	color:var(--fg);
	font:600 13px/1.2 inherit;
	cursor:pointer;
}

.wire-test-app .wt-tile i{font-size:1.35rem;color:var(--accent)}
.wire-test-app .wt-tile:hover{filter:brightness(1.04)}
.wire-test-app .wt-tile.active{background:var(--accent);color:#fff}
.wire-test-app .wt-tile.active i{color:#fff}

@media(max-width:650px){
	.wire-test-app .wt-nav{grid-template-columns:repeat(2,1fr)}
}

/* Tighter spacing -- the original's 14-16px gaps left the layout looking
   loose once it sat inside the portal shell. */
.wire-test-app .app{max-width:none;margin:0;padding:0}
.wire-test-app .card{padding:11px 12px;margin-bottom:.6rem}
.wire-test-app .grid{gap:.6rem}
.wire-test-app .card h2{margin:-1px 0 9px}

/* Sortable Wire Specs headers. */
.wire-test-app th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
.wire-test-app th.sortable:hover{filter:brightness(1.15)}
.wire-test-app th.sortable::after{content:"\2195";opacity:.35;margin-left:5px;font-size:10px}
.wire-test-app th.sortable.sort-asc::after{content:"\2191";opacity:1}
.wire-test-app th.sortable.sort-desc::after{content:"\2193";opacity:1}

/* -- Printable report ------------------------------------------------
   Two columns of label/value pairs so a full report fits one page. */
.wt-report{color:#17242c;font:11px/1.34 "Segoe UI",Arial,sans-serif}
.wt-report h1{font-size:16px;margin:0 0 4px;color:var(--accent);border-bottom:2px solid var(--accent);padding-bottom:5px}
.wt-report h3{font-size:12px;margin:10px 0 4px;color:var(--accent)}
.wt-report .meta{margin:0 0 8px;font-size:10px;color:#667783}
.wt-report .grid2{display:grid;grid-template-columns:118px 1fr 118px 1fr;gap:2px 9px;align-items:baseline}
.wt-report .lab{color:#64757e}
.wt-report .big{font-size:14px;font-weight:800}
.wt-report table{width:100%;border-collapse:collapse;font-size:10px}
.wt-report th{background:none;color:#17242c;text-align:left;padding:4px 5px;border-bottom:2px solid var(--accent);position:static}
.wt-report td{padding:3px 5px;border-bottom:1px solid #d9e3e7}
.wt-report .note{margin-top:9px;padding:7px 8px;border:1px solid #dfcf96;background:#fff8df;font-size:10px}

@media(max-width:650px){
	.wt-report .grid2{grid-template-columns:110px 1fr}
}

#wt-report-modal .modal-card{max-width:900px}

/* Print: emit ONLY the report. The visibility trick (rather than
   display:none on siblings) keeps the report's own ancestors laid out,
   which is what allows it to reposition to the top of the sheet. */
@media print{
	body *{visibility:hidden}
	#wt-report-modal, #wt-report-modal *{visibility:visible}
	#wt-report-modal{position:absolute;inset:0 auto auto 0;width:100%;padding:0;background:#fff;display:block!important}
	#wt-report-modal .modal-card{max-width:none;width:100%;max-height:none;overflow:visible;box-shadow:none;border:0;border-radius:0;padding:0}
	#wt-report-modal .no-print{display:none!important}
	.wt-report .note{background:none}
	@page{size:letter portrait;margin:12mm}
}

/* The portal's own global `.modal` (a centred dialog box) also matches the
   ported overlays, because the ported markup reuses that class name for a
   full-screen backdrop. The scoped rule above wins on the properties both
   set, but the portal's max-width/border/shadow are not overridden by it
   and would cap the backdrop at 560px with a stray border. Reset them.
   This applies to #detailModal too, which had the same latent problem. */
.wire-test-app .modal{
	max-width:none;
	width:auto;
	border:0;
	border-radius:0;
	box-shadow:none;
}

/* -------------------------------------------------------------------
   Wire Test Reports -- v2 interface.
   Sections now live in modals launched from an index-style tile grid,
   and the many separately-bordered cards are flattened into one
   continuous surface. Everything here intentionally overrides the
   ported rules earlier in this file.
   ------------------------------------------------------------------- */

/* Launch grid: same tiles as the home screen. */
.wire-test-app .wt-launch{
	justify-content:center;
	margin:0 auto;
	width:fit-content;
	max-width:100%;
}

.wire-test-app .wt-launch-tile{
	font:inherit;
	font-size:.95rem;
	gap:.6rem;
}

/* Comfortable breathing room down both sides of the page. */
.wire-test-main{padding:1.75rem clamp(1rem,4vw,3rem)}

/* Section modals -------------------------------------------------- */
.wire-test-app .wt-section-modal .modal-card{
	width:min(1280px,94vw);
	max-height:90vh;
	overflow:auto;
	padding:0;
	background:var(--panel);
	border-radius:12px;
}

.wire-test-app .wt-section-modal .modal-head{
	position:sticky;
	top:0;
	z-index:2;
	display:flex;
	align-items:center;
	justify-content:space-between;
	gap:1rem;
	margin:0;
	padding:.85rem 1.15rem;
	background:var(--panel);
	border-bottom:1px solid var(--line);
}

.wire-test-app .wt-section-modal .modal-head h2{
	margin:0;
	font-size:1.05rem;
	font-weight:600;
	color:var(--fg);
}

.wire-test-app .wt-section-body{padding:1.15rem}

/* The sections were tab panes; inside a modal they are always shown. */
.wire-test-app .wt-section-modal .page{display:block!important}

/* One continuous surface ------------------------------------------
   The cards were individually bordered, shadowed panels, which is what
   made the page read as disconnected boxes. Flatten them: no border, no
   shadow, no panel fill -- just spacing and a light rule between. */
.wire-test-app .wt-section-body .card{
	background:none;
	border:0;
	border-radius:0;
	box-shadow:none;
	padding:0 0 .9rem;
	margin:0 0 .9rem;
	border-bottom:1px solid var(--line);
}

.wire-test-app .wt-section-body .card:last-child{
	border-bottom:0;
	margin-bottom:0;
	padding-bottom:0;
}

/* Headings: quieter. They were all-caps-weight accent red, which is what
   made the interface read as "too bold". */
.wire-test-app .wt-section-body .card h2{
	font-size:.8rem;
	font-weight:600;
	letter-spacing:.04em;
	text-transform:uppercase;
	color:var(--muted);
	margin:0 0 .7rem;
}

.wire-test-app .wt-section-body .card h3{
	font-size:.78rem;
	font-weight:600;
	color:var(--muted);
}

/* Inputs: neutral rather than the original cream-on-teal. */
.wire-test-app .input,
.wire-test-app select,
.wire-test-app textarea{
	background:var(--panel);
	border:1px solid var(--line);
	border-radius:6px;
}

.wire-test-app .input:focus,
.wire-test-app select:focus,
.wire-test-app textarea:focus{
	border-color:var(--accent);
	box-shadow:0 0 0 3px rgba(213,0,0,.10);
}

/* Buttons: only the primary action carries the accent fill. */
.wire-test-app .btn{
	background:var(--panel);
	border:1px solid var(--line);
	border-radius:6px;
	color:var(--fg);
	font-weight:500;
}

.wire-test-app .btn:hover{border-color:var(--accent);color:var(--accent);background:var(--panel)}
.wire-test-app .btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.wire-test-app .btn.primary:hover{color:#fff;filter:brightness(1.08)}

/* Tables: lighter header, no heavy fill. */
.wire-test-app .table-wrap{border-color:var(--line)}
.wire-test-app th{
	background:var(--bg);
	color:var(--muted);
	font-weight:600;
	border-right:0;
	border-bottom:1px solid var(--line);
}
.wire-test-app td{border-bottom:1px solid var(--line)}

/* Result banner: keep the semantic colour, lose the slab of fill. */
.wire-test-app .resultbox{background:none;border-left-width:4px;padding:.5rem 0 .5rem .75rem}
.wire-test-app .result-main{font-size:1.25rem}

.wire-test-app .notice,
.wire-test-app .mutedbox,
.wire-test-app .status{background:var(--bg);border-color:var(--line);color:var(--muted)}

.wire-test-app .upload{border-color:var(--line);background:var(--bg)}

@media(max-width:900px){
	.wire-test-app .wt-section-modal .modal-card{width:96vw;max-height:94vh}
	.wire-test-app .wt-section-body{padding:.85rem}
}

/* -------------------------------------------------------------------
   Width fixes for the section modals.

   The ported .modal-card caps itself at max-width:760px. The v2 rule set
   `width` but not `max-width`, so the cap still won -- the modal stayed
   760px wide and its contents overflowed into a horizontal scrollbar.
   ------------------------------------------------------------------- */
.wire-test-app .wt-section-modal .modal-card{
	max-width:none;
	overflow-x:hidden;
}

/* Grid and flex children default to min-width:auto, so any wide
   descendant (a long <select> option, a min-width table) pushes its track
   past the container instead of shrinking. This is what actually produced
   the horizontal scrollbar; min-width:0 lets the tracks shrink. */
.wire-test-app .grid > *,
.wire-test-app .form-grid > *,
.wire-test-app .result-grid > *,
.wire-test-app .detail-grid > *,
.wire-test-app .metric-grid > *,
.wire-test-app .compare-stats > *{min-width:0}

/* Tables keep their own min-width but must scroll inside their wrapper
   rather than widening the modal. */
.wire-test-app .table-wrap{max-width:100%;overflow:auto}

/* Long values (construction strings, notes) wrap instead of forcing width. */
.wire-test-app .kv strong,
.wire-test-app .detail-grid strong,
.wire-test-app .result-grid strong{overflow-wrap:anywhere;min-width:0}

/* The label column was a hard 190px, which squeezed the control column on
   narrower modals and truncated the part-number select. */
.wire-test-app .form-grid{grid-template-columns:minmax(120px,180px) minmax(0,1fr)}
.wire-test-app .form-grid .input,
.wire-test-app .form-grid select,
.wire-test-app .form-grid textarea{width:100%;max-width:100%}

/* The part-number option text is long; let the select show as much as it
   can rather than clipping at a narrow intrinsic width. */
.wire-test-app #wire{min-width:0;width:100%;text-overflow:ellipsis}

/* -------------------------------------------------------------------
   Text containment.

   Inputs, help text and table cells were overflowing their containers:
   the ported rules set widths but never constrained long unbroken
   content, and form labels defaulted to nowrap inside a fixed track.
   ------------------------------------------------------------------- */

/* Labels wrap onto a second line rather than pushing the track wider. */
.wire-test-app .form-grid > label{
	overflow-wrap:anywhere;
	hyphens:auto;
	line-height:1.3;
	align-self:center;
}

/* Help text sits inside the card, never beyond it. */
.wire-test-app .small,
.wire-test-app .status,
.wire-test-app .notice,
.wire-test-app .upload-title,
.wire-test-app .footer-note{
	overflow-wrap:anywhere;
	max-width:100%;
}

/* Inputs honour the box model and shrink with their column. */
.wire-test-app .input,
.wire-test-app select,
.wire-test-app textarea{
	max-width:100%;
	min-width:0;
	box-sizing:border-box;
}

/* Selects clip with an ellipsis instead of widening the grid track;
   the full text is on the element's title attribute. */
.wire-test-app select{
	text-overflow:ellipsis;
	white-space:nowrap;
}

.wire-test-app .pastebox{resize:vertical;min-height:64px}

/* Table cells wrap. The ported rules left them at nowrap, which is what
   forced the wide horizontal scroll on Wire Specs. */
.wire-test-app td{overflow-wrap:anywhere}
.wire-test-app th{white-space:nowrap}

/* Keep the Construction column from dominating the specs table. */
.wire-test-app #specTable td:nth-child(5){max-width:22ch}
.wire-test-app #specTable{min-width:820px}

.wire-test-app .wt-spec-actions,
.wire-test-app .wt-spec-actions-col{width:1%;white-space:nowrap}
.wire-test-app .wt-spec-edit{padding:3px 9px;font-size:11px}

/* The edit modal is a plain form -- narrower than the section modals. */
#wt-spec-modal .modal-card{width:min(620px,94vw);max-width:none;max-height:90vh;overflow:auto;padding:0}
#wt-spec-modal .modal-head{
	display:flex;align-items:center;justify-content:space-between;
	gap:1rem;margin:0;padding:.85rem 1.15rem;border-bottom:1px solid var(--line);
}
#wt-spec-modal .modal-head h2{margin:0;font-size:1.05rem;font-weight:600;color:var(--fg)}
#wt-spec-modal .btnrow{margin-top:1rem}

/* ===================================================================
   Document Control (Document_Control.php)
   -------------------------------------------------------------------
   The register table follows the master's register-map look: the
   document number in monospace accent red, the revision as a mono badge.
   Everything is scoped under .doc-control / .dc-viewer.
   =================================================================== */

.doc-control-main {
	display: block;
	padding: 1.5rem 1rem;
}

.doc-control,
.doc-control-log {
	width: min(1200px, 100%);
	margin: 0 auto;
}

.doc-control-log {
	margin-top: 1.5rem;
}

.doc-card {
	width: 100%;
	max-width: none;
}

.doc-card h1 i {
	color: var(--accent);
	margin-right: 0.35rem;
}

.dc-toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
}

.dc-toolbar h1 {
	margin: 0;
}

.dc-search {
	width: min(24rem, 100%);
}

.dc-drop {
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: 1.25rem 1.5rem;
	border: 2px dashed var(--accent);
	border-radius: 10px;
	cursor: pointer;
	background: rgba(213, 0, 0, 0.03);
}

.dc-drop:hover,
.dc-drop.dc-over {
	background: rgba(213, 0, 0, 0.1);
}

.dc-drop.dc-busy {
	opacity: 0.6;
	pointer-events: none;
}

.dc-drop-icon {
	font-size: 2.4rem;
	color: var(--accent);
	flex-shrink: 0;
}

.dc-drop-text {
	font-size: 0.9rem;
	line-height: 1.5;
}

.dc-drop-text code {
	font-family: monospace;
	color: var(--accent);
}

.dc-sample {
	display: inline-block;
	margin-top: 0.4rem;
	color: var(--accent);
	font-weight: 600;
	text-decoration: none;
}

.dc-sample:hover {
	text-decoration: underline;
}

.dc-message {
	margin-top: 0.75rem;
	padding: 0.6rem 0.9rem;
	border-radius: 6px;
	font-size: 0.9rem;
	white-space: pre-wrap;
	border: 1px solid var(--grid-line);
}

.dc-message.error { border-color: #c62828; color: #c62828; }
.dc-message.success { border-color: #2e7d32; color: #2e7d32; }
.dc-message.warn { border-color: #ef6c00; color: #ef6c00; }
.dc-message.busy { opacity: 0.8; }

.dc-table .dc-row {
	cursor: pointer;
}

.dc-table .dc-row:hover {
	background: rgba(213, 0, 0, 0.06);
}

.dc-number {
	font-family: monospace;
	font-weight: 700;
	color: var(--accent);
}

.dc-rev {
	font-family: monospace;
	font-weight: 700;
}

.dc-when {
	opacity: 0.75;
	font-size: 0.85rem;
}

.dc-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	padding: 0.15rem 0.55rem;
	border-radius: 999px;
	font-size: 0.8rem;
	font-weight: 600;
	white-space: nowrap;
}

.dc-draft { background: rgba(239, 108, 0, 0.15); color: #ef6c00; }
.dc-approved { background: rgba(46, 125, 50, 0.15); color: #2e7d32; }
.dc-none { opacity: 0.6; }

.dc-event {
	font-weight: 600;
	white-space: nowrap;
}

.dc-event-approved { color: #2e7d32; }
.dc-event-un-approved, .dc-event-draft-deleted { color: #c62828; }
.dc-event-file-replaced, .dc-event-details-edited { color: #ef6c00; }

.admin-table td.dc-detail,
.dc-events .dc-detail {
	white-space: normal;
	opacity: 0.85;
	font-size: 0.85rem;
	min-width: 18rem;
}

#dc-log td {
	vertical-align: top;
}

.dc-btn.dc-primary {
	background: var(--accent);
	color: #fff;
}

.dc-actions {
	text-align: right;
}

.dc-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.3rem 0.6rem;
	font-size: 0.85rem;
	margin-left: 0.3rem;
	text-decoration: none;
}

.dc-viewer {
	max-width: min(1100px, 96vw);
	height: 92vh;
	display: flex;
	flex-direction: column;
	padding: 1.25rem 1.5rem;
}

.dc-viewer-head {
	display: flex;
	align-items: flex-start;
	gap: 1rem;
	margin-bottom: 0.75rem;
}

.dc-viewer-head h2 {
	margin: 0;
	font-size: 1.1rem;
	font-family: monospace;
}

.dc-viewer-head .dc-sub {
	font-size: 0.85rem;
	opacity: 0.85;
	margin-top: 0.25rem;
}

.dc-viewer-actions {
	margin-left: auto;
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem;
	justify-content: flex-end;
}

.dc-viewer-body {
	flex: 1;
	min-height: 0;
	display: grid;
	grid-template-columns: minmax(0, 1fr) 21rem;
	gap: 1rem;
}

.dc-pdf {
	width: 100%;
	height: 100%;
	border: 1px solid var(--grid-line);
	border-radius: 6px;
	background: #fff;
}

.dc-side {
	overflow: auto;
	font-size: 0.85rem;
	min-height: 0;
}

.dc-side h3 {
	margin: 0.6rem 0 0.35rem 0;
	font-size: 0.9rem;
	color: var(--accent);
}

.dc-side h3:first-child {
	margin-top: 0;
}

.dc-meta {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 0.15rem 0.6rem;
	margin: 0;
}

.dc-meta dt {
	opacity: 0.7;
	white-space: nowrap;
}

.dc-meta dd {
	margin: 0;
	white-space: pre-wrap;
}

.dc-edit label {
	display: block;
	margin-top: 0.4rem;
	font-size: 0.8rem;
	opacity: 0.8;
}

.dc-edit .form-input {
	width: 100%;
	font-size: 0.85rem;
	padding: 0.3rem 0.5rem;
	margin-top: 0.15rem;
}

.dc-edit .btn-row {
	margin-top: 0.4rem;
}

.dc-hint {
	font-size: 0.75rem;
	opacity: 0.65;
	margin: 0.3rem 0 0 0;
}

.dc-history-table td {
	padding: 0.3rem 0.4rem;
}

.dc-hrow {
	cursor: pointer;
}

.dc-hrow.dc-current {
	background: rgba(213, 0, 0, 0.08);
}

.dc-events {
	list-style: none;
	margin: 0;
	padding: 0;
}

.dc-events li {
	padding: 0.2rem 0;
	border-bottom: 1px solid var(--grid-line);
}


@media (max-width: 900px) {
	.dc-viewer-head { flex-wrap: wrap; }
	.dc-viewer-actions { margin-left: 0; }
	.dc-viewer-body { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
	.dc-side { max-height: 35vh; }
}

/* Feedback register: the message column is free text and can be long, and it
   is the column worth reading, so it gets the room. */
.feedback-page table{width:100%}
.feedback-page .fb-body{white-space:pre-wrap;word-break:break-word;min-width:280px;max-width:560px}
.feedback-page td:first-child{white-space:nowrap}
.feedback-page .fb-field{min-width:120px}
.feedback-page input.fb-field{width:100%}
.feedback-page td{vertical-align:top}

/* -- Panel Inspections (Panel_Inspection*.php) ----------------------- */

.pi-hub { display: flex; flex-direction: column; align-items: center; gap: 1.5rem; }
.pi-hub-title { margin: 0; color: var(--fg); }
.pi-hub-title i { color: var(--accent); }
.pi-hub-grid { grid-template-columns: repeat(3, 170px); }
.pi-tile-count { font-size: 0.78rem; padding: 0.1rem 0.55rem; border-radius: 999px; background: var(--accent); color: #fff; }
.pi-tile-count-quiet { background: transparent; color: var(--fg); opacity: 0.6; }

.pi-main { align-items: flex-start; }
.pi-card { width: 100%; }
.pi-card-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.pi-card-head h1 { margin: 0; }
.pi-card h1 i { color: var(--accent); }
.pi-hint { font-size: 0.9rem; opacity: 0.8; margin-top: 0; }
.pi-link { color: var(--accent); font-size: 0.9rem; }
.pi-muted { opacity: 0.5; }
.pi-pre { white-space: pre-wrap; word-break: break-word; }

.pi-form-row { display: grid; grid-template-columns: 2fr 2fr 1.3fr; gap: 1rem; }
.pi-description { font-family: inherit; line-height: 1.5; resize: vertical; min-height: 14rem; }
.pi-actions { flex-wrap: wrap; }
.pi-search { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.75rem; }
.pi-search input { flex: 1 1 320px; width: auto; }
.pi-search select { width: auto; }

.pi-table .pi-row { cursor: pointer; }
.pi-table .pi-row:hover td { background: var(--grid-line); }
.pi-table a { color: var(--fg); text-decoration: none; }
.pi-table .pi-excerpt { white-space: normal; min-width: 220px; max-width: 420px; }

.pi-badge, .pi-result { display: inline-block; font-size: 0.78rem; padding: 0.1rem 0.5rem; border-radius: 4px; border: 1px solid currentColor; }
.pi-badge-draft { color: #888; }
.pi-badge-submitted { color: #d98e04; }
.pi-badge-returned { color: var(--accent); }
.pi-badge-approved { color: #2e9e44; }
.pi-result-pass { color: #2e9e44; }
.pi-result-fail { color: var(--accent); }
.pi-result-conditional { color: #d98e04; }

.pi-toolbar { flex-wrap: wrap; }
.pi-review-box { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--grid-line); display: flex; flex-direction: column; gap: 0.5rem; }
.pi-review-box summary { cursor: pointer; opacity: 0.8; }
.pi-review-box textarea { font-family: inherit; margin: 0.5rem 0; }

.pi-document h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.05em; opacity: 0.75; margin: 1.5rem 0 0.5rem; }
.pi-doc-head { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 2px solid var(--accent); padding-bottom: 0.75rem; }
.pi-doc-head h1 { margin: 0.15rem 0 0; }
.pi-doc-kind { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }
.pi-doc-meta { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1.25rem; margin: 1rem 0 0; }
.pi-doc-meta dt { opacity: 0.7; }
.pi-doc-meta dd { margin: 0; }
.pi-body { line-height: 1.6; }
.pi-notes { border-left: 3px solid var(--accent); padding-left: 0.75rem; }
.pi-watermark { margin-top: 1.5rem; font-size: 0.85rem; color: var(--accent); font-style: italic; }
.pi-events td.pi-pre { white-space: pre-wrap; min-width: 200px; }

@media (max-width: 720px) {
	.pi-hub-grid { grid-template-columns: repeat(2, 150px); grid-auto-rows: 150px; }
	.pi-form-row { grid-template-columns: 1fr; }
}

@media print {
	.topbar, .pi-no-print { display: none !important; }
	body.pi-print-body { background: #fff; color: #000; }
	.pi-document { border: none; box-shadow: none; padding: 0; max-width: none; }
	.pi-main { padding: 0; min-height: 0; }
}
