Artur Mukhamadiev a9908a533f frontend: web UI track handoff (contract revision 1)
Static frontend with vendored marked/DOMPurify, bounded Markdown
pipeline, same-origin mock server with scenario selection, unit,
contract and CDP end-to-end tests under frontend/**.
2026-09-14 21:57:54 +03:00

1086 lines
21 KiB
CSS

/* Confluence Research Web UI - Clean White Minimalist Theme */
:root {
--color-bg-primary: #FFFFFF;
--color-bg-secondary: #FAFAFA;
--color-border: #E5E7EB;
--color-border-hover: #D1D5DB;
--color-text-primary: #111827;
--color-text-secondary: #6B7280;
--color-accent: #2563EB;
--color-accent-hover: #1D4ED8;
--color-accent-light: #EFF6FF;
--color-error: #DC2626;
--color-error-bg: #FEF2F2;
--color-error-border: #FCA5A5;
--color-success: #16A34A;
--color-success-bg: #F0FDF4;
--color-success-border: #86EFAC;
--color-warning: #D97706;
--color-warning-bg: #FFFBEB;
--color-warning-border: #FCD34D;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
--max-width: 860px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
}
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-sans);
font-size: 15px;
line-height: 1.6;
color: var(--color-text-primary);
background-color: var(--color-bg-primary);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Accessibility */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
.hidden {
display: none !important;
}
/* Header */
.app-header {
position: relative;
width: 100%;
max-width: var(--max-width);
margin: 0 auto;
padding: 16px 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.app-brand {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
font-size: 17px;
color: var(--color-text-primary);
letter-spacing: -0.01em;
}
.key-btn {
position: relative;
background: transparent;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
width: 38px;
height: 38px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--color-text-secondary);
transition: all 0.15s ease-in-out;
}
.key-btn:hover {
background-color: var(--color-bg-secondary);
border-color: var(--color-border-hover);
color: var(--color-text-primary);
}
.cred-indicator {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #9CA3AF; /* Gray outline/unset state */
transition: background-color 0.2s ease;
}
.cred-indicator.active {
background-color: var(--color-success); /* Green dot when active */
box-shadow: 0 0 0 1.5px var(--color-bg-primary);
}
/* App Main Container */
.app-main {
flex: 1;
width: 100%;
max-width: var(--max-width);
margin: 0 auto;
padding: 0 24px 48px 24px;
display: flex;
flex-direction: column;
}
/* Alert Boxes */
.alert-box {
width: 100%;
padding: 12px 16px;
border-radius: var(--radius-md);
font-size: 14px;
margin-bottom: 16px;
}
.error-box {
background-color: var(--color-error-bg);
border: 1px solid var(--color-error-border);
color: var(--color-error);
}
.warning-box {
background-color: var(--color-warning-bg);
border: 1px solid var(--color-warning-border);
color: var(--color-warning);
}
.success-box {
background-color: var(--color-success-bg);
border: 1px solid var(--color-success-border);
color: var(--color-success);
}
/* State 1: Prompt View */
.view-prompt {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: calc(80vh - 120px);
padding: 24px 0;
}
.prompt-wrapper {
width: 100%;
max-width: 680px;
display: flex;
flex-direction: column;
align-items: center;
}
.prompt-title {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 24px;
text-align: center;
color: var(--color-text-primary);
}
.prompt-box {
width: 100%;
position: relative;
background-color: var(--color-bg-primary);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 4px 6px -1px rgba(0, 0, 0, 0.03);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
padding: 14px 16px 10px 16px;
}
.prompt-box:focus-within {
border-color: var(--color-accent);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.prompt-input {
width: 100%;
border: none;
background: transparent;
outline: none;
font-family: var(--font-sans);
font-size: 16px;
line-height: 1.5;
color: var(--color-text-primary);
resize: none;
min-height: 72px;
max-height: 280px;
overflow-y: auto;
display: block;
}
.prompt-input::placeholder {
color: #9CA3AF;
}
.prompt-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid #F3F4F6;
}
.prompt-helper {
font-size: 12px;
color: var(--color-text-secondary);
user-select: none;
}
.submit-btn {
background-color: var(--color-accent);
color: #FFFFFF;
border: none;
border-radius: var(--radius-md);
padding: 6px 14px;
font-size: 14px;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
transition: background-color 0.15s ease;
}
.submit-btn:hover:not(:disabled) {
background-color: var(--color-accent-hover);
}
.submit-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* State 3: Loading View */
.view-loading {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: calc(80vh - 120px);
text-align: center;
}
.spinner-wrapper {
margin-bottom: 20px;
}
.gear-spinner {
width: 48px;
height: 48px;
color: var(--color-accent);
stroke-width: 2px;
animation: spin 1.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.gear-spinner {
animation: none;
}
}
.loading-status {
font-size: 16px;
font-weight: 500;
color: var(--color-text-primary);
margin-bottom: 24px;
}
.cancel-btn {
background: transparent;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 8px 18px;
font-size: 14px;
color: var(--color-text-secondary);
cursor: pointer;
transition: all 0.15s ease;
}
.cancel-btn:hover {
background-color: var(--color-bg-secondary);
color: var(--color-text-primary);
border-color: var(--color-border-hover);
}
/* State 4: Result View */
.view-result {
width: 100%;
}
.action-bar {
position: sticky;
top: 0;
background-color: var(--color-bg-primary);
border-bottom: 1px solid var(--color-border);
padding: 12px 0;
margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 20;
}
.action-btn {
background: transparent;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 7px 14px;
font-size: 14px;
font-weight: 500;
color: var(--color-text-primary);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.15s ease;
}
.action-btn:hover {
background-color: var(--color-bg-secondary);
border-color: var(--color-border-hover);
}
.export-btn {
background-color: var(--color-bg-secondary);
}
.export-btn:hover {
background-color: #F3F4F6;
}
/* Rendered Markdown Output */
.output-content {
line-height: 1.7;
color: var(--color-text-primary);
word-break: break-word;
margin-bottom: 32px;
}
.output-content h1,
.output-content h2,
.output-content h3,
.output-content h4,
.output-content h5,
.output-content h6 {
margin-top: 28px;
margin-bottom: 12px;
font-weight: 600;
line-height: 1.3;
color: var(--color-text-primary);
}
.output-content h1 { font-size: 24px; border-bottom: 1px solid var(--color-border); padding-bottom: 8px; }
.output-content h2 { font-size: 20px; border-bottom: 1px solid var(--color-border); padding-bottom: 6px; }
.output-content h3 { font-size: 17px; }
.output-content h4 { font-size: 15px; }
.output-content p {
margin-bottom: 16px;
}
.output-content ul,
.output-content ol {
margin-bottom: 16px;
padding-left: 24px;
}
.output-content li {
margin-bottom: 6px;
}
.output-content blockquote {
border-left: 3px solid var(--color-border-hover);
padding-left: 16px;
margin: 16px 0;
color: var(--color-text-secondary);
font-style: italic;
}
.output-content hr {
border: 0;
border-top: 1px solid var(--color-border);
margin: 24px 0;
}
.output-content a {
color: var(--color-accent);
text-decoration: underline;
text-underline-offset: 2px;
}
.output-content a:hover {
color: var(--color-accent-hover);
}
.output-content code {
font-family: var(--font-mono);
font-size: 13.5px;
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
padding: 2px 5px;
border-radius: var(--radius-sm);
}
.output-content pre {
font-family: var(--font-mono);
font-size: 13.5px;
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
padding: 14px 16px;
border-radius: var(--radius-md);
overflow-x: auto;
margin-bottom: 18px;
}
.output-content pre code {
background: transparent;
border: none;
padding: 0;
}
.output-content table {
width: 100%;
border-collapse: collapse;
margin: 18px 0;
font-size: 14px;
}
.output-content th,
.output-content td {
border: 1px solid var(--color-border);
padding: 8px 12px;
text-align: left;
}
.output-content th {
background-color: var(--color-bg-secondary);
font-weight: 600;
}
.output-content tr:nth-child(even) td {
background-color: #FCFCFC;
}
/* Pathological Fallback & Bounded Section Controls */
.pathological-banner,
.section-nav-banner {
background-color: var(--color-warning-bg);
border: 1px solid var(--color-warning-border);
border-radius: var(--radius-md);
padding: 10px 14px;
font-size: 13px;
color: var(--color-warning);
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
.section-nav-controls {
display: flex;
gap: 8px;
align-items: center;
}
.section-btn {
background: #FFFFFF;
border: 1px solid var(--color-warning-border);
border-radius: var(--radius-sm);
padding: 4px 10px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
}
.section-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pathological-preview {
background-color: var(--color-bg-subtle);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 12px;
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-all;
max-height: 400px;
overflow-y: auto;
margin-bottom: 16px;
}
.render-error-notice {
background-color: var(--color-error-bg);
border: 1px solid var(--color-error-border);
border-radius: var(--radius-md);
padding: 12px 16px;
font-size: 14px;
color: var(--color-error);
margin-bottom: 16px;
}
/* Warnings Area */
.warnings-container {
margin-bottom: 20px;
}
.warning-item {
display: flex;
gap: 8px;
align-items: flex-start;
padding: 8px 12px;
border-radius: var(--radius-sm);
background-color: var(--color-warning-bg);
border: 1px solid var(--color-warning-border);
font-size: 13px;
color: var(--color-warning);
margin-bottom: 6px;
}
.warning-code {
font-family: var(--font-mono);
font-weight: 600;
font-size: 12px;
}
/* Artifacts Section */
.artifacts-section {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 16px 20px;
margin-bottom: 24px;
background-color: var(--color-bg-secondary);
}
.artifacts-heading {
font-size: 15px;
font-weight: 600;
margin-bottom: 12px;
color: var(--color-text-primary);
}
.artifacts-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 8px;
}
.artifact-item {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #FFFFFF;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 10px 14px;
}
.artifact-info {
display: flex;
flex-direction: column;
gap: 2px;
}
.artifact-name {
font-weight: 500;
font-size: 14px;
color: var(--color-text-primary);
font-family: var(--font-mono);
}
.artifact-meta {
font-size: 12px;
color: var(--color-text-secondary);
}
.download-btn {
background-color: #FFFFFF;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 6px 12px;
font-size: 13px;
font-weight: 500;
color: var(--color-text-primary);
cursor: pointer;
transition: all 0.15s ease;
}
.download-btn:hover {
background-color: var(--color-bg-secondary);
border-color: var(--color-border-hover);
}
/* Sources & Request History */
.history-section {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
margin-top: 24px;
overflow: hidden;
background-color: #FFFFFF;
}
.history-toggle-btn {
width: 100%;
padding: 14px 18px;
background: transparent;
border: none;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
font-size: 15px;
font-weight: 600;
color: var(--color-text-primary);
text-align: left;
transition: background-color 0.15s ease;
}
.history-toggle-btn:hover {
background-color: var(--color-bg-secondary);
}
.toggle-icon {
font-size: 12px;
color: var(--color-text-secondary);
transition: transform 0.2s ease;
}
.history-toggle-btn[aria-expanded="true"] .toggle-icon {
transform: rotate(90deg);
}
.history-content {
padding: 0 18px 18px 18px;
border-top: 1px solid var(--color-border);
}
.history-subheading {
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-secondary);
margin: 16px 0 10px 0;
}
/* Pages Accessed Cards */
.pages-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 20px;
}
.page-card {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
}
.page-card-left {
display: flex;
align-items: center;
gap: 10px;
overflow: hidden;
}
.badge-space {
font-size: 11px;
font-weight: 600;
background-color: var(--color-accent-light);
color: var(--color-accent);
border: 1px solid #BFDBFE;
padding: 2px 6px;
border-radius: var(--radius-sm);
font-family: var(--font-mono);
}
.page-title-link {
font-weight: 500;
font-size: 14px;
color: var(--color-text-primary);
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.page-title-link:hover {
text-decoration: underline;
color: var(--color-accent);
}
.page-card-meta {
font-size: 12px;
color: var(--color-text-secondary);
white-space: nowrap;
}
/* Tool History Cards */
.tool-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.tool-card {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background-color: #FFFFFF;
overflow: hidden;
}
.tool-card-header {
padding: 10px 14px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
font-size: 13px;
}
.tool-card-header-left {
display: flex;
align-items: center;
gap: 8px;
}
.tool-id {
font-family: var(--font-mono);
font-weight: 600;
font-size: 12px;
color: var(--color-text-secondary);
}
.tool-name {
font-weight: 600;
color: var(--color-text-primary);
}
.tool-badges {
display: flex;
gap: 6px;
align-items: center;
}
.badge {
font-size: 11px;
padding: 2px 6px;
border-radius: var(--radius-sm);
font-weight: 500;
}
.badge-success {
background-color: var(--color-success-bg);
color: var(--color-success);
border: 1px solid var(--color-success-border);
}
.badge-error {
background-color: var(--color-error-bg);
color: var(--color-error);
border: 1px solid var(--color-error-border);
}
.badge-cache {
background-color: #F3F4F6;
color: #4B5563;
border: 1px solid #D1D5DB;
}
.badge-truncated {
background-color: var(--color-warning-bg);
color: var(--color-warning);
border: 1px solid var(--color-warning-border);
}
.tool-card-body {
padding: 10px 14px;
font-size: 13px;
}
.tool-meta-row {
display: flex;
gap: 16px;
color: var(--color-text-secondary);
font-size: 12px;
margin-bottom: 8px;
}
.tool-expand-btn {
background: transparent;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
padding: 3px 8px;
font-size: 12px;
cursor: pointer;
color: var(--color-text-secondary);
}
.tool-expand-btn:hover {
background-color: var(--color-bg-secondary);
color: var(--color-text-primary);
}
.tool-result-box {
margin-top: 8px;
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
padding: 10px;
font-family: var(--font-mono);
font-size: 12px;
max-height: 240px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
}
/* Modal View */
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.35);
backdrop-filter: blur(4px);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}
.modal-dialog {
background-color: #FFFFFF;
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 480px;
padding: 24px;
position: relative;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-title {
font-size: 18px;
font-weight: 600;
color: var(--color-text-primary);
}
.modal-close-btn {
background: transparent;
border: none;
font-size: 20px;
line-height: 1;
color: var(--color-text-secondary);
cursor: pointer;
padding: 4px;
}
.modal-close-btn:hover {
color: var(--color-text-primary);
}
.form-group {
margin-bottom: 16px;
}
.form-label {
display: block;
font-size: 13px;
font-weight: 500;
margin-bottom: 6px;
color: var(--color-text-primary);
}
.modal-input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
font-size: 14px;
font-family: var(--font-sans);
outline: none;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.modal-input:focus {
border-color: var(--color-accent);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.password-input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.toggle-password-btn {
position: absolute;
right: 8px;
background: transparent;
border: none;
color: var(--color-text-secondary);
cursor: pointer;
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-password-btn:hover {
color: var(--color-text-primary);
}
.field-hint {
display: block;
font-size: 11px;
color: var(--color-text-secondary);
margin-top: 4px;
}
.modal-feedback {
margin-bottom: 16px;
padding: 8px 12px;
border-radius: var(--radius-sm);
font-size: 13px;
}
.modal-actions {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--color-border);
flex-wrap: wrap;
gap: 8px;
}
.modal-actions-right {
display: flex;
gap: 8px;
}
.btn-primary {
background-color: var(--color-accent);
color: #FFFFFF;
border: none;
border-radius: var(--radius-md);
padding: 8px 14px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.15s ease;
}
.btn-primary:hover {
background-color: var(--color-accent-hover);
}
.btn-secondary {
background-color: transparent;
color: var(--color-text-primary);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 8px 14px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
}
.btn-secondary:hover {
background-color: var(--color-bg-secondary);
border-color: var(--color-border-hover);
}
.btn-secondary.danger {
color: var(--color-error);
border-color: var(--color-error-border);
}
.btn-secondary.danger:hover {
background-color: var(--color-error-bg);
}
/* Mobile responsive adjustments */
@media (max-width: 640px) {
.app-main {
padding: 0 16px 32px 16px;
}
.prompt-title {
font-size: 22px;
}
.modal-actions {
flex-direction: column-reverse;
align-items: stretch;
}
.modal-actions-right {
flex-direction: column;
}
.modal-actions-left {
margin-top: 8px;
display: flex;
justify-content: center;
}
.page-card {
flex-direction: column;
align-items: flex-start;
gap: 6px;
}
.page-card-meta {
font-size: 11px;
}
.tool-card-header {
flex-direction: column;
align-items: flex-start;
gap: 6px;
}
}