Commit Graph

117 Commits

Author SHA1 Message Date
Scott Idem
4d43fd8a67 fix(badges): move Badge Type field to top of Staff section
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>
2026-04-14 18:03:50 -04:00
Scott Idem
75f755c660 temp(badges): restrict Email Link to Administrator + Edit Mode only
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>
2026-04-14 17:41:00 -04:00
Scott Idem
5d6cc4ca35 fix(badges): shorten pending_close Save button label to prevent wrapping
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 17:28:54 -04:00
Scott Idem
a68b85e1f1 fix(badges): use direct token classes for field_actions buttons
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>
2026-04-14 17:19:03 -04:00
Scott Idem
0199c2e2c9 fix(badges): guard unsaved edits — warn on close, error on second close
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>
2026-04-14 17:07:26 -04:00
Scott Idem
126eb77be2 fix(badges): cancel edit state on field switch, not just on explicit cancel
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>
2026-04-14 16:55:22 -04:00
Scott Idem
7733ef8708 fix(badges): auto-focus input after accordion animation + mute placeholder text
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>
2026-04-14 16:42:58 -04:00
Scott Idem
a81d65ce7e fix(badges): detect and surface PATCH failure in handle_print_badge
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>
2026-04-14 16:36:56 -04:00
Scott Idem
3d81cb5a83 fix(badges): strip milliseconds/Z from datetime before PATCH
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>
2026-04-14 16:32:07 -04:00
Scott Idem
345641e4c4 fix(badges): show 'already printed' notice to public users on print page
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>
2026-04-13 23:51:25 -04:00
Scott Idem
71c615bf4a fix(badges): hide template debug info bar from non-staff users
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>
2026-04-13 23:44:44 -04:00
Scott Idem
81aa0eefcd fix(badges): properly suppress pronouns and lead scanning with {#if false}
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>
2026-04-13 23:29:36 -04:00
Scott Idem
430d39231d temp(badges): comment out pronouns and lead scanning for Axonius 2026
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>
2026-04-13 23:14:35 -04:00
Scott Idem
5203104fef refactor(badges): move hide toggle + print count editor to individual badge view
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>
2026-04-13 22:44:58 -04:00
Scott Idem
5826b21821 feat(badges): allow public_access to print first-print badges
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>
2026-04-13 18:01:47 -04:00
Scott Idem
ad3b27b747 fix(badges): auto-save font sizes on adjustment
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>
2026-04-11 19:37:31 -04:00
Scott Idem
22d62ba3b1 Adjusting styles Axonius 2026-04-10 19:42:41 -04:00
Scott Idem
c7fa75afc7 ui(badges): add background image bleed support (cfg_json, PVC layout)
- 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.
2026-04-10 14:25:08 -04:00
Scott Idem
e542c55500 ui(badges): layout & fit-text tweaks; improve template form controls; remove badge modals from event settings; add documentation for passcode security 2026-04-10 11:44:22 -04:00
Scott Idem
c9e2284758 Badges: per-badge locked font sizes via cfg_json
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>
2026-04-09 21:47:34 -04:00
Scott Idem
941ad6ae88 Badges: template controls cfg, collapsible form sections, navigation polish
- 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>
2026-04-09 20:31:38 -04:00
Scott Idem
d05420d9c1 Badges: persist template controls_cfg; fix onchange syntax in template form 2026-04-09 15:10:03 -04:00
Scott Idem
d5b2b557f3 chore(badges): hex-only body_text_color + form color picker; renderer default black 2026-04-08 14:19:48 -04:00
Scott Idem
b02843e467 feat(badges): cfg_json body_text_color applied in renderer 2026-04-08 12:32:13 -04:00
Scott Idem
ef45a0ca0f feat(badges): TC modal centering, positioning, and allow-tracking toggle
- 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>
2026-04-07 20:29:41 -04:00
Scott Idem
93fea0d165 Making custom changes just for Axonius badge printing next week 2026-04-07 14:59:23 -04:00
Scott Idem
988ba75df3 feat(badges): cfg_json hide toggles for title/affiliations/location; wire renderer 2026-04-07 14:28:10 -04:00
Scott Idem
34bf823987 chore(badges): save in-progress changes — background_image_path, cfg_json support, template form TS fix, view boolean fixes 2026-04-07 13:57:02 -04:00
Scott Idem
c198ca2454 chore(badges): remove legacy badge_id_only_search; sync remote badges config into badges_loc; docs update 2026-04-02 18:03:23 -04:00
Scott Idem
a3ed379b17 Prettier for Event Badges 2026-03-24 12:13:37 -04:00
Scott Idem
94849137f0 I think pretty much all references to v1 and v2 have been removed. All files have been renamed from _v3 to just the function/var name with out the appended version. Assume no _vX is the current version. 2026-03-24 11:32:06 -04:00
Scott Idem
512e5ef87c Saving more code clean up and removal 2026-03-24 11:15:01 -04:00
Scott Idem
de8a016bda Minor bug fix to render some icons in HTML text. :-) 2026-03-20 19:25:03 -04:00
Scott Idem
fe23899479 feat: leads QR UX — merged confirm modes, faster scanning, correct capture identity
- 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>
2026-03-20 19:15:35 -04:00
Scott Idem
6662e82f40 feat: leads re-enable flow — detect removed leads on scan + Remove/Restore buttons
- 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>
2026-03-20 18:18:10 -04:00
Scott Idem
519f5b949c chore: move ae_events_functions.ts into ae_events/ module
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>
2026-03-20 09:52:13 -04:00
Scott Idem
60461de9d9 fix: badge view debug bar — center text and reserve fixed height to prevent layout bounce
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>
2026-03-19 19:18:38 -04:00
Scott Idem
da3b8dcf46 feat: badge print controls — per-template field visibility and edit access via other_json.controls_cfg
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>
2026-03-19 19:04:40 -04:00
Scott Idem
f628e7e3fc feat: badge print controls — quick print btn, compacted spacing, collapsible sections, overflow fix
- Add Quick Print button (30%) alongside canonical Print Badge (70%): calls window.print()
  only — no count increment, no navigation back to search
