Ranges
One calendar wheel per leave type
Blackout ranges are configured on the leave type, in the same wizard as its other rules.
- Each range is a concrete pair of dates; add the next one with a click, up to 20 per leave type.
- The year wheel shows blocked stretches on the annual ring and totals them, like "25% of the year is blocked across 2 periods".
- Validation keeps ranges honest: no duplicates, no overlaps, end never before start.
At submit
The rule fires before the request exists
Enforcement happens at submission, on the server, for every request shape.
- A conflicting request is blocked with the exact dates of the range it crosses, spelled out in the message.
- Single, half-day, bulk, and recurring requests all pass the same check, item by item.
- Nothing conflicting reaches the approver, so the queue stays clean during the freeze.
At approval
Approvers get a flag, not a wall
Requests that were already pending when a blackout changed still need a human call.
- The approve dialog re-checks every rule and shows a dedicated blackout row among its policy checks.
- The flag is advisory: approvers can approve over it when the case deserves it.
- Every approval over a flag is recorded in the audit trail.
Guardrails
Sharp edges, spelled out
The feature stays deliberately small and predictable.
- Ranges are concrete calendar dates: for next year's freeze, you add next year's range.
- Employees learn about a conflict at submission, in the request modal, not from a greyed-out calendar.
- Team-level coverage rules and tag-level windows are separate mechanisms with their own configuration.




