diff --git a/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte b/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte index c2e475e1..1561f9ec 100644 --- a/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte +++ b/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte @@ -577,7 +577,10 @@ let select_ref_badge_type: HTMLSelectElement | undefined = $state(); $effect(() => { const field = active_field; if (!field) return; - requestAnimationFrame(() => { + // Wait for the accordion CSS animation (185ms ease-out) to finish before focusing. + // requestAnimationFrame fires at ~16ms — the input is still 0px / overflow:hidden + // at that point, so focus() silently fails. 210ms clears the animation safely. + setTimeout(() => { switch (field) { case 'name': input_ref_name?.focus(); @@ -601,7 +604,7 @@ $effect(() => { select_ref_badge_type?.focus(); break; } - }); + }, 210); }); // --- Dirty detection: compare live edit value against the last-saved badge obj --- @@ -2131,6 +2134,19 @@ let allow_tracking_open = $derived( font-size: 1.05rem; } +/* Placeholder text must read clearly as a hint, not as filled content. + The placeholders show the current badge value (e.g. "John Smith") so + without this they look identical to a filled-in field. */ +.ctrl-accordion-inner input::placeholder, +.ctrl-accordion-inner textarea::placeholder { + color: #9ca3af; /* gray-400 — visually distinct from input text */ + opacity: 1; /* Firefox sets opacity: 0.54 by default; override it */ +} +:global(.dark) .ctrl-accordion-inner input::placeholder, +:global(.dark) .ctrl-accordion-inner textarea::placeholder { + color: #6b7280; /* gray-500 in dark mode — readable but clearly a hint */ +} + /* ---- Entrance animation for form content ---- Triggered each time .open is applied to the parent accordion. Pairs with the height animation: content fades + zooms in from