- Compact panel spacing: reduce space-y, pt/pb on card headers, standalone row py, font_ctrl py
- Add collapsible Attendee/Staff section groups reusing ctrl-accordion CSS pattern;
  attendee starts open, staff starts collapsed — auto-collapses the other on expand
- Add overflow-x-hidden to print page panel container to kill horizontal scrollbar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:47:35 -04:00
Scott Idem
fdd8691e2e feat: badge print — two-line name toggle + leading-none tightening + calibration SVG
- 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>
2026-03-19 17:55:49 -04:00
Scott Idem
621a637b85 feat: badge print UX improvements — chrome toggle, banner width, overlap fix, header centering
- Replace ae_comp__badge_obj_view_v2 with ae_comp__badge_obj_view (consolidated component)
- Add hide-chrome toggle ([H] shortcut + button) to hide site nav/footer/sys bar for clean print workspace
  — syncs $ae_loc.sys_menu.hide + $ae_sess.disable_sys_nav/footer with restore-on-unmount
- Add banner_full_width toggle (default true=100% width, false=natural pixel size for calibration)
- Center badge header image (display:block; margin:0 auto) — was left-aligned when narrower than badge
- Fix controls panel overlap: move from bottom-0 to bottom-24 to clear sys bar (84px tall)
- Add [H] keyboard shortcut for chrome toggle (guards against focus in inputs)
- Persist hide_chrome and banner_full_width in ae_badge_print_tweaks localStorage key
- Add sample header image assets (calibration SVG/PNG, hex blue SVG/PNG, demo PNG)
- Update badge PVC CSS layout and module docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 15:42:22 -04:00
Scott Idem
07d21c29c8 feat: add trusted-only debug outlines toggle to badge print controls panel 2026-03-18 13:05:17 -04:00
Scott Idem
e085a1d513 chore: remove broken/redundant components imported from WIP branch 2026-03-17 10:51:58 -04:00
Scott Idem
df34a85a89 cherry: import ae_comp__badge_obj_view.svelte (v1 with edit) from wip-modal-fix-attempt 2026-03-17 10:35:00 -04:00
Scott Idem
b543c8a930 chore: migrate all FA icons to Lucide (@lucide/svelte)
- Replaced all active FontAwesome <span class="fas fa-*"> icons with
  Lucide components across 145 files (excluding /idaa/ which is intentional)
- Fixed merge script bug: consolidated lucide-svelte imports into @lucide/svelte
- Replaced dynamic toggle patterns (fa-toggle-on/off) with ToggleRight/ToggleLeft
- Replaced fa-eye/fa-eye-slash with Eye/EyeOff
- Replaced fa-bug/fa-bug-slash with Bug/BugOff
- Replaced fa-sync fa-spin with RefreshCw + animate-spin
- Replaced fa-microchip with Cpu
- Fixed {@const} placement in element_manage_event_file_li.svelte
- Removed obsolete CSS hover rules for .unlock_icon/.lock_icon
- svelte-check: 0 errors, 0 warnings
2026-03-16 18:07:43 -04:00
Scott Idem
80baaa9d91 style: badge code_to_icon refactor + core variant-* → preset-* migration
badge ae_comp__badge_obj_view_v2.svelte:
- Replace FA HTML string dict (code_to_html) with Lucide component map
  (code_to_icon) — no FontAwesome dependency for dietary/option icons
- option_1 maps: Biohazard (generic/allergy), Utensils (dietary), Bone,
  Fish, Carrot for specific diets
- option_2 maps: Asterisk (generic flag), Hand (first-time attendee)
- Template: replace {@html option_other_*} with {@const Icon}<Icon /> pattern
- Back-of-badge: shows text label + inline icon

core/ (21 files):
- variant-soft-* → preset-tonal-* (6 variants)
- variant-filled-* → preset-filled-* (6 variants)
- variant-glass-surface → preset-tonal-surface (Skeleton v4 has no glass)
- bare variant-soft → preset-tonal-surface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 14:42:28 -04:00
Scott Idem
37c9d830f6 style(badges): FA→Lucide migration in ae_comp__badge_obj_view_v2.svelte
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>
2026-03-16 14:30:30 -04:00
Scott Idem
1291b225c6 Svelte: fix 3 svelte-check warnings (non-IDAA) + Playwright test type error
- ae_comp__badge_print_controls: select_ref_badge_type declared as $state()
  so Svelte 5 tracks DOM ref assignment correctly (was plain let).
- launcher_cfg_section: <svelte:component this={icon}> replaced with
  let Icon = $derived(icon) + <Icon /> — svelte_component_deprecated fix.
- launcher_file_cont: same svelte_component_deprecated fix for FileIcon.
- badge_print_layout.test.ts: inject_idb signature changed from (badge, template)
  to ({ badge, template }) — page.evaluate() passes exactly one argument;
  all three call sites updated to pass { badge: mock_badge, template: mock_template }.
2026-03-16 13:51:01 -04:00
Scott Idem
6ca2314472 Badges: fix print page svelte-check error — extract print CSS to static file
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).
2026-03-16 13:50:28 -04:00
Scott Idem
cfa9e85d05 feat(badges): add demo background pattern toggle in edit mode
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.
2026-03-12 19:23:21 -04:00