# LotusGuild Aesthetic Diff — Convergence Guide Cross-app analysis of every divergence between Tinker Tickets (PHP), PULSE (Node.js), and GANDALF (Flask) that prevents a unified aesthetic. Each section lists the current state in each app, then the **target state** from the unified design system (`web_template/base.css`). --- ## 1. CSS Custom Property Names The biggest source of divergence. Gandalf uses entirely different variable names. | Property | Tinker Tickets | PULSE | GANDALF | **Target** | |---|---|---|---|---| | Main background | `--bg-primary: #0a0a0a` | `--bg-primary: #0a0a0a` | `--bg: #0a0a0a` | `--bg-primary` | | Surface | `--bg-secondary: #1a1a1a` | `--bg-secondary: #1a1a1a` | `--bg2: #1a1a1a` | `--bg-secondary` | | Raised surface | `--bg-tertiary: #2a2a2a` | `--bg-tertiary: #2a2a2a` | `--bg3: #2a2a2a` | `--bg-tertiary` | | Primary green | `--terminal-green: #00ff41` | `--terminal-green: #00ff41` | `--green: #00ff41` | `--terminal-green` | | Green tint | `--terminal-green-dim` | `--terminal-green-dim` | `--green-dim: rgba(0,255,65,.15)` | `--terminal-green-dim` | | Amber | `--terminal-amber: #ffb000` | `--terminal-amber: #ffb000` | `--amber: #ffb000` | `--terminal-amber` | | Amber tint | `--terminal-amber-dim` | `--terminal-amber-dim` | `--amber-dim` | `--terminal-amber-dim` | | Cyan | `--terminal-cyan: #00ffff` | `--terminal-cyan: #00ffff` | `--cyan: #00ffff` | `--terminal-cyan` | | Red | `--terminal-red: #ff4444` | `--terminal-red: #ff4444` | `--red: #ff4444` | `--terminal-red` | | Body text | `--text-primary` | `--text-primary` | `--text` | `--text-primary` | | Dim text | `--text-secondary` | `--text-secondary` | `--text-dim` | `--text-secondary` | | Muted text | `--text-muted: #00bb33` | `--text-muted: #008822` | `--text-muted: #00bb33` | `--text-muted: #00bb33` | | Border | `--border-color` | `--border-color` | `--border: rgba(0,255,65,.35)` | `--border-color` | | Glow (green) | `--glow-green` | `--glow-green` | `--glow` | `--glow-green` | | Glow (amber) | `--glow-amber` | `--glow-amber` | `--glow-amber` | `--glow-amber` ✓ | | Font | `--font-mono` | `--font-mono` | `--font` | `--font-mono` | ### Fix for GANDALF (`style.css`) Add these aliases at the top of `:root` (keeps existing rules working): ```css :root { /* Aliases to match unified naming */ --bg-primary: var(--bg); --bg-secondary: var(--bg2); --bg-tertiary: var(--bg3); --terminal-green: var(--green); --terminal-green-dim:var(--green-dim); --terminal-amber: var(--amber); --terminal-amber-dim:var(--amber-dim); --terminal-cyan: var(--cyan); --terminal-red: var(--red); --text-primary: var(--text); --text-secondary: var(--text-dim); --border-color: var(--border); --glow-green: var(--glow); --font-mono: var(--font); --text-muted: #00bb33; /* override GANDALF's #008822 — too dark */ } ``` Then migrate GANDALF's new code to use unified names. Remove aliases on next major refactor. --- ## 2. Border Width & Style | Context | Tinker Tickets | PULSE | GANDALF | **Target** | |---|---|---|---|---| | Standard card / panel | `2px solid` | `2px solid` | `1px solid` | `2px solid` | | Modal | `3px double` | `3px double` | `1px solid` | `3px double` | | Table outer | `2px solid` | — | none | `2px solid` | | Input fields | `2px solid` | `2px solid` | `1px solid` | `2px solid` | | Button | `2px solid` | `2px solid` | `1px solid` (`.btn-sm`) | `2px solid` | **Change required in GANDALF:** Increase `.modal`, `.host-card`, `.data-table`, `.form-group input/select`, `.btn-sm` border widths from `1px` to `2px`. The `1px` borders make elements look fragile compared to the other apps. ```css /* GANDALF style.css — search & replace */ .modal { border: 1px solid → border: 3px double } .host-card { border: 1px solid → border: 2px solid } .form-group input, .form-group select { border: 1px solid → border: 2px solid } .btn-sm { border: 1px solid → border: 2px solid } ``` --- ## 3. Button Pattern | Aspect | Tinker Tickets | PULSE | GANDALF | **Target** | |---|---|---|---|---| | Bracket decoration | `[ text ]` via `::before`/`::after` | `[ text ]` via `::before`/`::after` | `> text` (primary only), no brackets on most buttons | `[ text ]` via `::before`/`::after` | | Hover transform | `translateY(-2px)` | `translateY(-2px)` | none | `translateY(-2px)` | | Hover animation | `pulse-glow-box 1.5s infinite` | none | none | none (lift is sufficient) | | Padding (standard) | `10px 20px` | `12px 24px` | `6px 14px` (`.btn`) | `10px 20px` | | Padding (small) | `5px 10px` | `6px 12px` | `2px 8px` | `5px 10px` | | Font size | `0.9rem` | `1em` | `0.72em–0.8em` | `0.9rem` | | Text transform | uppercase | uppercase | uppercase | uppercase | **Change required in GANDALF:** Add `::before`/`::after` bracket decorations to all `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-danger` classes. Add `translateY(-2px)` hover transform. Increase padding. ```css /* GANDALF — add to existing .btn rules */ .btn::before { content: '[ '; } .btn::after { content: ' ]'; } .btn:hover { transform: translateY(-2px); } /* Adjust .btn-primary::before to '> ' instead of '[ ' for visual differentiation */ .btn-primary::before { content: '> '; } ``` --- ## 4. Glow Definition Consistency | App | Green glow | Amber glow | |---|---|---| | Tinker Tickets | `0 0 5px #00ff41, 0 0 10px #00ff41, 0 0 15px #00ff41` (3-layer solid) | `0 0 5px #ffb000, 0 0 10px #ffb000, 0 0 15px #ffb000` | | PULSE | Identical to Tinker Tickets | Identical | | GANDALF | `0 0 5px #00ff41, 0 0 10px rgba(0,255,65,.4)` (2-layer, rgba 2nd) | `0 0 5px #ffb000, 0 0 10px rgba(255,176,0,.4)` | GANDALF's 2-layer glow is slightly softer. Both look fine, but they appear different on the same screen if pages are compared side-by-side. **Change required in GANDALF:** Update glow definitions to match the 3-layer solid stack: ```css /* GANDALF style.css */ :root { --glow: 0 0 5px #00ff41, 0 0 10px #00ff41, 0 0 15px #00ff41; --glow-xl: 0 0 8px #00ff41, 0 0 16px #00ff41, 0 0 24px #00ff41, 0 0 32px rgba(0,255,65,.5); --glow-amber: 0 0 5px #ffb000, 0 0 10px #ffb000, 0 0 15px #ffb000; } ``` --- ## 5. Section Header Pattern | App | Syntax | Example | |---|---|---| | Tinker Tickets | `╠═══ TITLE ═══╣` | Symmetric, double-bar bookends | | PULSE | `═══ TITLE ═══` (via h3::before/after) | No `╠` character | | GANDALF | `╠══ TITLE` (one-sided) | Only left bookend, no right | **Change required in PULSE and GANDALF:** Standardise to `╠═══ TITLE ═══╣`. PULSE (`index.html`, all `h3::before`/`h3::after`): ```css /* PULSE: update h3 pseudo-elements */ h3::before { content: '╠═══ '; color: var(--terminal-green); } h3::after { content: ' ═══╣'; color: var(--terminal-green); } ``` GANDALF (`style.css`, `.section-title`): ```css /* GANDALF: add right bookend */ .section-title::after { content: ' ═══╣'; color: var(--green); } ``` --- ## 6. Modal Border Style | App | Border | Box shadow | |---|---|---| | Tinker Tickets | `3px double var(--terminal-green)` | none | | PULSE | `3px double var(--terminal-green)` | `0 0 30px rgba(0,255,65,.3)` | | GANDALF | `1px solid var(--green)` | `0 0 30px rgba(0,255,65,.18)` | **Change required in GANDALF:** Upgrade to `3px double` and add PULSE-style glow: ```css .modal { border: 3px double var(--green); box-shadow: 0 0 30px rgba(0, 255, 65, 0.2), 0 8px 40px rgba(0,0,0,0.8); } ``` --- ## 7. Modal Corner Characters | App | Top corners | Notes | |---|---|---| | Tinker Tickets | `╔ ╗` (double-line) | Matches `3px double` border | | PULSE | `╔ ╗` (double-line) | Matches `3px double` border | | GANDALF | `┌ ┐` (single-line) | Doesn't match — should be `╔ ╗` for modals | **Change required in GANDALF:** ```css .modal::before { content: '╔'; } .modal::after { content: '╗'; } ``` --- ## 8. Toast Position & Animation | Aspect | Tinker Tickets | PULSE | GANDALF | **Target** | |---|---|---|---|---| | Position | `bottom: 1rem; right: 1rem` | `top: 80px; right: 20px` | `bottom: 20px; right: 20px` | `bottom: 1rem; right: 1rem` | | Slide direction | from bottom | from top | from right | from right (`translateX(30px)`) | | Animation duration | `0.3s ease` | `0.3s ease-out` | `0.15s ease` | `0.2s ease-out` | | Auto-dismiss | 3500ms | 3000ms | 3500ms | `3500ms` | | Icon format | `>> ` prefix | `✓/✗/ℹ` prefix (inline style) | `>> ` prefix | `>> ` prefix + icon in `.lt-toast-icon` | | Queue system | Yes (serialised) | No (stacks) | No (stacks) | Yes (serialised) | **Change required in PULSE:** Move toast position to `bottom: 20px; right: 20px`. Replace inline-style notification function with `.lt-toast` classes. **Change required in GANDALF:** Already close — update animation to `slide-in-right` instead of `slide-in` (which slides from left in Gandalf's current implementation). --- ## 9. Table Cell Borders | App | Approach | |---|---| | Tinker Tickets | `border: 1px solid var(--border-color)` on every `` — full grid | | PULSE | Minimal table usage; when present, `border-bottom` only | | GANDALF | `border-collapse: collapse` + `border-bottom: 1px solid rgba(0,255,65,.08)` row-only | Both approaches are valid for different use cases. The design system provides both: - `.lt-table` → full-grid borders (Tinker Tickets style, simple data) - `.lt-data-table` → row-only borders (GANDALF style, dense data) **Action:** Migrate existing tables to the appropriate class. No visual breakage, just choose the right variant per context. --- ## 10. Form Label Colour | App | Label colour | |---|---| | Tinker Tickets | `color: var(--terminal-green)` | | PULSE | `color: var(--terminal-green)` | | GANDALF | `color: var(--amber)` (amber labels) | GANDALF's amber labels create a better visual hierarchy (labels stand out from field values). The unified design system adopts **amber labels** for all apps. **Change required in Tinker Tickets and PULSE:** ```css /* Tinker Tickets: assets/css/dashboard.css + ticket.css */ label, .filter-group h4 { color: var(--terminal-amber); text-shadow: var(--glow-amber); } /* PULSE: index.html inline CSS */ label { color: var(--terminal-amber); } ``` --- ## 11. Nav Link Active State | Aspect | Tinker Tickets | PULSE (tabs) | GANDALF | **Target** | |---|---|---|---|---| | Active colour | amber | amber | amber | amber ✓ | | Active background | `rgba(0,255,65,.08)` | `rgba(0,255,65,.2)` | `rgba(0,255,65,.07)` | `rgba(255,176,0,.15)` (amber tint) | | Active border | green | amber | `border-color: var(--border)` (invisible) | amber | | `[ ]` brackets | on `.btn` but not nav | on `.tab` | on `.nav-link` | on nav links | **Change required in Tinker Tickets:** Add `[ ]` bracket decoration to nav links to match GANDALF. Currently Tinker Tickets has plain nav links without brackets. **Change required in GANDALF:** Use amber tint background on active state instead of green tint: ```css .nav-link.active { background: var(--amber-dim); /* was: var(--green-dim) */ border-color: var(--amber); } ``` --- ## 12. `text-muted` Colour Value | App | Value | Contrast on #0a0a0a | |---|---|---| | Tinker Tickets | `#00bb33` | ~4.8:1 | | PULSE | `#008822` | ~2.9:1 ✗ WCAG AA fail | | GANDALF | `#00bb33` | ~4.8:1 | **Change required in PULSE:** Update `--text-muted` from `#008822` to `#00bb33` to pass WCAG AA contrast. ```css /* PULSE index.html :root */ --text-muted: #00bb33; /* was: #008822 */ ``` --- ## 13. Boot Sequence — Presence & Format | App | Boot sequence | App name in banner | |---|---|---| | Tinker Tickets | Yes — `showBootSequence()` in `DashboardView.php` | "TINKER TICKETS TERMINAL v1.0" | | PULSE | Yes — `showBootSequence()` in `index.html` | "PULSE ORCHESTRATION TERMINAL v1.0" | | GANDALF | **No** | — | **Change required in GANDALF:** Add boot sequence overlay to `base.html`. ```html ``` Plus add `lt.boot.run('GANDALF');` in `app.js` or inline at end of `base.html`. --- ## 14. Status Badge Format | App | Format | Example | |---|---|---| | Tinker Tickets | `[● Open]` — `::before`/`::after` brackets | Brackets are pseudo-elements | | PULSE | `[● Online]` — same pattern | Same | | GANDALF | `.chip::before { content: '['; }` + `.chip::after { content: ']'; }` | Same pattern — different class names | The pattern is consistent. The only issue is **class names** differ: | Component | Tinker Tickets | PULSE | GANDALF | |---|---|---|---| | Full status badge | `.status-Open`, `.status-Closed` | `.status.online`, `.status.failed` | `.chip-critical`, `.chip-ok` | | Small badge | — | `.badge` | `.badge`, `.chip` | **Standardise to** `.lt-status-*` (full badge) + `.lt-chip-*` (compact) + `.lt-badge-*` (inline label) going forward. Existing class names can remain as app-internal aliases. --- ## 15. Scanline Effect Differences All three apps have the same scanline `body::before` and data-stream `body::after`. Minor differences: | Aspect | Tinker Tickets | PULSE | GANDALF | |---|---|---|---| | Scanline opacity | `rgba(0,0,0,0.15)` | `rgba(0,0,0,0.15)` | `rgba(0,0,0,.13)` | | Flicker delay | `30s` | `30s` | `45s` | | Data stream position | `bottom:10px; right:10px` | `bottom:10px; right:10px` | `bottom:10px; right:14px` | These are minor. **Standardise to:** opacity `0.15`, flicker delay `30s`, position `bottom:10px; right:14px`. --- ## 16. Hover Transform on Cards / Items | App | Card hover | List item hover | |---|---|---| | Tinker Tickets | `translateY(-2px)` + glow | `translateY(-2px)` | | PULSE | `translateY(-2px)` | `translateX(3px)` | | GANDALF | `border-color` change only, no transform | `border-left-width` expansion | **Standardise to:** Cards use `translateY(-2px)`. List/row items use `border-left-width` expansion (GANDALF approach, less disorienting for dense lists). --- ## 17. CSS Architecture — Inline vs. External | App | CSS location | |---|---| | Tinker Tickets | External: `assets/css/dashboard.css` + `ticket.css` | | PULSE | **All inline** in `index.html` (`