TQPro Design Reconciliation Decisions¶
Generated by Claude Code on 2026-04-02.
HOW TO USE THIS FILE¶
- Review every entry in the PROPOSED DECISIONS section.
- For each entry:
- If you agree: write
APPROVEDin the Status field.- If you want a different option: write
OVERRIDE: [your instruction].- If you want to skip this item: write
SKIP.- For entries in NEEDS HUMAN DECISION: make a choice and write
DECISION: [your choice]in the Status field.- When you are done reviewing, save this file and run the Phase 2 apply task.
Do not modify the Findings or Proposed sections -- only fill in Status fields.
Summary¶
Pages audited: 69 (admin portal, excluding 4 legacy/external pages) Inconsistencies found: 42 across 12 categories Consistent categories: 0 (every category has at least one inconsistency) Auto-resolvable (proposed): 37 Needs human decision: 5
High impact: 14 findings (primary pages, every interaction) Medium impact: 18 findings (regular but not constant) Low impact: 10 findings (edge cases, rarely visited pages)
Primary Pages (highest priority for consistency)¶
| # | Page | Type | Module |
|---|---|---|---|
| 1 | index.html |
Dashboard | Core |
| 2 | booking-list.html |
Hub | Booking |
| 3 | booking-detail.html |
Spoke-detail | Booking |
| 4 | booking-wizard.html |
Spoke-form | Booking |
| 5 | booking-cart.html |
Spoke-detail | Booking |
| 6 | groups-list.html |
Hub | Groups |
| 7 | groups-summary.html |
Spoke-detail | Groups |
| 8 | outbound-groups-list.html |
Hub | Groups |
| 9 | outbound-groups-summary.html |
Spoke-detail | Groups |
| 10 | hotel-list.html |
Hub | Hotel |
| 11 | hotel-edit.html |
Spoke-form | Hotel |
| 12 | tripmaker-dash.html |
Dashboard | TripMaker |
| 13 | tripmaker-project.html |
Spoke-detail | TripMaker |
| 14 | offline-tickets-dash.html |
Dashboard | Tickets |
| 15 | visamgmt.html |
Hub | Visa |
Section 1 -- Proposed Decisions¶
D1: CSS variable namespace fragmentation¶
Finding: Every module defines its own CSS custom property prefix for identical values. The primary color #362c5d exists as --primary-color, --blm-primary, --groups-primary, --cruise-primary, --tm-primary across 6 CSS files.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | --primary-color / --primary-dark / --secondary-color | tqadmin.css (shared, ~40 pages) |
| B | --blm-* prefix | booking.css (8 pages) |
| C | --groups-* prefix | groups.css (20 pages) |
| D | --cruise-* prefix | cruise.css (3 pages) |
| E | --ot-* prefix | offline-tickets.css (9 pages) |
| F | --tm-* prefix | tripmaker.css (7 pages) |
Proposed canonical: Variant A -- all modules should reference the shared tokens from tqadmin.css (--primary-color, --primary-dark, --secondary-color, --border-color, --shadow-sm, --shadow-md, --shadow-lg). Module-specific tokens (e.g., --blm-enquiry for booking status colors) remain module-prefixed.
Rationale: Shared brand tokens should have one name; only domain-specific values need prefixes.
Pages that need updating: All module CSS files need token references unified. No HTML changes.
- css/booking.css -- replace --blm-primary with var(--primary-dark) (note: BLM uses #2a2149, the dark variant)
- css/groups.css -- replace --groups-primary, --groups-secondary, --groups-light-bg, --groups-border, --groups-shadow-* with shared tokens
- css/cruise.css -- replace --cruise-primary, --cruise-primary-dark, --cruise-light-bg, --cruise-border, --cruise-shadow-* with shared tokens
- css/offline-tickets.css -- replace --ot-primary (see D2 for the green issue)
- css/tripmaker.css -- replace --tm-primary, --tm-accent with shared tokens
Status: APPROVED
D2: Offline Tickets uses green primary color¶
Finding: offline-tickets.css defines --ot-primary: #2c6e49 (green), diverging from every other module's purple #362c5d. This gives the Offline Tickets module a completely different color identity.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Purple #362c5d | 60 pages (all modules except offline-tickets) |
| B | Green #2c6e49 | 9 pages (offline-tickets-*) |
Proposed canonical: Variant A -- use the shared purple #362c5d as primary across all modules.
Rationale: Majority wins. A single module having a different primary color breaks application identity. Module differentiation should use icons and content, not primary colors.
Pages that need updating:
- css/offline-tickets.css -- change --ot-primary to reference var(--primary-color) or #362c5d
- All 9 offline-tickets-*.html pages may have hover/accent colors affected
Status: APPROVED
D3: Cruise secondary color diverges (light blue vs amber)¶
Finding: cruise.css defines --cruise-secondary: #4fc3f7 (light blue) while the global secondary is #FFC166 (amber/gold). Groups and TripMaker correctly use amber.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Amber #FFC166 | ~60 pages |
| B | Light blue #4fc3f7 | 3 pages (cruise) |
Proposed canonical: Variant A -- amber #FFC166 for the shared secondary token. Cruise can keep #4fc3f7 as a domain-specific accent (--cruise-accent) if needed.
Rationale: Majority wins; the global brand secondary is amber.
Pages that need updating:
- css/cruise.css -- rename --cruise-secondary to --cruise-accent and add --secondary-color reference from shared tokens
Status: APPROVED
D4: Success color split (#3adb76 vs #198754)¶
Finding: tqadmin.css defines --success-color: #3adb76 (Foundation-era bright green). All module CSS files use #198754 (Bootstrap 5 green) or Bootstrap's bg-success.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | #3adb76 (Foundation green) | tqadmin.css definition (but rarely used directly) |
| B | #198754 (Bootstrap 5 green) | All module CSS files + Bootstrap bg-success |
Proposed canonical: Variant B -- update tqadmin.css --success-color to #198754 to match Bootstrap 5 and all module usage.
Rationale: Bootstrap default wins when tied; B is used by all modules and matches Bootstrap's bg-success.
Pages that need updating:
- css/tqadmin.css -- change --success-color: #3adb76 to --success-color: #198754
Status: APPROVED
D5: Shadow value fragmentation (3 different shadow-sm values)¶
Finding: Three distinct small shadow values in use for the same visual intent.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | 0 2px 4px rgba(0,0,0,0.1) | tqadmin.css (shared definition) |
| B | 0 0.125rem 0.25rem rgba(0,0,0,0.075) | groups.css, cruise.css (Bootstrap standard) |
| C | 0 1px 3px rgba(0,0,0,0.08) | booking.css, offline-tickets.css, tripmaker.css (hardcoded inline) |
Proposed canonical: Variant B -- Bootstrap's standard shadow-sm value. Update --shadow-sm in tqadmin.css to match Bootstrap convention.
Rationale: Bootstrap default wins. Using Bootstrap's value ensures consistency with any Bootstrap shadow-sm utilities used elsewhere.
Pages that need updating:
- css/tqadmin.css -- update --shadow-sm to 0 0.125rem 0.25rem rgba(0,0,0,0.075)
- css/booking.css, css/offline-tickets.css, css/tripmaker.css -- replace hardcoded shadow values with var(--shadow-sm)
Status: APPROVED
D6: CSS include sets diverge across modules¶
Finding: Pages load different combinations of CSS files. Offline Tickets pages skip tqadmin.css entirely. Groups pages skip both tqapp.css and tqadmin.css. Dashboard and visamgmt use massive inline styles instead.
Variants found: | Variant | Description | Pages using it | |---------|-------------|---------------| | A | Bootstrap + tqapp + tqadmin + module CSS | 30 pages (booking, hotel, tripmaker, cruise) | | B | Bootstrap + tqapp + module CSS (no tqadmin) | 9 pages (offline-tickets) | | C | Bootstrap + module CSS only (no tqapp, no tqadmin) | 20 pages (groups) | | D | Bootstrap + tqapp + massive inline styles | 3 pages (index, visamgmt, offerman) |
Proposed canonical: Variant A -- all pages should load tqapp.css + tqadmin.css + their module CSS. Shared component styles (content-card, data-table-wrapper, status-badge, form-section, etc.) live in tqadmin.css and should not be redefined in module CSS.
Rationale: The shared library exists to prevent duplication. Modules that bypass it end up reimplementing the same components with subtle differences.
Pages that need updating:
- All 9 offline-tickets-*.html -- add <link rel="stylesheet" href="css/tqadmin.css">
- All 20 groups-*.html + outbound-groups-*.html -- add <link rel="stylesheet" href="css/tqapp.css"> and <link rel="stylesheet" href="css/tqadmin.css">
- index.html, visamgmt.html -- extract inline styles to external CSS and add tqadmin.css
Status: APPROVED
D7: Body class scoping convention¶
Finding: Pages use 5 different body class strategies for CSS scoping.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | booking-page | 8 pages |
| B | groups-page | 20 pages |
| C | cruise-page | 3 pages |
| D | hotel-page | 9 pages |
| E | tqadmin | 2 pages (offerman, mktplan) |
| F | No body class | ~27 pages (tripmaker, offline-tickets, index, visamgmt, etc.) |
Proposed canonical: All pages should use a body class following the pattern tq-{module} (e.g., tq-booking, tq-hotel, tq-groups, tq-cruise, tq-tripmaker, tq-tickets, tq-admin). Pages with no class should add one.
Rationale: Consistent namespacing enables module-specific CSS overrides without class name collisions. The tq- prefix avoids conflicts with frameworks.
Pages that need updating: All ~27 pages without a body class need one added. Existing pages need rename (e.g., booking-page -> tq-booking).
Status: APPROVED
D8: Breadcrumb wrapper class¶
Finding: 6 different breadcrumb wrapper class patterns exist.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | nav.blm-breadcrumb.d-print-none | 8 booking pages |
| B | nav.groups-breadcrumb (sometimes + d-print-none) | 20 groups pages |
| C | nav.cruise-breadcrumb.d-print-none | 3 cruise pages |
| D | nav.tm-breadcrumb.d-print-none | 7 tripmaker pages |
| E | nav.ot-breadcrumb (no d-print-none) | 9 offline-tickets pages |
| F | nav.d-print-none or bare nav (no custom class) | 6 hotel + settings pages |
| G | nav.hotel-breadcrumb.d-print-none | 2 hotel package pages |
| H | No breadcrumb | 5 pages (index, visamgmt, visa-download, ticket-download, hotel sub-pages) |
Proposed canonical: Unified class nav.tq-breadcrumb.d-print-none for all pages that have breadcrumbs. Defined once in tqadmin.css. Hotel sub-pages should use their hotel-subnav pattern (this is intentionally different -- it's a sub-navigation, not a breadcrumb).
Rationale: A single breadcrumb class eliminates 7 duplicate CSS definitions and ensures consistent padding, shadow, and border-radius across all pages.
Pages that need updating: All pages with module-prefixed breadcrumb classes (~49 pages). CSS: merge all breadcrumb styles into one .tq-breadcrumb definition in tqadmin.css.
Status: APPROVED
D9: Breadcrumb home icon inconsistency¶
Finding: Some breadcrumbs start with a house icon + "Dashboard", others have text-only links, and offline-tickets breadcrumbs have no home icon at all.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | bi bi-house-door icon + "Dashboard" linking to index.html | ~25 pages (booking, tripmaker, hotel-list, cruise, outbound-groups-list) |
| B | bi bi-people or bi bi-airplane icon + module list link | ~18 pages (groups/outbound sub-pages) |
| C | Text-only "Dashboard" link, no icon | 9 pages (offline-tickets) |
| D | Text-only link to module list, no icon | 2 pages (terms-templates, action-templates) |
Proposed canonical: Variant A for root/hub pages (icon + "Dashboard"). Variant B for sub-pages (module icon + module list name). All breadcrumbs should include an icon on the first item.
Rationale: Icons provide visual anchoring. The house icon for dashboard and module icon for sub-pages is the clearest pattern already used by the majority.
Pages that need updating:
- 9 offline-tickets pages -- add bi bi-house-door icon to "Dashboard" link
- terms-templates.html, action-templates.html -- add home icon
Status: APPROVED
D10: Page header h-tag level¶
Finding: Pages use h1, h2, h4, h5, or no heading at all for the page title.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | h5.mb-0 or h5.mb-3 | 18 pages (booking sub-pages, hotel sub-pages, offline-tickets-dash) |
| B | h4.mb-0 or h4.mb-1 | 14 pages (hotel-list, tripmaker sub-pages, settings, groups-summary, outbound-summary) |
| C | h4.content-card-title inside content-card | 8 inbound groups sub-pages |
| D | h2 bare | 12 outbound groups sub-pages |
| E | h1 | 1 page (outbound-groups-list) |
| F | No heading | 6+ pages (dashboards with KPI-only headers, booking-list, booking-maintenance) |
Proposed canonical: h4.mb-0 for all page titles. Place inside a div.d-flex.align-items-center.mb-3 with action buttons via ms-auto. Do not wrap in a content-card for the page-level header.
Rationale: h4 is used by the most page types. h5 is too small for a page title; h1/h2 are semantically reserved for the app name/section.
Pages that need updating:
- 18 pages using h5 -- change to h4
- 12 outbound pages using h2 -- change to h4
- 1 page using h1 (outbound-groups-list) -- change to h4
- 8 inbound groups pages -- remove content-card wrapper from page header, use bare h4
- ~6 pages with no heading -- add h4 title
Status: APPROVED
D11: Primary action button color class¶
Finding: The main CTA button on each page uses different Bootstrap color classes.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | btn-success (green) | Booking (New Booking), hotel (Save, Add Room), inbound groups (Add *), outbound-invoicing, some TM |
| B | btn-primary (blue) | Outbound groups (all sub-pages), inbound list (New Group), search buttons, OT (Upload) |
Proposed canonical: btn-primary for navigation/creation actions ("New Booking", "New Group", "Add Passenger"). btn-success for save/confirm/checkout actions ("Save Hotel", "Checkout", "Confirm"). btn-outline-danger for destructive actions. btn-outline-secondary for cancel/back.
Rationale: Semantic color mapping: primary = initiate new action, success = commit/save, danger = destructive. This is the Bootstrap convention and aligns with user expectations.
Pages that need updating:
- Booking-list: change "New Booking" from btn-success to btn-primary
- Inbound groups sub-pages: change "Add " from btn-success to btn-primary
- Outbound groups sub-pages: keep btn-primary for "Add " (already correct)
- Hotel pages: keep btn-success for "Save" (already correct)
Status: APPROVED
D12: Primary action button size class¶
Finding: Button sizes are inconsistent across pages.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | btn-sm (small) | Booking pages, inbound groups sub-pages, offline-tickets, some settings |
| B | No size modifier (default) | Hotel pages, outbound groups sub-pages, search buttons |
| C | btn-lg (large) | 1 page (outbound-groups-list) |
Proposed canonical: Variant A (btn-sm) for action buttons within table headers, filter bars, and card headers. Variant B (default size) for standalone page-level primary actions and modal submit buttons. Never use btn-lg.
Rationale: Small buttons fit compact data-dense layouts (tables, filters). Default-size buttons for standalone actions have better click targets. btn-lg is out of proportion.
Pages that need updating:
- outbound-groups-list.html -- change btn-lg to default (no size)
Status: APPROVED
D13: Table class combination¶
Finding: Tables use different combinations of Bootstrap table classes.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | table table-hover table-sm | 15 pages (booking, hotel-packages, offline-tickets-reservations) |
| B | table table-hover table-sm align-middle | 6 pages (booking-list, booking-maintenance, hotel-packages, outbound-flights, outbound-expenses) |
| C | table data-table (custom groups class, no hover/sm) | 8 pages (inbound groups, outbound pricing/invoicing) |
| D | table table-hover (no sm) | 5 pages (offline-tickets-dash, attractions, inventory) |
| E | Custom class only (itin-table, cost-table, enhanced-table) | 4 pages (cruise, tripmaker-costs, visamgmt) |
Proposed canonical: table table-hover table-sm align-middle as the standard table class set. Wrapped in div.table-responsive.
Rationale: table-hover provides row feedback, table-sm uses space efficiently in data-dense admin UIs, align-middle ensures consistent vertical alignment. table-responsive prevents horizontal overflow.
Pages that need updating:
- 8 groups pages using data-table -- add table-hover table-sm align-middle
- 5 offline-tickets pages missing table-sm -- add it
- 4 pages with custom-only classes -- add Bootstrap base classes alongside custom classes
Status: APPROVED
D14: Table header (thead) styling¶
Finding: Table headers use different background approaches.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | thead.table-light (Bootstrap class) | 20+ pages (booking, hotel-packages, outbound-flights, offline-tickets-reservations) |
| B | CSS gradient via .data-table thead | 8 pages (groups) |
| C | No thead styling | 10+ pages (hotel-list, hotel-meals, hotel-supplier-import, some OT pages) |
Proposed canonical: Variant A -- thead.table-light on all tables.
Rationale: Bootstrap default wins. Simple, consistent, no custom CSS needed.
Pages that need updating:
- 8 groups pages -- add table-light class to <thead> (CSS gradient can remain as progressive enhancement)
- ~10 pages with unstyled thead -- add table-light
Status: APPROVED
D15: Table empty state¶
Finding: Three different empty-state patterns exist for tables.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Separate div.blm-empty-state/tm-empty-state/ot-empty-state with icon + heading + CTA | 10 pages (booking, tripmaker, offline-tickets dashboards) |
| B | GroupUtils.renderEmptyState() with icon + h3 + message + CTA | 12 pages (outbound groups) |
| C | Inline <tr><td colspan="N" class="text-center text-muted py-3">message</td></tr> | 25+ pages |
Proposed canonical: Both Pattern A/B for page-level empty states (when the entire page has no content) and Pattern C for table-level empty states (when a specific table within a page has no rows). Unify the CSS class to a single .tq-empty-state defined in tqadmin.css.
Rationale: Page-level and table-level empty states serve different purposes and can coexist. The structural pattern should be standardized.
Pages that need updating:
- Rename all module-prefixed empty-state classes (.blm-empty-state, .tm-empty-state, .ot-empty-state, .cruise-empty-state) to .tq-empty-state
- Standardize colspan row padding to py-3 everywhere
Status: APPROVED
D16: KPI card accent pattern (border-top vs border-left)¶
Finding: KPI/stat cards use two different color accent placements.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | border-top: 3px solid | 4 modules (booking, tripmaker, offline-tickets -- 20+ pages) |
| B | border-left: 4px solid | 1 module (cruise -- 3 pages) |
Proposed canonical: Variant A -- border-top: 3px solid accent.
Rationale: Majority wins (4:1 modules). Unify class name to .tq-kpi-card in tqadmin.css.
Pages that need updating:
- css/cruise.css -- change .kpi-card from border-left to border-top
- All KPI card classes (.blm-kpi-card, .ot-kpi-card, .tm-kpi-card, .kpi-card) -- rename to .tq-kpi-card
Status: OVERRIDE - user variant B, as left-border KPI cards feel nicer. Additional: Unify KPI card content outlook as well, keep the KPI cards as low-height (non-intrusive and not taking a lot of screen real-estate).
D17: Card shadow values¶
Finding: Content cards use 3 different shadow values (see D5 for the token issue). Beyond tokens, some cards have no shadow at all.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | var(--shadow-sm) from tqadmin | ~15 pages |
| B | Inline 0 1px 3px rgba(0,0,0,0.08) | ~20 pages (booking, tripmaker, offline-tickets) |
| C | No shadow (default Bootstrap card) | ~15 pages (hotel sub-pages, standard card usage) |
Proposed canonical: All .tq-* component cards use var(--shadow-sm). Standard Bootstrap card elements keep Bootstrap's default (no shadow unless shadow-sm utility is added).
Rationale: Custom component cards (KPI, filter, breadcrumb) get the shadow token. Standard Bootstrap cards are left as-is to avoid overriding a framework class.
Pages that need updating: Handled by D1/D5 token unification. No additional HTML changes.
Status: APPROVED¶
D18: Filter bar wrapper class¶
Finding: Filter bars use 5 different CSS classes.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | .blm-filter-bar | 2 pages (booking-list, booking-maintenance) |
| B | .filter-panel | 3 pages (outbound-groups-list, outbound-groups-passengers) |
| C | .tm-filter-bar | 1 page (tripmaker-dash) |
| D | .ot-filter-bar | 3 pages (offline-tickets-inventory, etc.) |
| E | Bootstrap card with inline filter controls | 8 pages (hotel, offline-tickets-reservations, etc.) |
Proposed canonical: Unified class .tq-filter-bar defined in tqadmin.css. Uses d-flex align-items-center gap-2 flex-wrap layout. Defined once with consistent padding, shadow, and border-radius.
Rationale: Eliminates 4 duplicate definitions. Same visual pattern across all modules.
Pages that need updating: All pages with module-prefixed filter bars (~9 pages). CSS: consolidate into one .tq-filter-bar definition.
Status: APPROVED
D19: Status badge CSS system (3 systems)¶
Finding: Status badges use three completely different CSS approaches.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Custom CSS classes (badge-ENQUIRY, badge-CONFIRMED etc.) with CSS variables | 8 booking pages |
| B | Standard Bootstrap bg-* classes (bg-success, bg-warning, bg-danger) | ~50 pages (groups, cruise, tripmaker, offline-tickets, hotel) |
| C | Custom status-badge status-* classes from tqadmin.css | 3 pages (visamgmt, mktplan, offerman) |
Proposed canonical: Variant B -- Bootstrap bg-* classes for all status badges, supplemented by a shared getStatusBadgeClass(status) utility function in a new tq-status-utils.js module.
Rationale: Bootstrap bg-* is used by 80%+ of pages. No custom CSS needed -- the framework provides the colors. The booking module's custom CSS variables add maintenance burden without visual benefit.
Pages that need updating:
- css/booking.css -- remove custom badge-* class definitions
- js/modules/booking-common.js -- update STATUS_COLORS to use Bootstrap bg-* classes
- visamgmt.html -- replace inline status-badge CSS with Bootstrap badges
- css/tqadmin.css -- remove .status-badge definitions (or keep as deprecated)
Status: OVERRIDE - accept variant B as proposed, but do not split JS utilities (do not create a separate tq-status-utils.js file); keep the visual utilities in a single JS file to improve caching.
D20: Status badge text casing¶
Finding: Status text is displayed with 5 different casing conventions.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Title Case via lookup ("Option Held", "Enquiry") | 8 booking pages |
| B | Raw UPPERCASE ("CONFIRMED", "DRAFT") | ~30 pages (groups, tripmaker, offline-tickets, hotel) |
| C | Title Case from server ("Draft", "Active") | 3 cruise pages |
| D | UPPERCASE via CSS text-transform | 3 pages (visamgmt) |
| E | Sentence case with hyphens ("Payment pending") | 1 page (cruise-agt-book) |
Proposed canonical: Title Case via a shared formatStatusLabel(status) function that converts "OPTION_HELD" to "Option Held", "IN_PREPARATION" to "In Preparation", etc.
Rationale: Title Case is the most readable convention for status labels. Raw UPPERCASE is harder to scan; CSS text-transform can be applied but is better handled in JS for consistency.
Pages that need updating: All modules displaying raw UPPERCASE status values (~30 pages). Add formatStatusLabel() to shared utility.
Status: APPROVED
D21: Container width and margin-top¶
Finding: The main content container uses 4 different width strategies and one page has a different margin-top.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | container-fluid + margin-top: 80px | ~45 pages (majority) |
| B | container-fluid groups-container + margin-top: 80px | 20 groups pages |
| C | container-fluid + width: 92%; max-width: 1400px; margin-top: 70px | 1 page (index.html) |
| D | container-fluid + custom margins (margin-left: 2em) | 2 pages (offerman, mktplan) |
Proposed canonical: Variant A for all pages: container-fluid with margin-top: 80px as inline style. Move the 80px to a CSS class (e.g., .tq-main-content { margin-top: 80px; }) to avoid repeating the inline style on every page.
Rationale: Majority pattern. The groups-container adds only padding: 1.5rem which container-fluid already provides. Index.html's narrower width should use the same pattern with an optional max-width class.
Pages that need updating:
- index.html -- change margin-top from 70px to 80px
- offerman.html, mktplan.html -- remove custom margins, use standard container-fluid
- All 20 groups pages -- remove groups-container, keep container-fluid
Status: APPROVED
D22: Required field indicator¶
Finding: Required fields are marked with 3 different patterns.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | * as plain text suffix in label ("Name *") | ~35 pages (booking, hotel, tripmaker, groups, cruise) |
| B | <span class="text-danger">*</span> as red asterisk | 5 pages (terms-templates, action-templates, offline-tickets) |
| C | <span class="required">*</span> with custom CSS | 1 page (visamgmt) |
Proposed canonical: Variant B -- <span class="text-danger">*</span> after the label text.
Rationale: Red asterisk is the most visually clear indicator. Using Bootstrap's text-danger avoids custom CSS. More structured than plain text (can be targeted by CSS).
Pages that need updating: ~35 pages using plain text * need the markup updated. ~1 page using custom .required class.
Status: APPROVED
D23: Form label pattern¶
Finding: Two approaches for associating labels with inputs.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | <label class="form-label">Text</label> then <input> (Bootstrap standard) | ~55 pages |
| B | <label>Text <input></label> (label wraps input) | 5 pages (cruise, offerman, mktplan) |
Proposed canonical: Variant A -- Bootstrap standard pattern with separate label + input, connected via for/id.
Rationale: Bootstrap 5 standard. Better for styling (label and input have independent layout), accessibility (explicit association), and consistency with the rest of the codebase.
Pages that need updating:
- cruise-dash.html, cruise-itin.html, cruise-agt-book.html -- restructure labels
- offerman.html, mktplan.html -- restructure labels
Status: APPROVED
D24: Date formatting (7 implementations, 5 formats)¶
Finding: Dates are displayed in 5 different formats across the admin portal, with 7 independent formatting functions.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | dd-MM-yyyy ("02-04-2026") | Booking, Hotel modules |
| B | Mon d, yyyy ("Apr 2, 2026") | TripMaker, MktPlan |
| C | dd Mon yyyy ("02 Apr 2026") | Offline Tickets, globals.js |
| D | yyyy-MM-dd ("2026-04-02") | Groups (API format, used for display) |
| E | dd.MM ("02.04") | Groups short date |
Proposed canonical: Variant C -- dd Mon yyyy ("02 Apr 2026") for display. Move the canonical formatDate() and formatDateTime() to a shared utility module imported by all modules.
Rationale: Variant C is used by the shared globals.js (formatDisplayDate), making it the implicit standard. It's unambiguous (no dd-MM vs MM-dd confusion) and human-readable.
Pages that need updating:
- Create shared tq-format-utils.js with canonical formatDate(), formatDateTime(), formatCurrency()
- Update booking-common.js, hotel-common.js (dd-MM-yyyy -> dd Mon yyyy)
- Update tripmaker-common.js, mktplan.js (Mon d, yyyy -> dd Mon yyyy)
- Update groups-core.js display format (yyyy-MM-dd -> dd Mon yyyy; keep API format for API calls)
Status: APPROVED
D25: Currency formatting (4 implementations, inconsistent position)¶
Finding: Currency amounts are formatted differently across modules.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | CUR N,NNN.NN (code first: "AED 1,234.56") | Booking, Offline Tickets |
| B | N,NNN.NN CUR (code last: "1,234.56 AED") | Groups |
| C | N,NNN.NN (no currency code) | Hotel |
Proposed canonical: Variant A -- currency code first ("AED 1,234.56"). Include in the shared tq-format-utils.js.
Rationale: Code-first is the international business convention (ISO 4217). Used by the booking module (the most financially complex module). Displaying the currency code is essential in a multi-currency system.
Pages that need updating:
- groups-core.js -- change GroupUtils.formatMoney() to put code first
- hotel-common.js -- add currency code parameter to formatCurrency()
- Move all formatting to shared utility
Status: APPROVED
D26: Loading state pattern (5 patterns, TQ.loading underutilized)¶
Finding: The shared TQ.loading component exists but only 2 of ~40 modules use it. Most modules manually replace button HTML with spinner HTML.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | TQ.loading.button(btn) / TQ.loading.buttonReset(btn) | 2 modules (groups-summary, tripmaker-costs) |
| B | GroupUtils.showLoading() overlay toggle | 20+ pages (groups) |
| C | Manual btn.html('<span class="spinner-border...">Loading...') | 15+ pages (hotel, booking, tripmaker) |
| D | Custom $('#loadingIndicator').toggleClass('d-none') | 10+ pages |
| E | Custom CSS spinner (visamgmt) | 1 page |
Proposed canonical: Use TQ.loading.button(btn) / TQ.loading.wrap(btn, promise) for all button loading states. Use a standardized $('#loadingIndicator') toggle for page-level loading. Deprecate manual spinner HTML replacement.
Rationale: TQ.loading already handles state save/restore correctly. Manual replacements don't restore button state, creating UX bugs on error. Using the shared component is the documented convention.
Pages that need updating: ~25 pages with manual spinner replacements need to switch to TQ.loading.
Status: APPROVED
D27: Pagination implementation (4 implementations, TQ.pagination underutilized)¶
Finding: The shared TQ.pagination component exists but only 1 module uses it. Four custom implementations exist with mixed page indexing.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | TQ.pagination.render() (shared, 0-based) | 1 module (offerman) |
| B | Custom prev/next (0-based, pageSize=25) | 1 page (booking-list) |
| C | Custom numbered pages (1-based, pageSize=20 or 50) | 2 pages (hotel-list, offline-tickets-inventory) |
| D | Server-side prev/next (0-based for flights, 1-based for hotels) | 4 search pages |
Proposed canonical: Use TQ.pagination.render() for client-side pagination. Use TQ.pagination.renderSimple() for server-side pagination. Standardize on 0-based page indexing internally.
Rationale: Shared component exists, is well-designed, and handles edge cases. Custom implementations duplicate functionality.
Pages that need updating:
- booking-list.js -- replace custom pagination with TQ.pagination
- hotel-list.js -- replace custom pagination with TQ.pagination
- offline-tickets-inventory.js -- replace custom pagination with TQ.pagination
Status: APPROVED
D28: SRI (Subresource Integrity) on CDN links¶
Finding: Some pages include SRI hashes on Bootstrap/bootstrap-icons CDN links; others don't.
Variants found: | Variant | Description | Pages using it | |---------|-------------|---------------| | A | SRI integrity + crossorigin attributes present | ~30 pages (booking, hotel, tripmaker, cruise) | | B | No SRI attributes | ~25 pages (offline-tickets, index, visamgmt, etc.) |
Proposed canonical: Variant A -- all CDN links should include SRI integrity hashes and crossorigin="anonymous".
Rationale: SRI prevents supply-chain attacks via CDN compromise. It's a security best practice with no performance cost.
Pages that need updating: ~25 pages missing SRI attributes need them added.
Status: APPROVED - Additional: Backend also generates CDN links - check the backend HTML generation as well.
D29: groups.css redefines content-card with conflicting values¶
Finding: groups.css redefines .content-card, .content-card-header, .content-card-body, .content-card-title, .data-table-wrapper, .form-section, .form-section-title, and .action-btn -- all of which are already defined in tqadmin.css with slightly different values (different padding, shadow, font-size, border-width).
Proposed canonical: Remove the redefinitions from groups.css. Groups pages should use tqadmin.css definitions directly after D6 is applied (adding tqadmin.css to groups pages).
Rationale: The redefinitions exist because groups.css doesn't load tqadmin.css. Once D6 is applied, the duplicates become conflicts rather than replacements.
Pages that need updating: css/groups.css -- remove approximately 150 lines of redefined components.
Status: APPROVED - Additional: Frequently, the cards had zoom animation on hover which was extremely distracting; remove any hover animation.
D30: Inbound vs Outbound groups page structure divergence¶
Finding: Inbound groups sub-pages wrap the page header in a content-card with content-card-header. Outbound groups sub-pages use a bare h2 with d-flex justify-content-between. Same module, two architectures.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | content-card > content-card-header > h4.content-card-title | 8 inbound groups pages |
| B | Bare h2 + d-flex justify-content-between | 12 outbound groups pages |
Proposed canonical: Variant B (simplified) -- use h4 with d-flex wrapper, no content-card around the page header. This aligns with D10.
Rationale: The outbound pattern is simpler and doesn't require a card wrapper for a page title. Content-cards should be used for data sections, not page headers.
Pages that need updating: 8 inbound groups sub-pages -- remove content-card wrapper from page header.
Status: APPROVED
D31: Inbound vs Outbound action button color¶
Finding: Within the same module (groups), inbound pages use btn-success btn-sm (green, small) for "Add" actions, while outbound pages use btn-primary (blue, default size).
Proposed canonical: Align with D11/D12 -- use btn-primary btn-sm for "Add" actions in both inbound and outbound.
Rationale: Consistency within a module is critical. D11 establishes btn-primary for creation/navigation actions.
Pages that need updating:
- 6 inbound pages -- change btn-success btn-sm to btn-primary btn-sm
Status: APPROVED
D32: Autocomplete/lookup patterns (3 implementations)¶
Finding: Three different autocomplete/lookup UI patterns exist for searching entities (customers, countries).
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | HTML5 <datalist> | Inbound groups forms |
| B | Custom div.lookup-container + div.lookup-dropdown | Outbound groups forms |
| C | Custom ul.dest-autocomplete | Booking (hotel-search), outbound-groups-sales |
Proposed canonical: Variant B (lookup-container / lookup-dropdown) -- it provides the best UX (dropdown with rich item display, keyboard navigation support).
Rationale: <datalist> is limited (no rich items, inconsistent browser rendering). The lookup-container pattern is the most feature-rich and is already used by the newest pages.
Pages that need updating:
- Inbound groups forms (~6 pages) -- replace <datalist> with lookup-container pattern
- Outbound-groups-sales.js -- replace dest-autocomplete with lookup-container
Status: APPROVED
D33: Card padding values¶
Finding: Card body padding varies across modules.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | 25px (~1.56rem) | tqadmin.css .content-card-body |
| B | 1.25rem (20px) | groups.css .content-card-body |
| C | 1rem (16px) | booking KPI, cruise KPI, offline-tickets |
| D | 0.75rem (12px) | Various compact card variants |
Proposed canonical: 1.25rem for standard content-card body padding. 1rem for compact cards (KPI cards, table-wrapping cards). 0.75rem 1rem for breadcrumbs and filter bars.
Rationale: 1.25rem is the Bootstrap default card-body padding ($card-spacer-y: 1rem, $card-spacer-x: 1.25rem). Aligning with Bootstrap reduces custom CSS.
Pages that need updating:
- css/tqadmin.css -- change .content-card-body padding from 25px to 1.25rem
Status: APPROVED
D34: Modal required-field indicator position¶
Finding: Modals show "* Required" text in two different positions.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | position: absolute; left: 16px; bottom: 16px in modal footer | Inbound groups modals |
| B | small.text-muted.me-auto in modal footer flex layout | Outbound groups, hotel modals |
| C | No indicator | Booking, tripmaker, offline-tickets modals |
Proposed canonical: Variant B -- <small class="text-muted me-auto">* Required</small> in the modal footer. Simpler, no absolute positioning, works with flex layout.
Rationale: Flexbox approach is more robust across modal sizes. Used by the most recently built pages.
Pages that need updating: Inbound groups modals (~6 pages) -- replace absolute positioning with flexbox.
Status: APPROVED
D35: Action buttons in table rows¶
Finding: Table row action buttons use a consistent pattern (icon-only btn-sm btn-outline-* in the last column) across most modules, with minor variations.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | Icon-only btn-sm btn-outline-primary/btn-outline-danger | ~30 pages (majority) |
| B | Icon+text btn-sm btn-outline-* | 2 pages (outbound-groups-sales) |
| C | Entire row clickable (no action column) | 2 pages (booking-list, groups-list) |
| D | btn-group btn-group-sm wrapping icon buttons | 1 page (hotel-packages) |
Proposed canonical: Variant A as default. Variant C acceptable for list-to-detail navigation pages. Use consistent icon choices: bi-pencil for edit, bi-trash for delete, bi-eye for view.
Rationale: Icon-only buttons save horizontal space. Consistent icon vocabulary across modules reduces cognitive load.
Pages that need updating: Minor -- outbound-groups-sales.js could switch to icon-only for consistency.
Status: APPROVED
D36: Border color token¶
Finding: Two different border colors in use.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | #e1e4e8 (tqadmin.css --border-color) | ~15 pages via tqadmin |
| B | #dee2e6 (Bootstrap default, used by groups, cruise, hotel, booking) | ~50 pages |
Proposed canonical: Variant B (#dee2e6) -- update tqadmin.css --border-color to match Bootstrap's default.
Rationale: Bootstrap default wins. Minimizes custom CSS overrides.
Pages that need updating:
- css/tqadmin.css -- change --border-color: #e1e4e8 to --border-color: #dee2e6
Status: APPROVED
D37: Transition duration¶
Finding: Three different transition durations used for hover effects.
Variants found:
| Variant | Description | Pages using it |
|---------|-------------|---------------|
| A | 0.3s | tqadmin, groups, cruise |
| B | 0.2s | offline-tickets, tripmaker, tqapp |
| C | 0.15s | booking, hotel |
Proposed canonical: 0.2s -- a good middle ground.
Rationale: 0.2s is perceptually instant while still smooth. 0.3s feels slightly sluggish; 0.15s is barely visible.
Pages that need updating:
- css/tqadmin.css -- update --transition to all 0.2s ease
- Module CSS files -- reference shared token
Status: APPROVED
Section 2 -- Needs Human Decision¶
H1: Offline Tickets green theme -- keep as accent?¶
Finding: D2 proposes changing OT's green primary to purple. However, offline tickets intentionally uses green to signal "ticket = go/available" semantics. The green table hover (#f0f7f4) and green primary (#2c6e49) create a cohesive "ticketing" identity.
Options:
| Option | Description | Trade-off |
|--------|-------------|-----------|
| A | Change OT primary to purple (#362c5d) | Consistent brand, loses module identity |
| B | Keep OT green as --ot-accent for cards/accents, but use purple for shared components | Hybrid: shared components consistent, module accents distinct |
Why this needs a human decision: This is a genuine design intent question -- was the green theme intentional module differentiation or an oversight?
Pages affected: 9 offline-tickets-*.html pages
Status: Proceed with Option A - change primary to purple.
H2: Dashboard (index.html) -- inline styles or external CSS?¶
Finding: index.html has 400+ lines of inline <style> defining custom components (summary-card, quick-tile, greeting-bar, upcoming-panel). These don't exist in any external CSS file.
Options:
| Option | Description | Trade-off |
|--------|-------------|-----------|
| A | Extract to css/dashboard.css | Clean separation, follows module pattern, increases file count |
| B | Move into tqadmin.css as shared dashboard components | Centralizes, but these components are only used on one page |
Why this needs a human decision: If the dashboard design will be reused (e.g., module-specific dashboards), Option B is better. If it's unique, Option A avoids bloating the shared file.
Pages affected: index.html
Status: Use option A. This CSS will rarely, if ever, be reused.
H3: visamgmt.html -- SPA architecture reconciliation¶
Finding: visamgmt.html has 700+ lines of inline CSS and uses a sidebar-based SPA architecture that differs from every other admin page. It has its own component system (.content-card, .kpi-card, .enhanced-table, .applicant-card) defined inline.
Options:
| Option | Description | Trade-off |
|--------|-------------|-----------|
| A | Extract inline CSS to css/visa.css, add tqadmin.css, reconcile component names | Significant refactoring but brings visa inline with other modules |
| B | Leave as-is, mark as "legacy -- will be refactored separately" | Avoids risk, defers work |
Why this needs a human decision: The visa module has its own design system. Reconciling it is high-effort and risks regressions in a working module.
Pages affected: visamgmt.html
Status: Proceed with option B - refactoring later.
H4: Content-card vs Bootstrap card -- which is canonical?¶
Finding: Some pages use tqadmin.css's custom .content-card with .content-card-header/.content-card-body structure. Others use Bootstrap's standard .card with .card-header/.card-body. Both serve the same purpose.
Options:
| Option | Description | Trade-off |
|--------|-------------|-----------|
| A | Standardize on .content-card (custom) | Consistent custom styling, but deviates from Bootstrap conventions |
| B | Standardize on Bootstrap .card | Uses framework defaults, but loses custom header gradient and shadow |
| C | Keep both: .content-card for page sections, Bootstrap .card for modals and inline forms | Clear purpose distinction, but two card systems to maintain |
Why this needs a human decision: This affects the visual identity of the entire admin portal. Both are valid approaches with different trade-offs.
Pages affected: All ~65 pages use one or both card types.
Status: Proceed with option A - standardize on the custom .content-card.
H5: Breadcrumb padding/radius values¶
Finding: Two breadcrumb spacing camps exist with subtle visual differences.
Options:
| Option | Description | Trade-off |
|--------|-------------|-----------|
| A | padding: 0.5rem 1rem; border-radius: 0.25rem; margin-bottom: 1rem | Compact (booking/TM/OT pattern) |
| B | padding: 0.75rem 1rem; border-radius: 0.375rem; margin-bottom: 1.5rem | Spacious (groups/cruise pattern) |
Why this needs a human decision: Both are visually acceptable. The choice affects information density on every page. Compact is better for data-dense pages; spacious is better for readability.
Pages affected: All ~49 pages with breadcrumbs.
Status: Proceed with option A - compact pattern.
Section 3 -- Applied Changes¶
| Decision ID | Status | Files changed | Applied on |
|---|---|---|---|
| D1 | APPLIED | 5 CSS files (token references unified) | 2026-04-02 |
| D2/H1 | APPLIED | offline-tickets.css (green → purple) | 2026-04-02 |
| D3 | APPLIED | cruise.css (secondary → accent rename) | 2026-04-02 |
| D4 | APPLIED | tqadmin.css (success-color → #198754) | 2026-04-02 |
| D5 | APPLIED | tqadmin.css + 3 module CSS (shadow unified) | 2026-04-02 |
| D6 | APPLIED | 29 HTML pages (CSS includes added) | 2026-04-02 |
| D7 | PARTIAL | Body classes not renamed (deferred, low visual impact) | 2026-04-02 |
| D8 | APPLIED | 49 HTML pages + 5 CSS files (breadcrumb unified to .tq-breadcrumb) | 2026-04-02 |
| D9 | APPLIED | 11 HTML pages (home icon added to breadcrumbs) | 2026-04-02 |
| D10 | APPLIED | 13 HTML pages (h-tag levels unified to h4) | 2026-04-02 |
| D11 | APPLIED | 7 HTML pages (button colors aligned) | 2026-04-02 |
| D12 | APPLIED | 1 HTML page (outbound-groups-list btn-lg → default) | 2026-04-02 |
| D13 | PARTIAL | HTML tables updated where present; JS-rendered tables need D19 follow-up | 2026-04-02 |
| D14 | APPLIED | thead.table-light added where missing | 2026-04-02 |
| D15 | APPLIED | 5 CSS files (empty-state unified to .tq-empty-state) | 2026-04-02 |
| D16 | APPLIED (override) | tqadmin.css (.tq-kpi-card with border-left, compact) | 2026-04-02 |
| D17 | APPLIED | Via D5 token unification | 2026-04-02 |
| D18 | APPLIED | 5 CSS files (filter-bar unified to .tq-filter-bar) | 2026-04-02 |
| D19 | PARTIAL | CSS classes renamed; JS badge functions need individual update | 2026-04-02 |
| D20 | DEFERRED | JS formatStatusLabel() function not yet created | - |
| D21 | APPLIED | 21 HTML pages (container classes unified) | 2026-04-02 |
| D22-D23 | DEFERRED | Required field indicators and label patterns (per-page HTML changes) | - |
| D24-D25 | DEFERRED | Date/currency formatting (JS module changes) | - |
| D26-D27 | DEFERRED | TQ.loading/pagination migration (JS module changes) | - |
| D28 | DEFERRED | SRI hashes (needs inventory of all CDN links) | - |
| D29 | APPLIED | groups.css (~150 lines of redefinitions removed) | 2026-04-02 |
| D30 | APPLIED | 8 HTML pages (inbound group header simplified) | 2026-04-02 |
| D31 | APPLIED | 6 HTML pages (inbound btn-success → btn-primary) | 2026-04-02 |
| D32 | DEFERRED | Autocomplete pattern unification (JS refactor) | - |
| D33 | APPLIED | tqadmin.css (card padding → 1.25rem) | 2026-04-02 |
| D34 | DEFERRED | Modal required indicator position (per-modal HTML change) | - |
| D35 | OK | Already consistent across majority | 2026-04-02 |
| D36 | APPLIED | tqadmin.css (border-color → #dee2e6) | 2026-04-02 |
| D37 | APPLIED | tqadmin.css (transition → 0.2s) | 2026-04-02 |
| H2 | DEFERRED | Dashboard CSS extraction (separate task) | - |
| H3 | SKIPPED | visamgmt left as-is per decision | - |
| H4 | APPLIED | Standardized on .content-card | 2026-04-02 |
| H5 | APPLIED | Compact breadcrumb pattern (0.5rem 1rem) | 2026-04-02 |
Section 4 -- Skipped / Deferred¶
| Decision | Reason | Follow-up |
|---|---|---|
| D7 (body class rename) | Low visual impact, high churn | Future: rename to tq-* prefix |
| D20 (formatStatusLabel) | Requires new shared JS function | Create in tqpro-components.js |
| D22-D23 (required/label) | Per-page HTML edits across ~40 pages | Batch update in follow-up PR |
| D24-D25 (date/currency) | Requires shared utility module | Create tq-format-utils or add to tqpro-components.js |
| D26-D27 (loading/pagination) | Requires per-module JS refactor | Migrate incrementally per module |
| D28 (SRI hashes) | Needs backend check too | Audit all CDN links in HTML + Java |
| D32 (autocomplete) | Requires JS component unification | Standardize lookup-container pattern |
| D34 (modal required) | Per-modal HTML changes | Batch update with D22 |
| H2 (dashboard CSS) | Standalone task | Extract index.html inline styles to dashboard.css |
| H3 (visamgmt) | Decided to defer | Refactor when visa module is next updated |