# Plan your stay — editable Python example

42 nonblank lines in pages/index.py, including the Page class, interface,
seven formulas and controller. CSS and the collection-enabled app.py are separate.
Python declares the page; the short formula/controller expressions run as
JavaScript in the browser. No manual field listeners or parallel state system.

## Run (Python 3.11+)

python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
uvicorn app:application --reload --reload-dir pages

Open http://127.0.0.1:8000/.

## Follow the chain

Classic costs EUR90/night; Superior EUR140. Both include two guests;
each extra guest adds EUR25/night. Guests: 1–4; nights: 1–30, whole numbers.
Room rate + extra guests -> nightly price -> stay subtotal -> 10% discount
for seven or more nights -> total -> 30% deposit, rounded to whole euros.
Three guests in Superior for seven nights: 140 + 25 = 165/night;
165 * 7 = 1155; discount 115.5; total 1039.5; rounded deposit 312.
Change seven nights to six and the discount disappears: total 990, deposit 297.
Prepare summary captures the current accepted total; it changes only on click.

## Three independent rule edits to pages/index.py

1. Guests validate_max=4 -> 6. Five guests in Classic for three nights:
   extra 75, nightly 165, total 495, deposit 149. Seven guests are rejected.
2. nights >= 7 -> nights >= 5. Five nights in Classic for two guests:
   subtotal 450, discount 45, total 405, deposit 122.
3. Math.max(guests - 2, 0) * 25 -> Math.max(guests - 2, 0) * 15.
   Three guests in Classic for three nights: nightly 105, total 315, deposit 95.

Save, allow reload, and refresh. Restore the original between exercises.
Runnable copies: /guest_limit, /discount, /supplement. Each changes one rule;
the explanatory sentence also changes when it repeats the edited price/threshold.

Invalid drafts remain visible without replacing accepted Data. All derived
amounts use accepted Data. The summary is a snapshot, not a booking or payment.
Prices and discount policies are illustrative. No availability or tax service.
Inline expressions use the adapter's default policy; reusable browser behavior
and strict CSP normally use named Logic.

Canonical: gramlot-examples/src/gramlot_examples/pages/controllers/23_room_estimate.py.
The website distributes a checked snapshot, not a second implementation.
