btn + preset-filled-* renders transparent on gray/surface backgrounds
(Skeleton v4 CSS variable specificity issue — documented in
GUIDE__AE_UI_Style_Guidelines.md §12).
Replace all three buttons in field_actions (Save, Revert, Cancel) with
direct Tailwind token classes: bg-warning-500, bg-error-500,
bg-success-500, bg-surface-200-800 etc. Save button now visibly renders
in amber (dirty), red + pulse (pending_close), green (saved).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a field accordion has unsaved changes and the user tries to close
(X button, same-header click, or switching to another field), we now set
pending_close = true instead of silently discarding.
- Save button turns bright red + animate-pulse with label "Save first (or × to discard)"
- X button turns red with "Discard changes" tooltip
- Field stays open — no data is lost
- Second close attempt (pending_close already true) actually discards
- Saving normally clears pending_close and closes the accordion
WHY: kiosk attendees at a live event were silently losing typed overrides
(professional title, affiliations, etc.) when switching fields mid-queue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
toggle_field only changed active_field — it never called cancel_field for the
previously open field. Unsaved typed values stayed in edit_full_name_override etc.,
so reopening a field would show the stale typed value and re-apply it to the badge
preview, even though the user had already moved on.
New logic: capture was_open, always call cancel_field for the current field (resets
edit vars + sets active_field = null), then open the new field if it wasn't the one
being closed. Closing a field by re-clicking its pencil now also discards unsaved state,
consistent with the explicit [X] button behavior.
Also: add global placeholder CSS fix to TODO__Agents.md (scoped workaround already
in ae_comp__badge_print_controls; long-term fix belongs in app.css or theme file).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-focus: requestAnimationFrame (~16ms) fired before the 185ms accordion
animation ended — input was still 0px/clipped so focus() silently failed.
Changed to setTimeout(210ms) so focus lands after the animation completes.
Placeholder color: placeholders show the current badge value (e.g. 'John Smith')
so without explicit styling they look identical to filled text. Added scoped
CSS rules setting placeholder to gray-400 (light) / gray-500 (dark) so it reads
clearly as a hint rather than existing content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
update_ae_obj__event_badge returns false on API failure without throwing,
so the old code always treated a failed PATCH as success — badge printed,
count not saved, page navigated away silently.
Now: check the return value explicitly. On failure — still fire window.print()
(physical print must never be blocked) and still navigate back, but show a
visible red error state ('Printed — count NOT saved (see staff)') and hold
for 4s so a kiosk operator can see it before the loop resets.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MariaDB rejects ISO 8601 with milliseconds ('2026-04-14T20:29:15.784Z').
print_last_datetime and print_first_datetime must be 'YYYY-MM-DDTHH:MM:SS'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, a public user who navigates to a printed badge's print page
sees a blank controls panel with no explanation. Now shows an amber notice
directing them to event staff. Gated on !can_print && is_printed && !is_trusted
so it never shows to staff.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The name|layout|v3 info row was always visible. Gate it on
trusted_access && edit_mode — attendees and volunteers should
not see internal template metadata above their badge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HTML comments don't suppress Svelte {#if} blocks — the content was rendering
unconditionally. Switch to {#if false} so the blocks are genuinely hidden.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lead scanning was canceled last-minute; pronouns not on this badge template.
Both blocks left in source with AXONIUS 2026 markers for easy restoration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hide/Unhide and print count edit belong on the per-badge page (print controls
staff section), not the search list — the list was getting too crowded.
- ae_comp__badge_obj_li: removed hide toggle, print count input, and the
ae_api/events_func imports that were only there to support them
- ae_comp__badge_print_controls: added Hide Badge button (Trusted, top of staff
section) and Print Count editor (Admin+, below hide); both reuse the existing
save_field/field_save_status pattern for consistent spinner/done/error feedback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lower access levels (authenticated, public) can have edit_mode active.
Show Hidden must be trusted+ only — split it out of the generic edit_mode block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide/Unhide toggle button (Trusted + Edit Mode) on each badge row in the list; badge disappears immediately when hidden unless Show Hidden is active
- Print count inline editor in debug row (Admin + Edit Mode); updates count only, no timestamp changes
- "Show Hidden" checkbox in search filters (Trusted + Edit Mode); wires through IDB fast-path, API hidden param, and visible_badge_obj_li filter
- show_hidden requires edit_mode to be active — reverts to hiding hidden badges when edit mode is off
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Edit mode should not override the filter state — staff set their
filters and turn off edit mode all the time. The real split is
trusted staff vs kiosk/public, not edit mode on/off.
Trusted and above: qry_printed_status is the sole control over
printed badge visibility, regardless of edit mode state.
Public (kiosk) / authenticated / anonymous: always unprinted only.
Badge kiosks run at public_access and should never expose a list
of already-printed badges to attendees.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs:
1. visible_badge_obj_li gated on trusted+edit_mode, but the filter
dropdown is also accessible to manager+ without edit_mode. Changed
gate to (trusted+edit) || manager_access to match the filter's own
access condition.
2. not_printed API query used print_count eq 0, which does not match
NULL in SQL. Unprinted badges have print_count = NULL, so the API
was returning 0 results and overwriting the correct IDB fast-path
results. Removed the not_printed condition from the API query —
IDB fast path (print_count ?? 0) < 1 and visible_badge_obj_li
both handle NULL correctly and are the authoritative filter for
that case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously edit_mode was a blunt override: trusted+edit showed all
badges regardless of the filter setting. This meant the Printed Status
dropdown had no effect on what was visible in the list.
Now trusted+edit mode respects qry_printed_status as the single source
of truth: 'all' shows everything, 'printed' shows only printed, and
'not_printed' shows only unprinted. The filter dropdown is only
accessible to trusted+edit users so it is safe to use as the control.
Kiosk/attendee behavior (trusted no edit, public, anonymous) unchanged:
only unprinted badges are shown regardless of filter state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sort changes without a text query were falling through to the fallback
liveQuery (50 badges sorted by given_name), ignoring the selected sort
entirely. Added params.sort to has_active_filters so any explicit sort
selection triggers the full search path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All four sort options in the dropdown were falling through to the
default (given_name ASC) because their cases were missing from both
the IDB fast-path sort and the API order_by_li mapping:
- Affiliations ASC: IDB sorts by affiliations_override → affiliations;
API sorts by affiliations column
- Badge Type ASC: badge_type_code ASC
- First Printed DESC: print_first_datetime DESC
- Last Printed DESC: print_last_datetime DESC
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update badge type codes for Axonius 2026 (replaces ISHLT 2024 list).
Added TODO to drive this from event templates in the future.
Fix printed status and badge type filters not working without a text
query. The min_chars guard was blocking all filter-only searches,
causing "Printed" and "Not Printed" to always return empty results.
Now bypasses min_chars when any non-default filter is active (printed
status, type code, or affiliations), since selecting a filter is
explicit user intent regardless of the text query.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Badge print kiosks authenticate at the public_access level (site-wide
passcode). Previously the print gate was trusted_access, meaning kiosk
operators had to sign in at the trusted level just to print.
Changed in both the list view and the badge detail controls panel:
- First print: public_access and above (kiosk use case)
- Reprint: still requires trusted_access + edit_mode
ae_comp__badge_obj_li.svelte: added is_public derived; updated
can_print and the print button #if condition.
ae_comp__badge_print_controls.svelte: added is_public derived; updated
can_print comment and logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Font size changes now persist automatically (600ms debounce) without
requiring the user to find and click Lock Sizes in the collapsed Staff
section. reset_font_sizes_to_auto continues to handle its own save.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per V3 convention, {obj_type}_id IS the random string — send
event_badge_template_id (not _random). The backend not saving it is
a backend bug, not a frontend concern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The IDB stores the random string in event_badge_template_id (overwritten
by _process_generic_props). Sending this as event_badge_template_id
passed a string to an int(11) FK column — backend silently ignored it.
Using event_badge_template_id_random lets the V3 CRUD handler resolve
it to the correct integer FK.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single-template events auto-select silently but gave no visual
confirmation. Added a read-only display of the template name so staff
can verify the correct template is in use before submitting.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every badged event must have a template — without one the badge cannot
render. Changed auto-select from === 1 to >= 1 so multi-template events
also get a default (first template). Added an error message and disabled
submit when no templates are configured at all. Removed blank
"-- Select Template --" option so the form never submits with null.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Professional title, organization, and location entered during manual
badge creation were being stored in the *_override fields. Override
fields are intended for overriding imported/AMS person data — for new
manually created badges, the base fields (professional_title,
affiliations, location) are correct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each data-theme selector is fully self-contained — CSS custom properties
do not inherit across theme selectors. The Axonius file only defined the
primary ramp, leaving surface/secondary/tertiary/success/warning/error
undefined, causing the UI to render in grey/black/white.
Added full color ramps and dark-mode contrast tokens (matching base
AE_Firefly) to both light and dark blocks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `bleed` field to BadgeTemplateCfg (CSS length, e.g. "0.125in")
- Badge view: derive bleed_offset, move bg-image to absolute positioned div
that extends past card edges; add isolation:isolate to badge_front stacking context
- Template form: add bleed input in Advanced > Appearance; wire to cfg_json save/load
- PVC layout CSS: change overflow:hidden → overflow:visible in print rule to allow
bleed div to render at physical card boundary (Zebra driver clips at card edge)
- Prevents white borders on PVC cards when printer has slight alignment variance.
Screen preview shows bleed visually extending past the card outline.
Allows coordinators to pre-tune font sizes for attendees with long names
and have those sizes apply automatically on every kiosk, not just one machine.
- ae_types.ts: add cfg_json to ae_EventBadge interface
- db_events.ts: add cfg_json to Badge Dexie interface
- ae_events__event_badge.ts: add cfg_json to properties_to_save so it is
persisted to IndexedDB on load and returned by the API
- print/+page.svelte: on first load per badge, read cfg_json.font_sizes and
initialize font_size_name/title/affiliations/location state from saved values
(guarded by _font_sizes_loaded_for to avoid clobbering user adjustments on
background liveQuery refreshes)
- ae_comp__badge_print_controls.svelte: add lock_font_sizes() and
reset_font_sizes_to_auto() functions; add Lock Sizes / Auto reset UI in the
Staff adjustments section (trusted-only); button shows warning style when
sizes are unsaved vs success when locked; status indicator shows what is
currently locked
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- badge_template_form: fix default field visibility (location off render, pronouns/leads excluded from controls); fix duplicate QR checkboxes by removing orphan show_qr_front/back state vars; reorganize Advanced cfg_json into labeled sub-groups; make all 5 non-Advanced sections collapsible (general starts open, rest collapsed)
- print_controls: add DEFAULT_SHOWN constant so field_shown() uses explicit whitelist fallback instead of showing all fields when no controls_cfg is set
- badges config +page: add Templates navigation button in header (FileText icon)
- templates +page: add back-nav header with ArrowLeft to badges/config, Settings icon, page title
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>