Files
Project-SDE-WP-Suite/html/theme-light.css
n.siegfried 39b48055ff Productionize WP Suite: auth, security hardening, sync, dashboard, PWA, email
Brings the Work Package Suite from a browser-local prototype to a
multi-tenant, SQL-backed deployment hardened for customer IP.

Auth & access control
- Local username/password login (bcrypt + JWT in an HttpOnly cookie),
  admin-managed users, per-project membership, and project-scoped API access.
- Admin console: change user roles, view the audit trail, manage settings.

Security hardening
- CSP / HSTS / X-Frame-Options / nosniff headers in nginx; Secure cookie via
  X-Forwarded-Proto; CSRF Origin check; attribute-safe output escaping.
- Login lockout, token_version session revocation, stronger password policy,
  fail-closed secret loading, encrypted (AES-256) database backups.

Persistence & schema
- SOPs and Work Packages are now DB-backed and shared across users, written
  through a durable client sync outbox that queues offline edits.
- Alembic migrations applied automatically on container start.

New capabilities
- Phase 2 dashboard (progress, gating, pagination, archive).
- Phase 3 PWA "Field View" with offline caching and auth fallback.
- WP owner assignment with OPTIONAL email notifications, OFF by default and
  toggled from the admin console. SMTP password is read only from the
  SMTP_PASSWORD env var (never stored); emails carry a WP number + deep link,
  never customer IP.

Also: IBM Carbon restyle, Help section, and DEPLOYMENT.md brought up to date.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:51:15 -07:00

250 lines
7.7 KiB
CSS

