diff --git a/docs/superpowers/specs/2026-05-10-lid-hibernate-design.md b/docs/superpowers/specs/2026-05-10-lid-hibernate-design.md
new file mode 100644
index 0000000..1de5e89
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-10-lid-hibernate-design.md
@@ -0,0 +1,138 @@
+# Lid-Close Hibernate Design
+
+**Date:** 2026-05-10
+**Status:** Approved
+
+## Summary
+
+Make the laptop sleep more aggressively to save battery: close the lid (on AC or battery) → suspend immediately → hibernate after 30 min if not reopened. Same path applies to swayidle's existing 30-min idle timer. Reliably reaches 0% battery drain within ~60 min of stopping use, while keeping fast resume for short interruptions.
+
+Requires one-time bootstrap to enable hibernation (swap file, kernel resume params, mkinitcpio hook, UKI regen, reboot). Day-to-day config lives in tracked dotfiles.
+
+## Current Behaviour
+
+Lid handling (`/etc/systemd/logind.conf.d/lid.conf`, not currently tracked in repo):
+```
+HandleLidSwitch=suspend
+HandleLidSwitchExternalPower=lock
+HandleLidSwitchDocked=ignore
+```
+On battery: lid close → suspend (RAM stays powered, slow drain). On AC: lid close → just locks (laptop runs at full power overnight).
+
+swayidle (`niri/config.kdl` line 39):
+```
+spawn-at-startup "swayidle" "-w" "timeout" "300" "niri msg action power-off-monitors" \
+ "timeout" "600" "gtklock" "-d" \
+ "timeout" "1800" "systemctl suspend" \
+ "before-sleep" "gtklock" "-d"
+```
+After 30 min idle, calls `systemctl suspend` (not hibernate, no auto-progression).
+
+Hibernation prerequisites are NOT met: only zram swap (4 GiB, RAM-backed, can't persist), no `resume=` kernel param, no `resume` mkinitcpio hook. `systemctl hibernate` would fail.
+
+## Target Behaviour
+
+| Trigger | Immediate action | After 30 min suspended | Result |
+|---|---|---|---|
+| Lid close (battery or AC) | suspend | hibernate | 0% drain |
+| Idle 30 min | suspend | hibernate | 0% drain |
+| Lid close while docked | ignore | — | desktop stays awake |
+| `systemctl hibernate` | hibernate immediately | — | 0% drain, manual |
+
+`HibernateDelaySec=30min` controls the suspend → hibernate transition. Tunable in one tracked file.
+
+## Implementation
+
+### Hibernation prerequisites (one-time bootstrap)
+
+`scripts/enable-hibernation.sh` — idempotent script, requires sudo, run **once**, reboot afterward:
+
+1. **Swap file.** `btrfs filesystem mkswapfile --size 16g /swapfile` (handles NOCOW, alignment, mkswap in one). Skip if `/swapfile` exists with size ≥14 GiB.
+2. **Activate.** `swapon /swapfile`. Append `/swapfile none swap defaults 0 0` to `/etc/fstab` if absent.
+3. **Compute resume params.**
+ - `RESUME_UUID=$(findmnt -no UUID /)` → root filesystem UUID (currently `60cbc9b9-3631-4f9a-925c-a45e0920eb17`)
+ - `RESUME_OFFSET=$(btrfs inspect-internal map-swapfile -r /swapfile)` → physical offset of swap file
+4. **mkinitcpio hook.** Edit `/etc/mkinitcpio.conf` HOOKS array to insert `resume` between `block` and `filesystems`. `sed` guarded so a re-run is a no-op.
+5. **Kernel cmdline.** Append `resume=UUID=$RESUME_UUID resume_offset=$RESUME_OFFSET` to `/etc/kernel/cmdline` if not already present.
+6. **Regenerate UKI.** `mkinitcpio -P` → produces `/boot/EFI/Linux/arch-linux-zen.efi` with new HOOKS + cmdline baked in.
+7. **Reboot.** Print explicit instruction; do not auto-reboot.
+
+Why a separate script and not `install.sh`: hibernation enablement is invasive (modifies `/etc/mkinitcpio.conf`, `/etc/kernel/cmdline`, allocates 16 GiB on disk, regenerates the UKI). `install.sh` runs frequently during dotfiles iteration; this should run once.
+
+### Tracked dotfiles (deployed by `install.sh`)
+
+| New file | Destination | Contents |
+|---|---|---|
+| `logind/lid.conf` | `/etc/systemd/logind.conf.d/lid.conf` | `[Login]`
`HandleLidSwitch=suspend-then-hibernate`
`HandleLidSwitchExternalPower=suspend-then-hibernate`
`HandleLidSwitchDocked=ignore` |
+| `sleep/hibernate-delay.conf` | `/etc/systemd/sleep.conf.d/hibernate-delay.conf` | `[Sleep]`
`HibernateDelaySec=30min` |
+
+### `install.sh` additions
+
+After the existing greetd block:
+```bash
+sudo install -Dm644 "$(pwd)/logind/lid.conf" /etc/systemd/logind.conf.d/lid.conf
+sudo install -Dm644 "$(pwd)/sleep/hibernate-delay.conf" /etc/systemd/sleep.conf.d/hibernate-delay.conf
+```
+
+`install -Dm644` creates intermediate directories if missing and sets correct mode (consistent with system file expectations).
+
+### `niri/config.kdl` swayidle tweak
+
+Line 39: change `"systemctl suspend"` to `"systemctl suspend-then-hibernate"`. The full line becomes:
+
+```kdl
+spawn-at-startup "swayidle" "-w" "timeout" "300" "niri msg action power-off-monitors" "timeout" "600" "gtklock" "-d" "timeout" "1800" "systemctl suspend-then-hibernate" "before-sleep" "gtklock" "-d"
+```
+
+This makes the 30-min idle path use the same logind/sleep configuration as the lid path. After this edit, idle suspends and lid suspends are identical paths — both transition to hibernation after 30 min suspended.
+
+### `README.md` setup section
+
+Add a paragraph after the existing `install.sh` instructions:
+
+```markdown
+### One-time hibernation enablement
+
+Hibernation requires a persistent swap file, kernel resume parameters, and a regenerated UKI. Run once, then reboot:
+
+ sudo bash scripts/enable-hibernation.sh
+
+After reboot, `systemctl hibernate` will work, and lid close / 30-min idle will suspend-then-hibernate per the tracked logind config.
+```
+
+## Verification
+
+After running `scripts/enable-hibernation.sh` and rebooting:
+
+```bash
+swapon --show # /swapfile, ≥14 GiB, prio low
+cat /proc/cmdline # contains resume=UUID=… resume_offset=…
+systemctl status systemd-hibernate.service
+```
+
+Behavioural checks:
+1. `systemctl hibernate` — laptop fully powers off, then resumes to gtklock on next press of power button. (Resume takes ~20–30 s.)
+2. `systemctl suspend-then-hibernate` — laptop suspends instantly. After 30 min, kernel transitions to hibernation. (Don't have to wait for a real test — `journalctl -u systemd-suspend-then-hibernate.service` shows the timer firing.)
+3. Close lid on battery → suspends. Reopen within 30 min → instant resume. Reopen after 30 min → ~30 s resume from hibernation.
+4. Close lid on AC → same as battery (the asymmetric "AC just locks" behavior is gone).
+5. Leave laptop idle 30 min → swayidle calls `systemctl suspend-then-hibernate`, same path as lid.
+
+## Files Touched
+
+| File | Action |
+|---|---|
+| `logind/lid.conf` | created |
+| `sleep/hibernate-delay.conf` | created |
+| `scripts/enable-hibernation.sh` | created |
+| `install.sh` | append two `sudo install` lines |
+| `niri/config.kdl` | one-line edit on line 39 (swayidle action) |
+| `README.md` | append a "One-time hibernation enablement" subsection |
+
+## Out of Scope
+
+- **Snapshot-aware swap subvolume.** No snapshot tool (snapper, btrbk) is installed, so a flat `/swapfile` on the root subvolume is safe. If snapshots are added later, the swap file needs to be moved to a dedicated `@swap` subvolume — a future migration, not part of this work.
+- **Encrypted hibernation image.** Root is not LUKS, so the hibernation image lands unencrypted on `/swapfile`. If full-disk encryption is added later, the swap file is automatically encrypted along with the rest of root.
+- **GUI tools** (`HandleSuspendKey`, `HandlePowerKey`, etc.) — unchanged. Only `Lid*` keys are touched.
+- **`HibernateDelaySec` UI exposure.** Tunable in the tracked file; no script or env var to flip it without editing.
+- **Auto-reboot from `enable-hibernation.sh`.** The script prints a reboot instruction and exits. Rebooting is a user action.
+- **Removing zram swap.** zram stays as a fast in-memory compressed swap layer; hibernation uses `/swapfile` (lower priority is fine — kernel picks higher-priority zram first under memory pressure).