- Replace stat-card cursor:pointer inline style with CSS rule
- Convert view toggle (table/card) to use .is-hidden CSS class
- Convert bulk-actions and export-dropdown to use .is-visible class
- Add .is-hidden/.is-visible utility rules to dashboard.css
- Remove duplicate lt.keys.initDefaults() call from dashboard.js
- Remove redundant setTimeout from view mode restore
- Add lt.keys.initDefaults() to dashboard.js (was missing entirely)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace all 8 showToast() calls in ApiKeysView.php with lt.toast.*
— all toast calls in the codebase now use lt.toast directly
- Add .duplicate-list, .duplicate-meta, .duplicate-hint CSS classes to
dashboard.css; replace inline styles in duplicate detection JS with them
- Add dashboardAutoRefresh() using lt.autoRefresh — reloads page every
5 minutes, skipping if a modal is open or user is typing in an input
- Add REFRESH button to dashboard header that triggers lt.autoRefresh.now()
for immediate manual refresh with timer restart
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add .inline-error and .inline-warning utility classes to dashboard.css
with correctly-matched terminal palette rgba values (replaces off-palette
rgba(231,76,60,0.1) and rgba(241,196,15,0.1))
- Add .key-generated-alert class for the new API key display frame
- Add base .dependency-item, .dependency-group h4, .dependency-item a,
.dependency-title, .btn-small overrides to ticket.css
- Remove all inline styles from the dependency list template in ticket.js
— layout, colors, and sizing now come from CSS classes
- Update CreateTicketView.php and ApiKeysView.php to use the new classes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add data-ts attributes to TicketView.php: ticket created/updated
header, comment dates (inner span to preserve edited indicator),
and all activity timeline dates
- Add initRelativeTimes() to ticket.js using lt.time.ago(); runs on
DOMContentLoaded and every 60s to keep relative times current
- Attachment dates now use lt.time.ago() with full date in title attr
and ts-cell span for periodic refresh
- Replace all 11 showToast() calls in ticket.js with lt.toast.* directly,
removing reliance on the backwards-compat shim for these paths
- Add span.ts-cell and td.ts-cell CSS to both dashboard.css and ticket.css:
dotted underline + cursor:help signals the title tooltip is available
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove collapsible ASCII banner from dashboard (was cluttering the UI)
- Show ASCII banner in the boot overlay on first session visit, above
the boot messages, with a 400ms pause before messages begin
- Add scroll fade indicator (green-tinted gradient edges) to .table-wrapper
so users can see when the table is horizontally scrollable
- Fix null guards for tab switcher in ticket.js (tabEl, activeBtn)
- Fix Reset → RESET uppercase in AuditLogView and UserActivityView
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set .table-wrapper to overflow-x: auto with touch scrolling support
- Add min-width: 900px to table to trigger scroll before columns collapse
- Set .ascii-frame-outer overflow-x: visible to avoid clipping conflict
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CSS fixes:
- Fix [ ] brackets appearing below button text by replacing display:inline-flex
with display:inline-block + white-space:nowrap on .btn — removes cross-browser
flex pseudo-element inconsistency as root cause
- Remove conflicting .btn::before ripple block (position:absolute was overriding
bracket content positioning)
- Remove overflow:hidden from .btn which was clipping bracket content
- Fix body::after duplicate rule causing GPU layer blink (second position:fixed
rule re-created compositor layer, overriding display:none suppression)
- Replace all transition:all with scoped property transitions in dashboard.css,
ticket.css, base.css (prevents full CSS property evaluation on every hover)
- Convert pulse-warning/pulse-critical keyframes from box-shadow to opacity
animation (GPU-composited, eliminates CPU repaints at 60fps)
- Fix mobile *::before/*::after blanket content:none rule — now targets only
decorative frame glyphs, preserving button brackets and status indicators
- Remove --terminal-green-dim override that broke .lt-btn hover backgrounds
JS fixes:
- Fix all lt.lt.toast.* double-prefix instances in dashboard.js
- Add null guard before .appendChild() on bulkAssignUser select
- Replace all remaining emoji with terminal bracket notation (dashboard.js,
ticket.js, markdown.js)
- Migrate all toast.*() shim calls to lt.toast.* across all JS files
View fixes:
- Remove hardcoded [ ] brackets from .btn buttons (CSS now adds them)
- Replace all emoji with terminal bracket notation in all views and admin views
- Add missing CSP nonces to AuditLogView.php and UserActivityView.php script tags
- Bump CSS version strings to ?v=20260319b for cache busting
Security fixes:
- update_ticket.php: add authorization check (non-admins can only edit their own
or assigned tickets)
- add_comment.php: validate and cast ticket_id to integer with 400 response
- clone_ticket.php: fix unconditional session_start(), add ticket ID validation,
add internal ticket access check
- bulk_operation.php: add HTTP 401/403 status codes on auth failures
- upload_attachment.php: fix missing $conn arg in AttachmentModel constructor
- assign_ticket.php: add ticket existence check and permission verification
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rules: transform/opacity = GPU composited (fine). box-shadow/text-shadow on
hover = CPU repaint (removed). Static box-shadow/text-shadow = painted once (fine).
- Buttons (.btn, .btn-base, button, .btn-primary): add will-change:transform
for pre-promotion, add transform:translateY(-1px) on hover (GPU, no repaint),
scope transition to include transform, remove box-shadow/text-shadow from hover
- Stat cards: add will-change:transform, add transform:translateY(-2px) on hover
- Priority badges: replace filter:blur(6px) ::after pseudo-element (permanent GPU
layer per badge, ~20 on screen at once) with static box-shadow:0 0 6px currentColor
on the badge itself — painted once, never changes, zero compositor overhead
- Links: replace opacity-transition ::after underline (lazy GPU layer creation on
hover) with text-decoration:underline on hover (pure CPU paint, no GPU layer)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chrome promotes ALL position:fixed elements to GPU compositing layers for scroll
performance, regardless of whether they have animations. The body::before scanline
overlay (position:fixed, z-index:9999, full-viewport) and body::after watermark
(position:fixed) were both on GPU layers. Every CPU repaint from any hover state
change required a compositor re-blend pass → one-frame blink at compositor sync.
Fixes:
- Move scanlines from body::before (position:fixed) into body { background-image }
— same visual, no separate element, no GPU layer promotion
- Set body::before { display:none } and body::after { display:none } in both
dashboard.css and base.css
- Remove animation:matrix-rain from .stat-card:hover::before — background-position
animation is not GPU-composited, caused CPU repaints every frame while hovered
plus GPU texture uploads when animation started/stopped on cursor enter/exit
- Scope a { transition: all } → transition: color in base.css
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: removing 'animation' from dashboard.css body::before did NOT disable
the scanline — it just stopped overriding base.css which still had
'animation: scanline 8s linear infinite'. CSS cascade means the base.css value
remained active. Fixed by setting 'animation: none' explicitly in dashboard.css.
Also fix base.css (used by all pages including ticket page):
- Set body::before animation: none (removes GPU compositing layer from scanline)
- Change corner-pulse/subtle-pulse/pulse-glow/pulse-red keyframes from text-shadow
and box-shadow animations to opacity (GPU composited, zero CPU repaint overhead)
- Change exec-running-pulse from box-shadow to opacity
- Remove box-shadow from .lt-table tr:hover, .lt-card:hover, .lt-stat-card:hover
- Remove text-shadow/box-shadow/transform from .lt-btn:hover and variants
- Remove text-shadow from a:hover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change pulse-glow keyframes from text-shadow animation to opacity (GPU composited,
eliminates 60fps CPU repaint that was the likely root cause of the persistent blink)
- Remove box-shadow from .quick-action-btn:hover; scope transition: all → background/color
- Remove box-shadow + background gradient + transform:translateY from .stat-card:hover;
scope transition: all → border-color only
- Remove .stat-card::after transition and hover background change
- Remove duplicate .stat-card:hover transform:translateY block
- Remove box-shadow from .clear-search-btn:hover; scope transition: all → background/color
- Remove text-shadow from th transition (th:hover never changes text-shadow)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove body::before scanline animation (transform: translateY promoted it to a
GPU compositing layer; CPU repaints from hover states required compositor re-blend,
causing one-frame blink at compositor sync boundary)
- Remove text-shadow and transform: translateY(-2px) from .btn-primary:hover/.create-ticket:hover
- Scope .btn-primary transition from 'all' to specific composited properties
- Remove box-shadow: inset from .banner-toggle:hover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These non-composited properties force CPU repaints of the surrounding
paint region (the section itself) every time hover enters or exits.
With the fixed overlay (body::before scanline), each such repaint
requires the compositor to re-blend the layer, visible as a blink.
Removed from dashboard.css:
- btn/button/btn-base:hover: box-shadow + text-shadow
- th:hover: text-shadow
- ticket-link:hover: text-shadow
- pagination button:hover: box-shadow + transform + transition:all
- ticket-card-row:hover: box-shadow + transition:all -> background only
- .btn ripple rule: transition:all -> specific properties
- ascii-frame-outer: removed will-change/translateZ (GPU upload worse)
Removed from ticket.css:
- metadata-select:hover: box-shadow; transition:all -> border-color
- comment:hover: box-shadow
- btn:hover: box-shadow
- mention:hover: text-shadow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The body::before scanline overlay (position:fixed, z-index:9999) requires
the compositor to re-blend over the section every time a CPU repaint
happens inside it. Hover state entry/exit triggers these repaints, causing
a visible blink as the compositor flushes.
Fixes:
- Add will-change:transform + transform:translateZ(0) to ascii-frame-outer
to promote it to its own GPU compositing layer, isolating its repaints
from the scanline compositing pass
- Convert corner-pulse and subtle-pulse from text-shadow (CPU repaint)
to opacity (GPU composited) to eliminate continuous repaint pressure
inside the section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four root causes removed:
- body { transition: all } — forced browser to check all CSS properties
on every hover event across the entire page
- a:not(.btn)::after underline: width+box-shadow transition replaced with
opacity transition — width repaints paint layer, box-shadow forced parent
section repaint; opacity is GPU-composited and doesn't repaint ancestors
- .ticket-link:hover { transform: translateX } — created/destroyed GPU
compositor layer on every ticket ID hover; removed, scoped transition
to specific non-layout properties
- .btn:hover { transform: translateY } in ticket.css — same layer issue
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove pulse-glow-box animation and translateY from button:hover
(infinite animation stopping abruptly caused a flash on mouse-leave)
- Scope button transition from 'all' to specific visual properties
(prevents transform/layout changes from triggering on hover exit)
- Scope th transition from 'all' to background-color + text-shadow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove .ascii-frame-outer:hover flicker animation (caused article to
shake/blink every time cursor entered the ticket container)
- Remove body flicker animation (caused full page blink every 30s)
- Remove deploy.sh (deployment now handled by Gitea CI/CD)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
transition:all was firing on every row simultaneously when the cursor
left the table. Scoped it to background-color only. Also removed the
inset box-shadow from tr:hover which forced repaint layer thrashing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add lt-modal-overlay, lt-modal, lt-btn fallback styles to dashboard.css
so modals are properly hidden (display:none) and styled even when
/web_template/base.css is not yet served. Mirrors the rules from base.css.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- §10: Filter sidebar labels color green→amber with glow-amber,
matching unified amber-for-labels convention from base.css
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mobile bottom nav:
- Added nav-label class to all text labels in JS
- Fixed icon sizing (20px fixed height)
- Fixed label sizing (10px for all)
- Equal width columns (25% each)
- Changed gear emoji from ⚙️ to ⚙ for consistency
Ticket view mobile:
- Removed all borders from ticket container
- Removed decorative corners on mobile
- Reduced nested padding significantly
- ascii-frame-inner now 0.75rem padding (was 1rem)
- Nested ascii-frame-inner only 0.5rem
- detail-group full-width has no padding
- Content goes edge-to-edge
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mobile bottom nav:
- Consistent sizing for icons (1.1rem) and text (0.7rem)
- Added .nav-label class for text labels
- Increased height to 64px for better touch targets
- Added active state styling
Ticket view mobile improvements:
- Full width container (removed margins, no side borders)
- Wider tab content areas with proper padding
- Tabs now fill available width
- Active tab has bottom border indicator
- Description textarea full width with proper sizing
- Markdown preview with better font sizing
- Improved comment form styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added breakpoints:
- 900-1399px: Tablet with sidebar, card layout
- 600-899px: Small tablet, compact cards with actions
- 480-599px: Large phone, hidden sidebar, mobile filter toggle
- Below 768px: Full mobile optimization
Card improvements:
- Better touch targets (48px buttons)
- Clearer visual hierarchy
- Active states for touch feedback
- Priority border indicators
- Clean meta information layout
Mobile improvements:
- Removed card gaps for cleaner list appearance
- Larger fonts for readability
- Better spacing and padding
- Touch-friendly action buttons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major improvements:
- Replace table with card-based layout below 1400px width
- Cards show ticket ID, title, category, assignee, status, and actions
- Priority indicated by left border color
- Fully responsive from 1400px down to mobile
Mobile improvements (768px and below):
- Cards stack vertically with touch-friendly sizing
- Action buttons are full-width with 44px touch targets
- Meta info displayed in a clean row format
- Removed old table-based mobile styles
Sidebar collapse improvements:
- Collapsed state now truly saves space (0 width, no gap)
- Expand button is compact vertical text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sidebar collapse improvements:
- Remove gap when sidebar is collapsed
- Hide sidebar content completely when collapsed
- Make expand button compact (vertical text)
Table responsive improvements:
- Add breakpoints for 1200-1599px and 1000-1199px ranges
- Hide less important columns progressively as screen shrinks
- Ensure table doesn't overflow container with overflow-x: auto
- Reduce padding and font size on smaller screens
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The ::before element on tbody tr was creating a blank column space
that didn't affect the thead, causing visual misalignment.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tbody first column had a 6px left border for priority indicator,
but the thead first column didn't have this border, causing misalignment.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The '> ' prefix was being added to the checkbox header column,
causing misalignment with the data rows.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change overflow-x from auto to visible in table wrapper
- Allow text wrapping in table cells instead of ellipsis truncation
- Remove min-width constraints that forced horizontal scrolling
- Change textarea white-space from pre to pre-wrap
- Remove fixed min-height on ticket container and description
- Update mobile styles to wrap content instead of scroll
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move inline styles to CSS classes in ticket.css and dashboard.css
- Add intermediate responsive breakpoints (600px, 900px, 1200px)
- Convert HTML to semantic elements (header, section, article)
- Add ARIA attributes for modals and navigation
- Add utility classes for text styling and spacing
- Update cache-busting version numbers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comment threading/reply functionality with nested display
- Database migration for parent_comment_id and thread_depth columns
- Recursive comment rendering with depth-based indentation
- Reply form with inline UI and smooth animations
- Thread collapse/expand capability
- Max thread depth of 3 levels
- Fix 401 authentication errors on API calls
- Add credentials: 'same-origin' to all fetch calls
- Affects settings.js, ticket.js, dashboard.js, advanced-search.js
- Ensures session cookies are sent with requests
- Enhanced comment styling
- Thread connector lines for visual hierarchy
- Reply button on comments (up to depth 3)
- Quote block styling for replies
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Keyboard Navigation:
- Add J/K keys for Gmail-style ticket list navigation
- Add N key for new ticket, C for comment focus
- Add G then D for go to dashboard (vim-style)
- Add 1-4 number keys for quick status changes on ticket page
- Add Enter to open selected ticket
- Update keyboard help modal with all new shortcuts
Ticket Age Indicator:
- Show "Last activity: X days ago" on ticket view
- Visual warning (yellow pulse) for tickets idle >5 days
- Critical warning (red pulse) for tickets idle >10 days
Ticket Clone Feature:
- Add "Clone" button on ticket view
- Creates copy with [CLONE] prefix in title
- Preserves description, priority, category, type, visibility
- Automatically creates "relates_to" dependency to original
Active Filter Badges:
- Show visual badges above ticket table for active filters
- Click X on badge to remove individual filter
- "Clear All" button to reset all filters
- Color-coded by filter type (status, priority, search)
Visual Enhancements:
- Add keyboard-selected row highlighting for J/K navigation
- Smooth animations for filter badges
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Removed min-width: 180px from .setting-row label
- Changed min-width: 200px to min-width: 0 for form inputs
- Labels now size to content, inputs fill remaining space
- Updated cache version to 20260126c
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added .setting-row-compact class for stacked label/input layout
- Updated TemplatesView.php grid to use compact rows (3 columns)
- Updated RecurringTicketsView.php grid to use compact rows (2 columns)
- Removed inline style="width: 100%" (handled by CSS now)
- Labels now stack above inputs in grid context for clarity
- Updated cache version to 20260126b
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Template fixes:
- Fixed column name mismatch: use 'default_priority' instead of 'priority'
- Updated manage_templates.php API INSERT and UPDATE queries
- Updated TemplatesView.php to use correct field name in PHP and JS
CSS improvements for .setting-row:
- Better flexbox layout with flex-wrap for responsiveness
- Proper styling for inputs, selects, and textareas in setting rows
- Labels now align to top (better for textareas)
- Added focus states with amber glow effect
- Improved checkbox styling within setting rows
- Better mobile responsive behavior (stacked layout)
- Updated cache version to 20260126a
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comment edit/delete functionality (owner or admin can modify)
- Add edit/delete buttons to comments in TicketView
- Create update_comment.php and delete_comment.php API endpoints
- Add updateComment() and deleteComment() methods to CommentModel
- Show "(edited)" indicator on modified comments
- Add migration script for updated_at column
- Auto-link URLs in plain text comments (non-markdown)
- Add markdown table support with proper HTML rendering
- Preserve code blocks during markdown parsing
- Fix mobile UI elements showing on desktop (add display:none defaults)
- Add mobile styles for CreateTicketView form elements
- Stack status-priority-row on mobile devices
- Update cache busters to v20260124e
- Update Claude.md and README.md documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Dashboard sidebar fixes:
- Added proper styling for sidebar interior on mobile
- Filter groups have touch-friendly labels (44px height)
- Larger checkboxes (22px)
- Full-width apply/clear buttons
- Border separators between filter groups
Ticket page fixes:
- Metadata fields stack vertically on mobile
- Assignment dropdown full-width
- All selects have 48px height and 16px font
- Better spacing throughout
- Sticky header
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major mobile improvements:
- Sticky header with simplified controls
- Slide-out filter sidebar with overlay
- Bottom navigation bar (Home, Filter, New, Settings)
- Stacked toolbar layout
- Full-width modals sliding up from bottom
- Admin dropdown as bottom sheet
- Horizontal scrolling table with touch support
- 44px minimum touch targets throughout
- iOS zoom prevention on inputs
- Landscape mode optimizations
CSS changes:
- Rewrote all mobile styles with correct class names
- Added mobile bottom nav styles
- Fixed toolbar-left, toolbar-center, toolbar-right
- Fixed user-header-left, user-header-right
JS changes:
- initMobileSidebar now creates bottom nav
- Removed style.display = 'none' (CSS handles visibility)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change session.cookie_samesite from Strict to Lax for Authelia compatibility
- Redesign sidebar toggle with separate collapse/expand buttons
- Add script to create missing ticket_dependencies table
- Add .env.example template
- Add check for missing .env with helpful error message
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix collapsible sidebar toggle button positioning (moved outside sidebar)
- Toggle button now stays visible when sidebar is collapsed
- Update cache busting version
- Update Claude.md with new features documentation
- Update README.md with new features documentation
- Remove migrations folder (no longer needed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin dropdown menu in dashboard header with links to all admin pages
- Fix template modal: larger size (800px), responsive grid, type/priority dropdowns
- Fix recurring tickets modal: add Type and Assign To fields, larger size
- Make dashboard stat cards clickable for quick filtering
- Fix user-activity query (remove is_active requirement)
- Add table existence check in ticket_dependencies API
- Fix table overflow on dashboard
- Update Claude.md and README.md with current project status
- Remove migrations directory (all migrations completed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove is_active filter from get_users.php (column doesn't exist)
- Fix ticket ID validation regex in upload_attachment.php (9-digit format)
- Fix createSettingsModal reference to use openSettingsModal from settings.js
- Add error handling for dependencies tab to prevent infinite loading
- Add try-catch wrapper to ticket_dependencies.php API
- Make export dropdown visible only when tickets are selected
- Export only selected tickets instead of all filtered tickets
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>