Spaces:
Sleeping
Sleeping
Commit ·
f7864d7
1
Parent(s): 01cb704
feat: Implement dark mode functionality and refine various frontend layout styles.
Browse files- frontend/app.js +44 -1
- frontend/index.html +122 -129
- frontend/styles.css +221 -9
frontend/app.js
CHANGED
|
@@ -88,6 +88,9 @@ const physicianNotesInput = document.getElementById("physicianNotesInput");
|
|
| 88 |
const confirmShareButton = document.getElementById("confirmShareButton");
|
| 89 |
const shareEmailInput = document.getElementById("shareEmailInput");
|
| 90 |
const shareMessageInput = document.getElementById("shareMessageInput");
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
const analysisMessages = [
|
| 93 |
"Processing 324 slices",
|
|
@@ -100,6 +103,7 @@ wireUpload();
|
|
| 100 |
wireActions();
|
| 101 |
wireModals();
|
| 102 |
wireTechnicalTabs();
|
|
|
|
| 103 |
renderRecentUploads();
|
| 104 |
renderHistoryPage();
|
| 105 |
updateNavState();
|
|
@@ -259,6 +263,45 @@ function wireModals() {
|
|
| 259 |
});
|
| 260 |
}
|
| 261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
function wireTechnicalTabs() {
|
| 263 |
technicalTabs.forEach((tab) => {
|
| 264 |
tab.addEventListener("click", () => {
|
|
@@ -660,7 +703,7 @@ function renderHistoryPage() {
|
|
| 660 |
|
| 661 |
if (!items.length) {
|
| 662 |
historyGroups.innerHTML = `
|
| 663 |
-
<article class="card"
|
| 664 |
<h3>No scans yet</h3>
|
| 665 |
<p class="summary-text">Analyze a CT scan to start building your history.</p>
|
| 666 |
</article>
|
|
|
|
| 88 |
const confirmShareButton = document.getElementById("confirmShareButton");
|
| 89 |
const shareEmailInput = document.getElementById("shareEmailInput");
|
| 90 |
const shareMessageInput = document.getElementById("shareMessageInput");
|
| 91 |
+
const themeRadios = Array.from(document.querySelectorAll("input[name='theme']"));
|
| 92 |
+
const THEME_KEY = "oncovision.theme";
|
| 93 |
+
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
| 94 |
|
| 95 |
const analysisMessages = [
|
| 96 |
"Processing 324 slices",
|
|
|
|
| 103 |
wireActions();
|
| 104 |
wireModals();
|
| 105 |
wireTechnicalTabs();
|
| 106 |
+
wireThemeSelector();
|
| 107 |
renderRecentUploads();
|
| 108 |
renderHistoryPage();
|
| 109 |
updateNavState();
|
|
|
|
| 263 |
});
|
| 264 |
}
|
| 265 |
|
| 266 |
+
function wireThemeSelector() {
|
| 267 |
+
const stored = localStorage.getItem(THEME_KEY) || "auto";
|
| 268 |
+
themeRadios.forEach((input) => {
|
| 269 |
+
input.checked = input.value === stored;
|
| 270 |
+
input.addEventListener("change", () => {
|
| 271 |
+
localStorage.setItem(THEME_KEY, input.value);
|
| 272 |
+
applyTheme(input.value);
|
| 273 |
+
});
|
| 274 |
+
});
|
| 275 |
+
|
| 276 |
+
applyTheme(stored);
|
| 277 |
+
const handleSystemThemeChange = () => {
|
| 278 |
+
if (localStorage.getItem(THEME_KEY) === "auto") {
|
| 279 |
+
applyTheme("auto");
|
| 280 |
+
}
|
| 281 |
+
};
|
| 282 |
+
|
| 283 |
+
if (typeof prefersDarkScheme.addEventListener === "function") {
|
| 284 |
+
prefersDarkScheme.addEventListener("change", handleSystemThemeChange);
|
| 285 |
+
} else if (typeof prefersDarkScheme.addListener === "function") {
|
| 286 |
+
prefersDarkScheme.addListener(handleSystemThemeChange);
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
function applyTheme(preference) {
|
| 291 |
+
const resolved =
|
| 292 |
+
preference === "dark"
|
| 293 |
+
? "dark"
|
| 294 |
+
: preference === "light"
|
| 295 |
+
? "light"
|
| 296 |
+
: prefersDarkScheme.matches
|
| 297 |
+
? "dark"
|
| 298 |
+
: "light";
|
| 299 |
+
|
| 300 |
+
document.body.classList.toggle("theme-dark", resolved === "dark");
|
| 301 |
+
document.body.classList.toggle("theme-light", resolved === "light");
|
| 302 |
+
document.documentElement.dataset.theme = preference;
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
function wireTechnicalTabs() {
|
| 306 |
technicalTabs.forEach((tab) => {
|
| 307 |
tab.addEventListener("click", () => {
|
|
|
|
| 703 |
|
| 704 |
if (!items.length) {
|
| 705 |
historyGroups.innerHTML = `
|
| 706 |
+
<article class="card">
|
| 707 |
<h3>No scans yet</h3>
|
| 708 |
<p class="summary-text">Analyze a CT scan to start building your history.</p>
|
| 709 |
</article>
|
frontend/index.html
CHANGED
|
@@ -57,7 +57,7 @@
|
|
| 57 |
<section class="hero">
|
| 58 |
<div class="hero__copy page-entrance">
|
| 59 |
<p class="eyebrow">Clinical-grade AI review</p>
|
| 60 |
-
<h1>Detect lung cancer earlier with AI-powered analysis.</h1>
|
| 61 |
<p class="hero__subtitle">Calm, focused software for CT scan upload, nodule detection, and risk review.</p>
|
| 62 |
<p class="hero__lede">
|
| 63 |
OncoVision-X transforms complex chest CT volumes into clear findings, actionable next steps,
|
|
@@ -639,142 +639,135 @@ print(response.json()["analysis"])</code></pre>
|
|
| 639 |
</footer>
|
| 640 |
</div>
|
| 641 |
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
<
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
<
|
| 664 |
-
|
| 665 |
-
</section>
|
| 666 |
-
</div>
|
| 667 |
-
<div class="modal__footer">
|
| 668 |
-
<button class="button button--primary" data-close-modal type="button">Save Changes</button>
|
| 669 |
</div>
|
| 670 |
-
</div>
|
| 671 |
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
|
| 698 |
-
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
|
|
|
| 706 |
</div>
|
| 707 |
-
</div>
|
| 708 |
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
<
|
| 729 |
-
|
| 730 |
-
|
| 731 |
-
|
| 732 |
-
|
| 733 |
-
<
|
| 734 |
-
<
|
| 735 |
-
|
| 736 |
-
|
| 737 |
-
<
|
| 738 |
-
|
| 739 |
-
<
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
<
|
| 744 |
-
<button class="button button--primary" id="generateExportButton" type="button">Generate PDF</button>
|
| 745 |
</div>
|
| 746 |
-
</div>
|
| 747 |
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
|
|
|
| 775 |
</div>
|
| 776 |
</div>
|
| 777 |
-
</div>
|
| 778 |
|
| 779 |
<template id="noduleCardTemplate">
|
| 780 |
<article class="nodule-card">
|
|
|
|
| 57 |
<section class="hero">
|
| 58 |
<div class="hero__copy page-entrance">
|
| 59 |
<p class="eyebrow">Clinical-grade AI review</p>
|
| 60 |
+
<h1>Detect lung cancer earlier with <span class="nowrap">AI-powered</span> analysis.</h1>
|
| 61 |
<p class="hero__subtitle">Calm, focused software for CT scan upload, nodule detection, and risk review.</p>
|
| 62 |
<p class="hero__lede">
|
| 63 |
OncoVision-X transforms complex chest CT volumes into clear findings, actionable next steps,
|
|
|
|
| 639 |
</footer>
|
| 640 |
</div>
|
| 641 |
|
| 642 |
+
<div class="modal-backdrop" id="modalBackdrop" hidden>
|
| 643 |
+
<div class="modal modal--settings" id="settingsModal" hidden>
|
| 644 |
+
<div class="modal__header">
|
| 645 |
+
<h2>Settings</h2>
|
| 646 |
+
<button class="icon-close" data-close-modal type="button">×</button>
|
| 647 |
+
</div>
|
| 648 |
+
<div class="modal__body">
|
| 649 |
+
<section class="settings-group">
|
| 650 |
+
<h3>Preferences</h3>
|
| 651 |
+
<label><input type="checkbox" checked> Email notifications</label>
|
| 652 |
+
<label><input type="checkbox" checked> Auto-save scans</label>
|
| 653 |
+
<label><input type="checkbox"> Share anonymous data</label>
|
| 654 |
+
</section>
|
| 655 |
+
<section class="settings-group">
|
| 656 |
+
<h3>Display</h3>
|
| 657 |
+
<label><input type="radio" name="theme" value="light" checked> Light</label>
|
| 658 |
+
<label><input type="radio" name="theme" value="auto"> Auto</label>
|
| 659 |
+
<label><input type="radio" name="theme" value="dark"> Dark</label>
|
| 660 |
+
</section>
|
| 661 |
+
</div>
|
| 662 |
+
<div class="modal__footer">
|
| 663 |
+
<button class="button button--primary" data-close-modal type="button">Save Changes</button>
|
| 664 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 665 |
</div>
|
|
|
|
| 666 |
|
| 667 |
+
<div class="modal" id="helpModal" hidden>
|
| 668 |
+
<div class="modal__header">
|
| 669 |
+
<h2>Documentation</h2>
|
| 670 |
+
<button class="icon-close" data-close-modal type="button">×</button>
|
| 671 |
+
</div>
|
| 672 |
+
<div class="modal__body">
|
| 673 |
+
<input class="search-input" type="search" placeholder="Search workflow notes">
|
| 674 |
+
<section class="settings-group">
|
| 675 |
+
<h3>Getting Started</h3>
|
| 676 |
+
<p>Upload one CT volume or use the sample study from the upload page.</p>
|
| 677 |
+
<p>Wait for preprocessing, candidate review, and report assembly to complete before navigating away.</p>
|
| 678 |
+
<p>Open the results page to inspect the scan views, summary banner, nodule cards, and timing metrics.</p>
|
| 679 |
+
</section>
|
| 680 |
+
<section class="settings-group">
|
| 681 |
+
<h3>Reading Results</h3>
|
| 682 |
+
<p>Risk labels summarize the highest malignancy probability found in the current scan.</p>
|
| 683 |
+
<p>Each nodule card lists location, detection confidence, malignancy probability, and follow-up guidance.</p>
|
| 684 |
+
<p>Use the CT visualization and the exported PDF together when preparing printouts or handoffs.</p>
|
| 685 |
+
</section>
|
| 686 |
+
<section class="settings-group">
|
| 687 |
+
<h3>Exports and Sharing</h3>
|
| 688 |
+
<p>Use Export PDF for a formatted report with dedicated imaging pages suitable for printing.</p>
|
| 689 |
+
<p>Use Share to prepare a review link and message for another clinician or collaborator.</p>
|
| 690 |
+
<p>Use Export Image when you only need the current visualization panel.</p>
|
| 691 |
+
</section>
|
| 692 |
+
<section class="settings-group">
|
| 693 |
+
<h3>Troubleshooting</h3>
|
| 694 |
+
<p>If a scan does not appear, confirm the file is `.nii`, `.nii.gz`, `.mhd`, `.npy`, or `.npz`.</p>
|
| 695 |
+
<p>If the PDF layout looks outdated, refresh the browser before generating a new report.</p>
|
| 696 |
+
<p>If results look unexpected, compare the current scan against prior exports from the History page.</p>
|
| 697 |
+
</section>
|
| 698 |
+
</div>
|
| 699 |
+
<div class="modal__footer">
|
| 700 |
+
<button class="button button--primary" data-close-modal type="button">Close</button>
|
| 701 |
+
</div>
|
| 702 |
</div>
|
|
|
|
| 703 |
|
| 704 |
+
<div class="modal" id="exportModal" hidden>
|
| 705 |
+
<div class="modal__header">
|
| 706 |
+
<h2>Generate PDF Report</h2>
|
| 707 |
+
<button class="icon-close" data-close-modal type="button">×</button>
|
| 708 |
+
</div>
|
| 709 |
+
<div class="modal__body">
|
| 710 |
+
<section class="settings-group">
|
| 711 |
+
<h3>Include in report</h3>
|
| 712 |
+
<label><input type="checkbox" checked> Cover page</label>
|
| 713 |
+
<label><input type="checkbox" checked> Executive summary</label>
|
| 714 |
+
<label><input type="checkbox" checked> Detailed nodule findings</label>
|
| 715 |
+
<label><input type="checkbox" checked> CT scan visualization</label>
|
| 716 |
+
<label><input type="checkbox" checked> Technical metadata</label>
|
| 717 |
+
<label><input type="checkbox" checked> Medical disclaimer</label>
|
| 718 |
+
</section>
|
| 719 |
+
<section class="settings-group">
|
| 720 |
+
<h3>Report Style</h3>
|
| 721 |
+
<p class="summary-text">Professional template only — curated for clinical handoff.</p>
|
| 722 |
+
</section>
|
| 723 |
+
<section class="settings-group">
|
| 724 |
+
<h3>Patient Information</h3>
|
| 725 |
+
<input class="search-input" id="patientNameInput" type="text" placeholder="Name">
|
| 726 |
+
<input class="search-input" id="patientMrnInput" type="text" placeholder="MRN">
|
| 727 |
+
<input class="search-input" id="patientDobInput" type="text" placeholder="DOB">
|
| 728 |
+
</section>
|
| 729 |
+
<section class="settings-group">
|
| 730 |
+
<h3>Physician Notes</h3>
|
| 731 |
+
<textarea class="notes-input" id="physicianNotesInput" placeholder="Add clinical context..."></textarea>
|
| 732 |
+
</section>
|
| 733 |
+
</div>
|
| 734 |
+
<div class="modal__footer">
|
| 735 |
+
<button class="button button--ghost" data-close-modal type="button">Cancel</button>
|
| 736 |
+
<button class="button button--secondary" id="previewExportButton" type="button">Preview</button>
|
| 737 |
+
<button class="button button--primary" id="generateExportButton" type="button">Generate PDF</button>
|
| 738 |
+
</div>
|
|
|
|
| 739 |
</div>
|
|
|
|
| 740 |
|
| 741 |
+
<div class="modal" id="shareModal" hidden>
|
| 742 |
+
<div class="modal__header">
|
| 743 |
+
<h2>Share Scan Results</h2>
|
| 744 |
+
<button class="icon-close" data-close-modal type="button">×</button>
|
| 745 |
+
</div>
|
| 746 |
+
<div class="modal__body">
|
| 747 |
+
<section class="settings-group">
|
| 748 |
+
<h3>Share Method</h3>
|
| 749 |
+
<label><input type="radio" name="share-method"> Secure Link</label>
|
| 750 |
+
<label><input type="radio" name="share-method" checked> Email</label>
|
| 751 |
+
<label><input type="radio" name="share-method"> Download QR Code</label>
|
| 752 |
+
</section>
|
| 753 |
+
<section class="settings-group">
|
| 754 |
+
<h3>Email</h3>
|
| 755 |
+
<input class="search-input" id="shareEmailInput" type="email" placeholder="physician@example.com">
|
| 756 |
+
<textarea class="notes-input" id="shareMessageInput" placeholder="Please review this scan..."></textarea>
|
| 757 |
+
</section>
|
| 758 |
+
<section class="settings-group">
|
| 759 |
+
<h3>Security Options</h3>
|
| 760 |
+
<label><input type="checkbox" checked> Require password</label>
|
| 761 |
+
<label><input type="checkbox" checked> Notify me when viewed</label>
|
| 762 |
+
<label><input type="checkbox"> Disable after first view</label>
|
| 763 |
+
</section>
|
| 764 |
+
</div>
|
| 765 |
+
<div class="modal__footer">
|
| 766 |
+
<button class="button button--ghost" data-close-modal type="button">Cancel</button>
|
| 767 |
+
<button class="button button--primary" id="confirmShareButton" type="button">Share Results</button>
|
| 768 |
+
</div>
|
| 769 |
</div>
|
| 770 |
</div>
|
|
|
|
| 771 |
|
| 772 |
<template id="noduleCardTemplate">
|
| 773 |
<article class="nodule-card">
|
frontend/styles.css
CHANGED
|
@@ -93,6 +93,10 @@ a {
|
|
| 93 |
text-decoration: none;
|
| 94 |
}
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
button {
|
| 97 |
border: 0;
|
| 98 |
background: none;
|
|
@@ -592,7 +596,7 @@ a:focus-visible,
|
|
| 592 |
}
|
| 593 |
|
| 594 |
.page-header {
|
| 595 |
-
|
| 596 |
padding: 56px 0 20px;
|
| 597 |
}
|
| 598 |
|
|
@@ -611,9 +615,11 @@ a:focus-visible,
|
|
| 611 |
|
| 612 |
.upload-layout {
|
| 613 |
display: grid;
|
| 614 |
-
grid-template-columns: minmax(0, 720px) minmax(280px, 360px);
|
| 615 |
gap: 32px;
|
|
|
|
| 616 |
align-items: start;
|
|
|
|
|
|
|
| 617 |
}
|
| 618 |
|
| 619 |
.upload-focus {
|
|
@@ -1250,7 +1256,7 @@ a:focus-visible,
|
|
| 1250 |
}
|
| 1251 |
|
| 1252 |
.history-toolbar {
|
| 1253 |
-
|
| 1254 |
display: flex;
|
| 1255 |
flex-wrap: wrap;
|
| 1256 |
gap: 12px;
|
|
@@ -1261,7 +1267,7 @@ a:focus-visible,
|
|
| 1261 |
}
|
| 1262 |
|
| 1263 |
.history-group {
|
| 1264 |
-
|
| 1265 |
padding-top: 28px;
|
| 1266 |
}
|
| 1267 |
|
|
@@ -1296,9 +1302,9 @@ a:focus-visible,
|
|
| 1296 |
}
|
| 1297 |
|
| 1298 |
.technical-tabs {
|
| 1299 |
-
|
| 1300 |
-
display:
|
| 1301 |
-
|
| 1302 |
gap: 12px;
|
| 1303 |
}
|
| 1304 |
|
|
@@ -1310,7 +1316,7 @@ a:focus-visible,
|
|
| 1310 |
background: rgba(255, 255, 255, 0.9);
|
| 1311 |
color: var(--text-secondary);
|
| 1312 |
box-shadow: var(--shadow-sm);
|
| 1313 |
-
white-space:
|
| 1314 |
}
|
| 1315 |
|
| 1316 |
.technical-tab.is-active {
|
|
@@ -1320,7 +1326,7 @@ a:focus-visible,
|
|
| 1320 |
}
|
| 1321 |
|
| 1322 |
.technical-content {
|
| 1323 |
-
|
| 1324 |
}
|
| 1325 |
|
| 1326 |
.technical-card {
|
|
@@ -2004,3 +2010,209 @@ a:focus-visible,
|
|
| 2004 |
line-height: 1.5;
|
| 2005 |
}
|
| 2006 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
text-decoration: none;
|
| 94 |
}
|
| 95 |
|
| 96 |
+
.nowrap {
|
| 97 |
+
white-space: nowrap;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
button {
|
| 101 |
border: 0;
|
| 102 |
background: none;
|
|
|
|
| 596 |
}
|
| 597 |
|
| 598 |
.page-header {
|
| 599 |
+
width: 100%;
|
| 600 |
padding: 56px 0 20px;
|
| 601 |
}
|
| 602 |
|
|
|
|
| 615 |
|
| 616 |
.upload-layout {
|
| 617 |
display: grid;
|
|
|
|
| 618 |
gap: 32px;
|
| 619 |
+
grid-template-columns: minmax(0, 1.2fr) minmax(280px, 360px);
|
| 620 |
align-items: start;
|
| 621 |
+
width: min(100%, 1120px);
|
| 622 |
+
margin: 0 auto;
|
| 623 |
}
|
| 624 |
|
| 625 |
.upload-focus {
|
|
|
|
| 1256 |
}
|
| 1257 |
|
| 1258 |
.history-toolbar {
|
| 1259 |
+
width: 100%;
|
| 1260 |
display: flex;
|
| 1261 |
flex-wrap: wrap;
|
| 1262 |
gap: 12px;
|
|
|
|
| 1267 |
}
|
| 1268 |
|
| 1269 |
.history-group {
|
| 1270 |
+
width: 100%;
|
| 1271 |
padding-top: 28px;
|
| 1272 |
}
|
| 1273 |
|
|
|
|
| 1302 |
}
|
| 1303 |
|
| 1304 |
.technical-tabs {
|
| 1305 |
+
width: 100%;
|
| 1306 |
+
display: grid;
|
| 1307 |
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
| 1308 |
gap: 12px;
|
| 1309 |
}
|
| 1310 |
|
|
|
|
| 1316 |
background: rgba(255, 255, 255, 0.9);
|
| 1317 |
color: var(--text-secondary);
|
| 1318 |
box-shadow: var(--shadow-sm);
|
| 1319 |
+
white-space: normal;
|
| 1320 |
}
|
| 1321 |
|
| 1322 |
.technical-tab.is-active {
|
|
|
|
| 1326 |
}
|
| 1327 |
|
| 1328 |
.technical-content {
|
| 1329 |
+
width: 100%;
|
| 1330 |
}
|
| 1331 |
|
| 1332 |
.technical-card {
|
|
|
|
| 2010 |
line-height: 1.5;
|
| 2011 |
}
|
| 2012 |
}
|
| 2013 |
+
|
| 2014 |
+
body.theme-dark {
|
| 2015 |
+
background: #010101;
|
| 2016 |
+
color: #f4f4f5;
|
| 2017 |
+
}
|
| 2018 |
+
|
| 2019 |
+
body.theme-dark .topbar__inner {
|
| 2020 |
+
background: rgba(0, 0, 0, 0.9);
|
| 2021 |
+
border-color: rgba(255, 255, 255, 0.08);
|
| 2022 |
+
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.85);
|
| 2023 |
+
}
|
| 2024 |
+
|
| 2025 |
+
body.theme-dark .nav a {
|
| 2026 |
+
color: rgba(255, 255, 255, 0.8);
|
| 2027 |
+
}
|
| 2028 |
+
|
| 2029 |
+
body.theme-dark .nav a.is-active,
|
| 2030 |
+
body.theme-dark .nav a:hover {
|
| 2031 |
+
color: #fff;
|
| 2032 |
+
}
|
| 2033 |
+
|
| 2034 |
+
body.theme-dark h1,
|
| 2035 |
+
body.theme-dark h2,
|
| 2036 |
+
body.theme-dark h3,
|
| 2037 |
+
body.theme-dark h4,
|
| 2038 |
+
body.theme-dark h5,
|
| 2039 |
+
body.theme-dark h6,
|
| 2040 |
+
body.theme-dark p,
|
| 2041 |
+
body.theme-dark span,
|
| 2042 |
+
body.theme-dark strong,
|
| 2043 |
+
body.theme-dark small {
|
| 2044 |
+
color: rgba(255, 255, 255, 0.95);
|
| 2045 |
+
}
|
| 2046 |
+
|
| 2047 |
+
body.theme-dark .page-header h1,
|
| 2048 |
+
body.theme-dark .page-header h2,
|
| 2049 |
+
body.theme-dark .history-toolbar span,
|
| 2050 |
+
body.theme-dark .hero__subtitle,
|
| 2051 |
+
body.theme-dark .lead-text,
|
| 2052 |
+
body.theme-dark .cta-panel h2,
|
| 2053 |
+
body.theme-dark .page-header__actions button {
|
| 2054 |
+
color: #fff;
|
| 2055 |
+
}
|
| 2056 |
+
|
| 2057 |
+
body.theme-dark .hero h1,
|
| 2058 |
+
body.theme-dark .hero__subtitle,
|
| 2059 |
+
body.theme-dark .hero__lede,
|
| 2060 |
+
body.theme-dark .section-copy h2,
|
| 2061 |
+
body.theme-dark .section-copy p,
|
| 2062 |
+
body.theme-dark .panel-header h2,
|
| 2063 |
+
body.theme-dark .panel-header p,
|
| 2064 |
+
body.theme-dark .summary-text,
|
| 2065 |
+
body.theme-dark .feature-card h3,
|
| 2066 |
+
body.theme-dark .stat-card strong,
|
| 2067 |
+
body.theme-dark .history-card h3,
|
| 2068 |
+
body.theme-dark .history-card__file,
|
| 2069 |
+
body.theme-dark .history-card__date,
|
| 2070 |
+
body.theme-dark .history-card__score,
|
| 2071 |
+
body.theme-dark .risk-banner__label,
|
| 2072 |
+
body.theme-dark .legend span,
|
| 2073 |
+
body.theme-dark .results-meta,
|
| 2074 |
+
body.theme-dark .analysis-detail,
|
| 2075 |
+
body.theme-dark .breadcrumb {
|
| 2076 |
+
color: rgba(255, 255, 255, 0.8);
|
| 2077 |
+
}
|
| 2078 |
+
|
| 2079 |
+
body.theme-dark .card,
|
| 2080 |
+
body.theme-dark .modal,
|
| 2081 |
+
body.theme-dark .upload-zone,
|
| 2082 |
+
body.theme-dark .hero__visual-card,
|
| 2083 |
+
body.theme-dark .results-main,
|
| 2084 |
+
body.theme-dark .results-sidebar .card,
|
| 2085 |
+
body.theme-dark .history-card,
|
| 2086 |
+
body.theme-dark .stat-card,
|
| 2087 |
+
body.theme-dark .feature-card,
|
| 2088 |
+
body.theme-dark .step-card,
|
| 2089 |
+
body.theme-dark .cta-panel,
|
| 2090 |
+
body.theme-dark .sample-card,
|
| 2091 |
+
body.theme-dark .panel-header,
|
| 2092 |
+
body.theme-dark .technical-card,
|
| 2093 |
+
body.theme-dark .media-card,
|
| 2094 |
+
body.theme-dark .code-card,
|
| 2095 |
+
body.theme-dark .floating-bar,
|
| 2096 |
+
body.theme-dark .upload-focus,
|
| 2097 |
+
body.theme-dark .technical-columns,
|
| 2098 |
+
body.theme-dark .metric-table div,
|
| 2099 |
+
body.theme-dark .selected-file-panel,
|
| 2100 |
+
body.theme-dark .file-facts div,
|
| 2101 |
+
body.theme-dark .timing-grid div,
|
| 2102 |
+
body.theme-dark .scan-detail-grid div,
|
| 2103 |
+
body.theme-dark .nodule-card,
|
| 2104 |
+
body.theme-dark .recent-upload-item,
|
| 2105 |
+
body.theme-dark .empty-state {
|
| 2106 |
+
background: rgba(0, 0, 0, 0.85);
|
| 2107 |
+
border-color: rgba(255, 255, 255, 0.08);
|
| 2108 |
+
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.9);
|
| 2109 |
+
}
|
| 2110 |
+
|
| 2111 |
+
body.theme-dark .results-main,
|
| 2112 |
+
body.theme-dark .results-sidebar .card {
|
| 2113 |
+
border: 1px solid rgba(255, 255, 255, 0.06);
|
| 2114 |
+
}
|
| 2115 |
+
|
| 2116 |
+
body.theme-dark .modal-backdrop {
|
| 2117 |
+
background: rgba(0, 0, 0, 0.78);
|
| 2118 |
+
}
|
| 2119 |
+
|
| 2120 |
+
body.theme-dark .upload-zone__icon,
|
| 2121 |
+
body.theme-dark .status-banner {
|
| 2122 |
+
background: rgba(255, 255, 255, 0.03);
|
| 2123 |
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 2124 |
+
color: #fff;
|
| 2125 |
+
}
|
| 2126 |
+
|
| 2127 |
+
body.theme-dark .risk-banner {
|
| 2128 |
+
border-left-width: 1px;
|
| 2129 |
+
}
|
| 2130 |
+
|
| 2131 |
+
body.theme-dark .risk-banner--low {
|
| 2132 |
+
background: rgba(16, 185, 129, 0.12);
|
| 2133 |
+
border-left-color: var(--success);
|
| 2134 |
+
}
|
| 2135 |
+
|
| 2136 |
+
body.theme-dark .risk-banner--medium {
|
| 2137 |
+
background: rgba(245, 158, 11, 0.12);
|
| 2138 |
+
border-left-color: var(--warning);
|
| 2139 |
+
}
|
| 2140 |
+
|
| 2141 |
+
body.theme-dark .risk-banner--high {
|
| 2142 |
+
background: rgba(239, 68, 68, 0.12);
|
| 2143 |
+
border-left-color: var(--alert);
|
| 2144 |
+
}
|
| 2145 |
+
|
| 2146 |
+
body.theme-dark .analysis-view h1 {
|
| 2147 |
+
color: #fff;
|
| 2148 |
+
}
|
| 2149 |
+
|
| 2150 |
+
body.theme-dark .analysis-steps span {
|
| 2151 |
+
background: rgba(255, 255, 255, 0.08);
|
| 2152 |
+
color: #f4f4f5;
|
| 2153 |
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
| 2154 |
+
}
|
| 2155 |
+
|
| 2156 |
+
body.theme-dark input,
|
| 2157 |
+
body.theme-dark textarea,
|
| 2158 |
+
body.theme-dark select,
|
| 2159 |
+
body.theme-dark .search-input,
|
| 2160 |
+
body.theme-dark .filter-select {
|
| 2161 |
+
background: rgba(0, 0, 0, 0.92);
|
| 2162 |
+
border-color: rgba(255, 255, 255, 0.2);
|
| 2163 |
+
color: #f4f4f5;
|
| 2164 |
+
}
|
| 2165 |
+
|
| 2166 |
+
body.theme-dark ::placeholder {
|
| 2167 |
+
color: rgba(255, 255, 255, 0.45);
|
| 2168 |
+
}
|
| 2169 |
+
|
| 2170 |
+
body.theme-dark .scroll-hint span {
|
| 2171 |
+
background: rgba(255, 255, 255, 0.5);
|
| 2172 |
+
}
|
| 2173 |
+
|
| 2174 |
+
body.theme-dark .upload-divider span {
|
| 2175 |
+
color: rgba(255, 255, 255, 0.45);
|
| 2176 |
+
}
|
| 2177 |
+
|
| 2178 |
+
body.theme-dark .icon-button {
|
| 2179 |
+
background: rgba(255, 255, 255, 0.05);
|
| 2180 |
+
border-color: rgba(255, 255, 255, 0.12);
|
| 2181 |
+
color: #fff;
|
| 2182 |
+
}
|
| 2183 |
+
|
| 2184 |
+
body.theme-dark .icon-button:hover {
|
| 2185 |
+
background: rgba(255, 255, 255, 0.12);
|
| 2186 |
+
border-color: rgba(255, 255, 255, 0.2);
|
| 2187 |
+
}
|
| 2188 |
+
|
| 2189 |
+
body.theme-dark .footer,
|
| 2190 |
+
body.theme-dark .footer-grid,
|
| 2191 |
+
body.theme-dark .footer-strip {
|
| 2192 |
+
color: rgba(255, 255, 255, 0.7);
|
| 2193 |
+
}
|
| 2194 |
+
|
| 2195 |
+
body.theme-dark .footer-link,
|
| 2196 |
+
body.theme-dark .footer-heading {
|
| 2197 |
+
color: #fff;
|
| 2198 |
+
}
|
| 2199 |
+
|
| 2200 |
+
body.theme-dark .technical-tabs {
|
| 2201 |
+
background: rgba(0, 0, 0, 0.95);
|
| 2202 |
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 2203 |
+
padding: 14px;
|
| 2204 |
+
border-radius: 16px;
|
| 2205 |
+
}
|
| 2206 |
+
|
| 2207 |
+
body.theme-dark .technical-tab {
|
| 2208 |
+
background: rgba(255, 255, 255, 0.05);
|
| 2209 |
+
border-color: rgba(255, 255, 255, 0.12);
|
| 2210 |
+
color: #fff;
|
| 2211 |
+
box-shadow: none;
|
| 2212 |
+
}
|
| 2213 |
+
|
| 2214 |
+
body.theme-dark .technical-tab.is-active {
|
| 2215 |
+
background: rgba(255, 255, 255, 0.18);
|
| 2216 |
+
border-color: rgba(255, 255, 255, 0.2);
|
| 2217 |
+
color: #fff;
|
| 2218 |
+
}
|