Was at the bottom after print position controls — now first item in
Staff Adjustments, before Hide/Unhide Badge, where staff expect it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Was: visible to everyone pre-print, Trusted+Edit for reprints.
Now: Administrator + Edit Mode only (all three locations).
Temporarily restricted for Axonius 2026 — restore broader access after event.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
- 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>
- Center modal horizontally; position 10vh from top instead of centered vertically
- Add Allow/Do-not-allow toggle buttons inside the TC modal so attendees
can set their lead scanning preference while reading the terms
- Buttons reflect current DB value on open and use solid color fills
(green/red) so selection state is unambiguous in light and dark mode
- Save & Close calls existing save_field('allow_tracking') then closes;
Cancel closes without saving
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Merge Rapid + Qualify scan modes into single Confirm mode with two-button card:
"Add & Scan Next" (resets) and "Add & View Lead" (navigates to detail). Same
two-button pattern on the reenable card: "Restore & Scan Next" / "Restore & View Lead".
Stale 'qualify' localStorage values normalized to 'rapid' via $derived.by().
- QR scanner speed: fps 10→25, qrbox 82%→88%, useBarCodeDetectorIfSupported (native
BarcodeDetector API on Chrome/Edge — significantly faster than ZXing JS fallback)
- Fix capture identity stored in external_person_id / group:
licensed exhibit user → their email; shared passcode → 'shared_passcode' label
(not the raw passcode); Aether user bypassing exhibit sign-in → access_type string
('trusted', 'manager', 'super', etc.). Consistent across all three lead capture
components (single scanner, multi scanner, manual search).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- QR scanner (single + multi): detect previously-removed leads via IDB enable flag;
route to 'reenable' state instead of duplicate error; offer Re-activate button
- API fallback: if create fails and no IDB record, search API for disabled tracking
record by event_exhibit_id + event_badge_id (adds qry_badge_id param to
search__exhibit_tracking)
- Lead detail page: Replace raw enable checkbox with Remove Lead (two-click confirm,
navigates back after) and Restore Lead card (shown when enable is falsy)
- Fix flash of disabled records in leads list: filter !enable in both filtered_lead_li
derived and local IDB fast-path in handle_search_refresh
- eslint.config.js: disable svelte/no-navigation-without-resolve (no base path configured)
- Also includes _random field annotation cleanup (db_events, ae_types), iframe layout
fixes, badge view tweaks, test updates, and doc updates from prior session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Relocates the functions file from lib root into its module directory,
matching the pattern used by all other modules (ae_journals, ae_archives, etc.).
Updated all 85 import paths from \$lib/ae_events_functions → \$lib/ae_events/ae_events_functions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add justify-center + h-6 to the debug info row above the badge so it stays centered
and doesn't cause vertical shift when conditional elements show/hide on edit mode toggle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add field_shown() and field_editable() functions driven by event_badge_template.other_json:
controls_cfg: { shown?: string[], auth_editable?: string[] }
Access rules:
- No authenticated_access → display-only, no edit buttons shown
- authenticated only → can edit fields in auth_editable (default: title/affiliations/location/allow_tracking/pronouns)
- trusted + edit_mode → always sees and edits all fields, ignores config
Each attendee field card (name, title, affiliations, location, allow_tracking, pronouns)
is now wrapped in {#if field_shown()} and its edit button/accordion gated by field_editable().
No backend changes needed — other_json is an existing longtext JSON column.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add name_two_lines toggle (default: true) — uses CSS horizontal padding scaled by
character count to coax short names (e.g. "Scott Idem") into a natural two-line wrap
without a hard <br>; three tiers: ≤12 chars (18%), ≤20 (8%), ≤28 (2%), >28 no pad
- Inner <div> (block element) used inside Element_fit_text for class: directives —
Svelte scoped CSS requires static class names in the template; dynamic strings and
class: on component elements both fail to match scoped CSS rules
- Add leading-none to all four Element_fit_text fields (name, title, affiliations,
location) — line-height must be set at the wrapper div level where fit_text measures
scrollHeight, otherwise the binary-search scaler returns inflated sizes
- name_two_lines state persisted to localStorage (ae_badge_print_tweaks key) alongside
existing print_offset, hide_chrome, and banner_full_width tweaks
- Rewrite badge_header_calibration.svg as a precise SVG ruler with labeled tick marks
(major at 1in intervals, minor at 0.25in) for accurate physical print calibration
- Gate debug outline CSS on html.debug_outlines class (set by controls panel) so
outlines never appear in normal print mode
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Convert 6 template-level FA spans to Lucide components (Star, Biohazard,
Asterisk, Wifi). The code_to_html JS string dict (dietary symbols used
with {@html}) retains FA spans since they are raw HTML strings, not
Svelte template markup — FontAwesome CSS (app.html CDN) renders them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Svelte 5 does not support <style> or conditional {#if} blocks wrapping
<style> tags inside <svelte:head>. The parser treats them as raw-text
elements and reports '<script> was left open' at EOF.
Fix:
- Print media CSS moved to static/ae-print-badge.css (plain static file,
no framework magic needed — all selectors target global elements).
- svelte:head now uses a simple <link> to that file.
- $effect injects the @page size dynamically per template layout field,
avoiding the Svelte 5 parser limitation for conditional style injection.
- Badge_template interface in db_events.ts: added cfg_json / data_json
(standard Aether object fields that were missing from the type).
Adds a 🎨 button to the badge debug bar (edit-mode only) that cycles
through 5 SVG background patterns keyed by badge type color palette:
stripes, dots, diamonds, grid, swirls.
Swirl tile is 64×64 with corner-to-corner cubic bezier S-curves so
edges align seamlessly when tiled. Off by default; never prints.