type page = Dream_html.node val login : Dream.request -> ?error:string -> ?registration_open:bool -> unit -> page (** [registration_open] shows the "Register" link. Defaults to [false]. *) val register : Dream.request -> ?error:string -> unit -> page val choose_routine : Dream.request -> logging:bool -> viewer:View_model.Viewer.t -> routines:View_model.Routine_choice.t list -> page val home : Dream.request -> viewer:View_model.Viewer.t -> home:View_model.Home.t -> page val workout_in_progress : Dream.request -> viewer:View_model.Viewer.t -> workout_name:string -> page (** The Home card shown while a workout is in progress. Links to the current workout so it stays one tap away. *) val routine : Dream.request -> ?logging:bool -> viewer:View_model.Viewer.t -> View_model.Routine.t -> page val workout : Dream.request -> viewer:View_model.Viewer.t -> ?errors:(string * string) list -> ?editing:int -> ?logging:bool -> record_id:string option -> active_slot:int -> View_model.Workout.t -> page (** Renders one prescribed slot at a time under a dropdown that selects the exercise. Authenticated pages carry generic progressive-enhancement markers. Current workouts additionally mark slot links and forms, while saved-record edits use the generic authenticated form path. [active_slot] is the slot the view opens on. A handler clamps a requested slot and falls back to the first outstanding slot. [record_id] is [None] for the workout in progress and [Some id] for a saved history record. [logging] sets the middle navigation action. It defaults to a live workout view (true when [record_id] is [None]). *) type feedback_flow = { step : int; answers : (string * string) list } val feedback_factors : (string * string) list (** Ordered factor codes and labels used by the sequential feedback flow. *) val logbook : Dream.request -> ?logging:bool -> viewer:View_model.Viewer.t -> ?feedback:View_model.Feedback.report list -> ?suggest_feedback:bool -> ?feedback_flow:feedback_flow -> ?feedback_open:bool -> View_model.Logbook_entry.t list -> page (** The logbook: recorded workouts and a modal sequential subjective feedback flow. [feedback] lists past reports, most recent first. [suggest_feedback] shows a prompt inviting feedback, set after a workout finishes. *) val profile : Dream.request -> ?logging:bool -> viewer:View_model.Viewer.t -> ?username_error:string -> ?password_error:string -> ?notice:string -> unit -> page (** The account profile page: rename the account and change the password, each an independent form. [username_error] and [password_error] report a refused change inline. [notice] confirms a successful one. *) val settings : Dream.request -> ?logging:bool -> viewer:View_model.Viewer.t -> theme:string -> unit -> page (** The session-scoped theme settings page. *) val import_review : Dream.request -> viewer:View_model.Viewer.t -> View_model.Import_review.t -> page (** The review of a provisional Hevy import batch. Lists the rows dropped on parse, then each workout with its sets, blockers, and acknowledgement state. Renders a mapping form per distinct source name, a normal-set confirmation form, a per-workout promote form, and a batch promote form. Basic accessible HTML: it names no core entity, only the view model. *) val problem : title:string -> detail:string -> page val error_page : ?viewer:View_model.Viewer.t -> ?request:Dream.request -> status:int -> unit -> page (** A branded page for an HTTP failure. It names only the class of failure, so no server-supplied string leaks, and keeps the navigation affordances: top on desktop, bottom on mobile. *) val app_feedback : Dream.request -> ?logging:bool -> viewer:View_model.Viewer.t -> ?tab:[ `Write | `Submitted ] -> ?error:string -> View_model.App_feedback.t list -> page (** The authenticated application feedback page. One tab accepts a freeform message. The other lists the trainee's submitted messages. *)