diff --git a/modules/home/idle.nix b/modules/home/idle.nix
index bdb3226..67922fc 100644
--- a/modules/home/idle.nix
+++ b/modules/home/idle.nix
@@ -43,17 +43,19 @@ in
check_color = rgb c.warn;
fail_color = rgb c.bad;
rounding = t.ui.rounding;
- # $FPRINTPROMPT is the ONLY place hyprlock renders the fingerprint
- # ready/scanning/failed messages — there is no implicit slot for
- # them. Enabling the backend without this yields a reader that
- # silently works while the field still says "password…", i.e. a
- # feature nobody can find (VISION: fingerprint discoverable without
- # reading the README). Verified on hardware 2026-07-14: unlock by
- # finger worked and said nothing at all.
- placeholder_text =
- if cfg.idle.fingerprint then "$FPRINTPROMPT" else "password…";
+ placeholder_text = "password…";
}];
+ # The lock screen is deliberately just the clock: the input field
+ # fades out while empty (hyprlock's fade_on_empty default) and only
+ # appears once you type. So the fingerprint hint CANNOT live in the
+ # field's placeholder — $FPRINTPROMPT renders faithfully into a widget
+ # nobody sees until they have already given up on the reader and
+ # started typing. It needs a surface that is visible at rest, and a
+ # label is the one that keeps the clock-only look. (Confirmed on
+ # hardware 2026-07-14: labels do expand $FPRINTPROMPT, so the line is
+ # live — "password… or scan finger", then "scanning finger…" on touch —
+ # and not static text.)
label = [{
monitor = "";
text = "$TIME";
@@ -63,7 +65,20 @@ in
position = "0, 120";
halign = "center";
valign = "center";
- }];
+ }] ++ lib.optional cfg.idle.fingerprint {
+ monitor = "";
+ text = "$FPRINTPROMPT";
+ # subtext-on-base is the palette's secondary-text role and is held
+ # to a 3.0 contrast floor on every theme by checks.theme-contrast —
+ # the same guard that exists because two themes once shipped
+ # subtext == base and made hint text invisible.
+ color = rgb c.subtext;
+ font_size = 16;
+ font_family = t.fonts.ui;
+ position = "0, -160";
+ halign = "center";
+ valign = "center";
+ };
} // lib.optionalAttrs cfg.idle.fingerprint {
# hyprlock does NOT take a fingerprint through PAM: its PAM stack runs
# only on submit, so a parallel module never gets to poll the reader.