/* IBM Carbon Design System - Light Theme (g10) */
:root {
--cds-interactive-01: #0f62fe;
--cds-interactive-02: #393939;
--cds-interactive-03: #0f62fe;
--cds-interactive-04: #0f62fe;
--cds-ui-background: #f4f4f4;
--cds-ui-01: #ffffff;
--cds-ui-02: #f4f4f4;
--cds-ui-03: #e0e0e0;
--cds-ui-04: #8d8d8d;
--cds-ui-05: #161616;
--cds-text-01: #161616;
--cds-text-02: #525252;
--cds-text-03: #a8a8a8;
--cds-text-04: #ffffff;
--cds-text-05: #6f6f6f;
--cds-text-error: #da1e28;
--cds-icon-01: #161616;
--cds-icon-02: #525252;
--cds-icon-03: #ffffff;
--cds-link-01: #0f62fe;
--cds-link-02: #0043ce;
--cds-inverse-link: #78a9ff;
--cds-field-01: #ffffff;
--cds-field-02: #f4f4f4;
--cds-inverse-01: #ffffff;
--cds-inverse-02: #393939;
--cds-support-01: #da1e28;
--cds-support-02: #198038;
--cds-support-03: #f1c21b;
--cds-support-04: #0043ce;
--cds-inverse-support-01: #fa4d56;
--cds-inverse-support-02: #42be65;
--cds-inverse-support-03: #f1c21b;
--cds-inverse-support-04: #4589ff;
--cds-overlay: rgba(22, 22, 22, .5);
--cds-danger: #da1e28;
--cds-focus: #0f62fe;
--cds-hover-primary: #0353e9;
--cds-active-primary: #002d9c;
--cds-hover-primary-text: #0043ce;
--cds-hover-secondary: #4c4c4c;
--cds-active-secondary: #6f6f6f;
--cds-hover-tertiary: #0353e9;
--cds-active-tertiary: #002d9c;
--cds-hover-ui: #e5e5e5;
--cds-hover-light-ui: #e5e5e5;
--cds-hover-selected-ui: #cacaca;
--cds-active-ui: #c6c6c6;
--cds-active-light-ui: #cacaca;
--cds-selected-ui: #e5e5e5;
--cds-selected-light-ui: #e5e5e5;
--cds-inverse-hover-ui: #353535;
--cds-hover-danger: #ba121b;
--cds-active-danger: #750e13;
--cds-hover-row: #f4f4f4;
--cds-visited-link: #0043ce;
--cds-disabled-01: #f4f4f4;
--cds-disabled-02: #bdbdbd;
--cds-disabled-03: #8d8d8d;
--cds-button-primary: #0f62fe;
--cds-button-secondary: #393939;
--cds-button-tertiary: #0f62fe;
--cds-button-danger-primary: #da1e28;
--cds-button-danger-secondary: #da1e28;
--cds-background: #f4f4f4;
--cds-background-inverse: #161616;
--cds-background-brand: #0f62fe;
--cds-background-active: #e5e5e5;
--cds-background-hover: #e8e8e8;
--cds-background-selected: #e5e5e5;
--cds-background-selected-hover: #cacaca;
--cds-layer: #ffffff;
--cds-layer-accent: #f4f4f4;
--cds-layer-accent-hover: #e8e8e8;
--cds-layer-accent-active: #e0e0e0;
--cds-layer-hover: #e8e8e8;
--cds-layer-active: #e5e5e5;
--cds-layer-selected: #e5e5e5;
--cds-layer-selected-hover: #cacaca;
--cds-layer-selected-inverse: #393939;
--cds-field: #ffffff;
--cds-field-hover: #e8e8e8;
--cds-border-subtle: #e0e0e0;
--cds-border-strong: #8d8d8d;
--cds-border-inverse: #393939;
--cds-border-interactive: #0f62fe;
--cds-border-subtle-selected: #c6c6c6;
--cds-text-primary: #161616;
--cds-text-secondary: #525252;
--cds-text-placeholder: #a8a8a8;
--cds-text-helper: #6f6f6f;
--cds-text-on-color: #ffffff;
--cds-text-inverse: #f4f4f4;
--cds-text-disabled: #bdbdbd;
--cds-link-primary: #0f62fe;
--cds-link-secondary: #0043ce;
--cds-link-visited: #0043ce;
--cds-link-inverse: #78a9ff;
--cds-link-primary-hover: #0353e9;
--cds-icon-primary: #161616;
--cds-icon-secondary: #525252;
--cds-icon-on-color: #ffffff;
--cds-icon-inverse: #f4f4f4;
--cds-icon-disabled: #bdbdbd;
--cds-support-error: #da1e28;
--cds-support-success: #198038;
--cds-support-warning: #f1c21b;
--cds-support-info: #0043ce;
--cds-support-error-inverse: #fa4d56;
--cds-support-success-inverse: #42be65;
--cds-support-warning-inverse: #f1c21b;
--cds-support-info-inverse: #4589ff;
--cds-interactive: #0f62fe;
--cds-shadow: rgba(0, 0, 0, .16);
}
/* Typography */
body {
font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
color: var(--cds-text-primary);
background: var(--cds-background);
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
line-height: 1.28572;
}
h1 { font-size: 2rem; }
h2 { font-size: 1.75rem; }
h3 { font-size: 1.25rem; }
h4 { font-size: 1rem; }
h5 { font-size: .875rem; }
h6 { font-size: .75rem; }
a {
color: var(--cds-link-primary);
text-decoration: none;
}
a:hover {
color: var(--cds-link-primary-hover);
text-decoration: underline;
}
button {
font-family: inherit;
cursor: pointer;
}
input, textarea, select {
font-family: inherit;
color: var(--cds-text-primary);
}
/* ============================================================================
App shell — shared "UI Shell" chrome (Prime Controls, IBM Carbon styling)
----------------------------------------------------------------------------
One dark top bar across every page so the suite reads as a single product.
The Prime Controls logo is a white-background wordmark, so it sits inside a
white "chip" on the near-black bar (reads as intentional, not a stray box).
Flip --wp-appbar-bg to a light value if a light header is ever preferred.
============================================================================ */
:root {
--wp-appbar-bg: #161616; /* near-black UI Shell bar */
--wp-appbar-fg: #ffffff;
--wp-appbar-fg-dim: #c6c6c6;
--wp-appbar-border: #6f6f6f; /* outline for ghost buttons on the bar */
--wp-appbar-hover: #353535;
--wp-appbar-height: 48px;
}
.wp-appbar {
background: var(--wp-appbar-bg);
color: var(--wp-appbar-fg);
display: flex;
align-items: center;
gap: 16px;
height: var(--wp-appbar-height);
padding: 0 16px;
position: sticky;
top: 0;
z-index: 100;
}
.wp-appbar-brand {
display: flex;
align-items: center;
gap: 12px;
height: 100%;
text-decoration: none;
color: var(--wp-appbar-fg);
}
.wp-appbar-brand:hover { text-decoration: none; opacity: .92; }
.wp-logo-chip {
display: inline-flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 4px;
padding: 4px 8px;
}
.wp-logo-chip img { height: 24px; width: auto; display: block; }
.wp-appbar-title {
font-size: 15px;
font-weight: 600;
color: var(--wp-appbar-fg);
white-space: nowrap;
letter-spacing: .01em;
}
.wp-appbar-title .wp-appbar-sub { font-weight: 400; color: var(--wp-appbar-fg-dim); }
.wp-appbar-spacer { flex: 1 1 auto; }
.wp-appbar-meta { font-size: 13px; color: var(--wp-appbar-fg-dim); white-space: nowrap; }
.wp-appbar-actions { display: flex; align-items: center; gap: 8px; }
/* Buttons and links that live on the dark bar */
.wp-appbar-btn {
background: transparent;
color: var(--wp-appbar-fg);
border: 1px solid var(--wp-appbar-border);
border-radius: 0;
padding: 7px 14px;
font-size: 14px;
font-family: inherit;
line-height: 1.2;
cursor: pointer;
text-decoration: none;
white-space: nowrap;
transition: background .15s, border-color .15s;
}
.wp-appbar-btn:hover { background: var(--wp-appbar-hover); color: var(--wp-appbar-fg); text-decoration: none; }
.wp-appbar-btn.primary { background: var(--cds-interactive-01); border-color: var(--cds-interactive-01); }
.wp-appbar-btn.primary:hover { background: var(--cds-hover-primary); border-color: var(--cds-hover-primary); }
.wp-appbar-btn:focus-visible { outline: 2px solid var(--wp-appbar-fg); outline-offset: 1px; }
.wp-appbar-count { font-size: 13px; color: var(--wp-appbar-fg-dim); padding: 0 2px; white-space: nowrap; }
/* Plain text links on the dark bar (Overview / Feedback / Help, Admin, etc.) */
.wp-appbar-link { color: var(--wp-appbar-fg-dim); text-decoration: none; font-size: 14px; white-space: nowrap; }
.wp-appbar-link:hover { color: var(--wp-appbar-fg); text-decoration: none; }
@media (max-width: 720px) {
.wp-appbar { height: auto; flex-wrap: wrap; gap: 8px; padding: 8px 12px; }
.wp-appbar-actions { flex-wrap: wrap; }
.wp-appbar-meta { width: 100%; order: 5; }
}