Skip to content

TQPro Design Reconciliation Decisions

Generated by Claude Code on 2026-04-02.

HOW TO USE THIS FILE

  1. Review every entry in the PROPOSED DECISIONS section.
  2. For each entry:
  3. If you agree: write APPROVED in the Status field.
  4. If you want a different option: write OVERRIDE: [your instruction].
  5. If you want to skip this item: write SKIP.
  6. For entries in NEEDS HUMAN DECISION: make a choice and write DECISION: [your choice] in the Status field.
  7. 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


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