diff --git a/docs/implementation-notes.md b/docs/implementation-notes.md index 00ee7a6..51f9d40 100644 --- a/docs/implementation-notes.md +++ b/docs/implementation-notes.md @@ -19,6 +19,7 @@ The current slice is a responsive React/Vite local-first review workspace, a det - The current local workspace is persisted in browser storage under a versioned key, including sources, findings, analysis metrics, review notes and decisions. This is intentionally device-local and does not replace a shared backend. - Review reports and approved change requests can be exported as Markdown files without sending project data to an external service. - Pilot safeguards include a 10 MB source limit, required scope/message source validation, source reclassification and removal, stable finding IDs, basic negation and sender-role handling, included/excluded scope matching, and multipart email/plain-text Slack fallbacks. +- The pilot visual system remains the original warm paper/ink/orange workspace design; the page header and demo banner have explicit layout styles so pilot-state additions do not fall back to browser defaults. ## Next technical slice diff --git a/reports/browser-qa.md b/reports/browser-qa.md index e635d0a..e0af8a8 100644 --- a/reports/browser-qa.md +++ b/reports/browser-qa.md @@ -79,3 +79,10 @@ PASS for the local pilot slice. The application is ready for a controlled export - The source list showed both files, the status changed to `Ready to analyse`, and the analysis completed with one finding. - No console errors occurred during the full flow. - The onboarding dialog receives focus when opened and remains dismissible with `Escape`. + +## 2026-08-03 visual regression pass + +- Restored the missing desktop page layout rules for `.content-wrap`, `.page-intro`, headings, intro copy and action buttons. +- Added the visual treatment for the `Demo data` status banner. +- Verified the local desktop render at 1280 × 720 against the intended paper/ink/orange design system. +- Console errors and warnings were empty after the fix. diff --git a/reports/design-audit.md b/reports/design-audit.md new file mode 100644 index 0000000..0060e87 --- /dev/null +++ b/reports/design-audit.md @@ -0,0 +1,41 @@ +# ScopeGuard design audit + +Date: 2026-08-03 + +## Finding + +The pilot hardening change introduced new page markup but dropped the existing CSS block for the editorial page header. The sidebar and lower workspace styles remained active, while the intro layout, heading scale, action buttons and demo banner fell back to browser defaults. This was a high-severity visual regression because the primary workspace lost its visual hierarchy. + +## Before / after + +- Before: the main content started at the page edge, the headline and buttons were unstyled, and the demo notice read as plain text. +- After: the original centered content rail, large editorial headline, paper/ink/orange controls and bordered demo banner are restored. + +## Checked aspects + +1. Page background and warm paper palette — pass. +2. Sidebar width and rail separation — pass. +3. Content max width and horizontal padding — restored and pass. +4. Editorial headline scale and tracking — restored and pass. +5. Intro copy width and line height — restored and pass. +6. Primary and quiet action button states — restored and pass. +7. Demo banner hierarchy and contrast — added and pass. +8. Analysis status strip placement — pass. +9. Evidence/source two-column grid — pass. +10. Finding card borders, radius and spacing — pass. +11. Accent orange reserved for risk and actions — pass. +12. Responsive rules remain present for mobile layout — pass by source inspection; mobile browser emulation remains a follow-up check. +13. Focus-visible treatment remains present — pass. +14. Reduced-motion rule remains present — pass. + +## Files changed + +- `src/styles.css` +- `reports/browser-qa.md` + +## Validation + +- `npm run typecheck` — passed. +- `npm run build` — passed. +- Local browser render at 1280 × 720 — restored visual hierarchy. +- Browser console errors and warnings — none observed. diff --git a/src/styles.css b/src/styles.css index 899783f..112a03e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -49,7 +49,9 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; } .sidebar-footer { margin-top: auto; padding: 16px 7px 0; border-top: 1px solid var(--line); }.device-note { display: grid; gap: 3px; padding: 10px 2px 0; border-top: 1px solid var(--line); }.device-note strong { font-size: 10px; }.device-note small { color: var(--muted); font-size: 9px; line-height: 1.4; } .privacy-note, .user-row { display: flex; align-items: center; gap: 9px; }.privacy-note { padding: 0 2px 22px; }.privacy-note > span:last-child, .user-row > span:nth-child(2) { display: grid; gap: 3px; }.privacy-note strong { font-size: 11px; }.privacy-note small { color: var(--muted); font-size: 10px; }.lock-mark { color: var(--sage); font-size: 9px; }.user-row { padding: 10px 2px 0; }.user-avatar { background: #d88764; font-size: 9px; }.user-row button { border: 0; background: none; color: var(--muted); font-weight: 800; cursor: pointer; } .main-content { min-width: 0; flex: 1; }.topbar { height: 72px; display: flex; align-items: center; justify-content: space-between; padding: 0 clamp(24px, 4vw, 60px); border-bottom: 1px solid var(--line); }.breadcrumbs { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 12px; }.breadcrumbs b { color: #c4bfb4; font-weight: 400; }.breadcrumbs strong { color: var(--ink); font-weight: 700; }.topbar-actions { display: flex; align-items: center; gap: 18px; }.saved-status { display: flex; align-items: center; gap: 7px; color: var(--muted); font-size: 11px; }.saved-status i { width: 6px; height: 6px; border-radius: 50%; background: var(--sage); }.export-notice { color: var(--sage); font-size: 10px; font-weight: 700; }.help-button { width: 23px; height: 23px; display: grid; place-items: center; border: 1px solid #bcb6ab; border-radius: 50%; background: transparent; color: var(--muted); font-size: 12px; cursor: pointer; } +.content-wrap { width: min(1210px, 100%); margin: 0 auto; padding: 53px clamp(24px, 4vw, 60px) 80px; }.page-intro { display: flex; align-items: end; justify-content: space-between; gap: 30px; }.eyebrow { margin: 0 0 11px; color: #a09a8f; font-size: 10px; font-weight: 800; letter-spacing: .16em; line-height: 1.3; }.page-intro h1 { margin: 0; font-size: clamp(38px, 4.2vw, 59px); font-weight: 600; letter-spacing: -.065em; line-height: .98; }.page-intro h1 em { color: var(--accent); font-style: normal; }.intro-copy { max-width: 410px; margin: 18px 0 0; color: var(--muted); font-size: 14px; line-height: 1.55; }.intro-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding-bottom: 2px; }.quiet-button, .primary-button { display: inline-flex; align-items: center; gap: 17px; height: 42px; padding: 0 16px; border-radius: 8px; font-size: 12px; font-weight: 700; cursor: pointer; }.quiet-button { border: 1px solid var(--line); background: transparent; }.quiet-button:hover { background: var(--white); }.primary-button { border: 1px solid var(--ink); background: var(--ink); color: var(--paper); }.primary-button:hover { background: #3c3b36; }.primary-button:active, .quiet-button:active { transform: translateY(1px); }.primary-button span, .quiet-button span { font-size: 15px; font-weight: 400; } .quiet-button:disabled { opacity: .45; cursor: not-allowed; } +.demo-banner { display: flex; align-items: center; gap: 14px; margin-top: 28px; padding: 12px 14px; border: 1px solid #e6cfc2; border-radius: 10px; background: #fff7f0; }.demo-banner-label { flex: 0 0 auto; color: var(--accent-dark); font-size: 9px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }.demo-banner p { flex: 1; margin: 0; color: #7f6e64; font-size: 11px; line-height: 1.4; }.demo-banner button { flex: 0 0 auto; padding: 7px 9px; border: 1px solid #e4b7a6; border-radius: 6px; background: transparent; color: var(--accent-dark); font-size: 10px; font-weight: 700; cursor: pointer; }.demo-banner button:hover { background: #fff0e7; } .status-strip { display: flex; align-items: center; justify-content: space-between; gap: 28px; margin-top: 49px; padding: 18px 21px; border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,253,250,.62); }.status-intro { display: flex; align-items: center; gap: 12px; }.status-icon { width: 28px; height: 28px; display: grid; place-items: center; border-radius: 50%; background: #e6e1d8; color: var(--muted); font-size: 13px; font-weight: 800; }.status-icon.ready { background: #dce5dc; color: #608066; }.status-intro div { display: grid; gap: 4px; }.status-intro strong { font-size: 12px; }.status-intro span:last-child { color: var(--muted); font-size: 11px; }.status-metrics { display: flex; gap: clamp(25px, 4vw, 56px); }.status-metrics div { display: grid; gap: 4px; }.status-metrics span { color: var(--muted); font-size: 10px; }.status-metrics strong { font-size: 16px; font-variant-numeric: tabular-nums; }.orange-text { color: var(--accent); } .workspace-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: clamp(24px, 4vw, 57px); margin-top: 56px; }.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; min-height: 51px; border-bottom: 1px solid var(--line); }.section-heading h2 { margin: 0 0 13px; font-size: 22px; letter-spacing: -.04em; }.section-heading .eyebrow { margin-bottom: 8px; }.filter-tabs { display: flex; gap: 3px; padding-bottom: 9px; }.filter-tabs button { padding: 7px 8px; border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 10px; cursor: pointer; }.filter-tabs button:hover, .filter-tabs button.is-active { color: var(--ink); background: var(--paper-deep); font-weight: 700; }.finding-list { display: grid; gap: 13px; padding-top: 15px; }.finding-card { padding: 19px 20px 17px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--white); }.finding-card:hover { border-color: #b8b1a5; }.finding-card.is-reviewed { background: rgba(255,253,250,.45); opacity: .75; }.finding-topline { display: flex; align-items: center; gap: 8px; }.severity-dot { width: 7px; height: 7px; border-radius: 50%; }.severity-dot.high { background: var(--accent); }.severity-dot.medium { background: #b49a6f; }.severity-dot.low { background: var(--sage); }.finding-type, .finding-id { color: #a09a8f; font-size: 9px; font-weight: 800; letter-spacing: .13em; }.finding-id { margin-left: auto; color: #bdb7ad; letter-spacing: .08em; }.finding-card h3 { margin: 13px 0 8px; font-size: 15px; letter-spacing: -.025em; }.finding-card blockquote { margin: 0; padding-left: 12px; border-left: 2px solid #e6e0d6; color: #6f6c64; font-size: 12px; line-height: 1.5; }.finding-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 18px; padding-top: 13px; border-top: 1px solid #ebe7df; }.finding-meta span, .finding-estimate { display: grid; gap: 4px; color: var(--muted); font-size: 10px; line-height: 1.3; }.finding-meta b { color: #aaa398; font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }.finding-bottom { display: flex; align-items: end; justify-content: space-between; gap: 20px; margin-top: 18px; }.finding-estimate { display: flex; align-items: baseline; flex-wrap: wrap; gap: 7px; }.finding-estimate strong { color: var(--accent); font-size: 13px; }.confidence { padding-left: 8px; border-left: 1px solid var(--line); color: #a49d91; font-size: 10px; }.confidence.strong { color: #68816d; }.review-button { padding: 7px 10px; border: 1px solid var(--line); border-radius: 6px; background: transparent; color: #6f6b63; font-size: 10px; font-weight: 700; cursor: pointer; white-space: nowrap; }.review-button:hover { border-color: var(--ink); color: var(--ink); }.review-button.done { border-color: #c9d5ca; color: #68816d; background: #f1f6f1; }.empty-state { display: grid; gap: 6px; padding: 30px; border: 1px dashed #c8c2b8; border-radius: var(--radius); color: var(--muted); text-align: center; }.empty-state strong { color: var(--ink); font-size: 13px; }.empty-state span { font-size: 11px; } .source-panel { min-width: 0; }.source-heading { align-items: center; }.source-heading h2 { margin-bottom: 13px; }.source-count { margin-bottom: 13px; color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }.source-list { display: grid; gap: 7px; padding: 16px 0 14px; }.source-file { display: flex; align-items: center; gap: 9px; padding: 10px 0; }.file-icon { width: 30px; height: 33px; display: grid; place-items: center; border: 1px solid #d7cfc2; border-radius: 5px; color: var(--accent); font-size: 7px; font-weight: 900; }.file-icon.json { color: #708c76; }.source-file div { display: grid; min-width: 0; flex: 1; gap: 4px; }.source-file strong { overflow: hidden; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }.source-file small { overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; }.file-check { color: #7d987f; font-size: 12px; }.drop-zone { display: grid; justify-items: center; gap: 7px; padding: 22px 12px; border: 1px dashed #bdb6a9; border-radius: var(--radius); background: rgba(255,253,250,.34); text-align: center; transition: .2s ease; }.drop-zone.is-dragging, .drop-zone:hover { border-color: var(--accent); background: #fff9f1; }.upload-symbol { width: 26px; height: 26px; display: grid; place-items: center; margin-bottom: 1px; border: 1px solid #c0b9ae; border-radius: 50%; color: var(--accent); font-size: 18px; line-height: 1; }.drop-zone strong { font-size: 11px; }.drop-zone small { color: var(--muted); font-size: 10px; }.drop-zone button { padding: 0; border: 0; border-bottom: 1px solid #a5a098; background: none; color: var(--ink); cursor: pointer; }.privacy-callout { display: flex; gap: 9px; margin-top: 27px; padding: 13px 0 0; border-top: 1px solid var(--line); }.privacy-callout > span { color: var(--sage); font-size: 9px; padding-top: 2px; }.privacy-callout strong { font-size: 10px; }.privacy-callout p { margin: 5px 0 0; color: var(--muted); font-size: 10px; line-height: 1.45; }.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }