The UX/UI layer of the Guesteria system: the components, layout and screen anatomy behind three tonally distinct surfaces - the white, dense Front-Desk console, the warm, airy guest app and the cool, compact staff app.
11 Components
Mirrors the ShadCN vocabulary plus the Guesteria-specific variants the product actually ships (status split-buttons, the five-star + optional-comment rating, verb-coloured staff CTAs, the .guest-chip room-row, the operator's merge-field composer). Each family below is tagged by the surface it belongs to — Front-Desk, Guest, or Both; the staff app is a third surface and is called out where it diverges.
CTA colour routes by SURFACE and by VERB, not by actor. The guest primary is dark navy (--brand-800 #2D2F44) on every guest screen sampled - "Next", "Pay now", "Back to Dashboard", "Confirm", "Decline", "Upgrade room type" (Guest/Guest - My requests1.png, Guest/Guest - Pre-check-in-Step 8.png, Guest/Guest - Chats-Request by menu.png). The staff primary is full-width and coloured by the VERB, three hues in one card component on one screen: Get blue, Start orange, Finish green (Staff/staff - Dashboard.png). The console's manager action is the status split-button (11.2), and its create actions are violet (Front Desk/FD - Requests list - Guest.png, "+ Guest service" / "+ Internal service"). Violet marks the AMOUNT, the unread count, the active-nav fill and the translation chip - never the pay action.
The actor-routed variants .btn-staff and .btn-guest are NOT shipped. No screen carries a Skyline-blue "ordinary staff CTA" or an Earthy-brown "ordinary guest CTA"; they survive in the stylesheet as legacy role aliases only. Do not reach for them when building a screen.
Staff verb buttons - one hue per verb, same component, same screen (Staff/staff - Dashboard.png):
Legacy aliases, kept in the stylesheet and shipped on no screen:
| Variant | Background | Border | Text | Use |
|---|---|---|---|---|
| Guest primary | --brand-800 #2D2F44 navy | none | #FFFFFF | EVERY guest-app primary: "Next", "Pay now" (with a card glyph), "Back to Dashboard", "Confirm", "Decline", "Upgrade room type" |
| Staff verb | one hue per verb - Get blue, Start orange, Finish green | none | #FFFFFF | The full-width staff task action. Two cards with the SAME status carry different buttons, because assignment - not status alone - picks the verb |
Primary (.btn-primary) | --brand-600 violet | none | #FFFFFF | Console CREATE actions ("+ Guest service", "+ Internal service"). Violet's other jobs are marks, not buttons: the price, the unread count, the active-nav fill, the translation chip |
| Secondary | --surface-canvas | 1px --line-strong | --text-primary | "Filters", "Skip", "Add feedback", and the "Cancel" that abandons a dialog or a form - the card demotes its own action to an outlined secondary once the object is terminal |
| Split-button | --ctx-1-700 slate, or --status-* at a terminal state | none | #FFFFFF | Label + caret manager actions: "Set", "Approve", "To Do" all slate; only "Done" green and "Canceled" red |
.btn-staff / .btn-guest | --ctx-1-800 / --ctx-2-800 | none | #FFFFFF | LEGACY ALIASES. Actor-routed CTAs are not shipped on any screen; do not use |
| Tertiary | transparent | none | --text-primary | Toolbar, dense console surfaces |
| Link | transparent | none | --accent-link | True hyperlink, "All" / "See original" |
| Destructive | --status-error | none | #FFFFFF | "Cancel request", "Mark Canceled" - an action that destroys the object |
| Size | Height | State | Spec |
|---|---|---|---|
sm | 28px | rest | the resting fill |
md (default) | 36px | hover | -10% luminance |
lg | 44px | pressed | -20% luminance |
xl (marketing only) | 52px | focus | 2px --focus-ring, 2px offset |
| -- | disabled | 40% opacity | |
| -- | loading | spinner replaces label, width preserved |
A label + caret manager action whose primary segment is the NEXT state and whose dropdown holds the others. The fill follows the status only at the TERMINAL states. Set, Approve and To Do all render in the same desaturated slate (--ctx-1-700 #6D82A3); only Done is green and only Canceled is red (Front Desk/FD - Requests list - Guest.png, Front Desk/FD - Requests list - Internal.png). At a terminal state the button greys out entirely. The caret half opens the dropdown of the other statuses.
Label-only, icon-only (square), leading icon, trailing icon. Icon is 14-16px; padding tightens for icon-only.
| Element | Resting | Focus | Error | Disabled |
|---|---|---|---|---|
| Text / textarea | 1px --line-strong, ~8px radius, 40px height; char counter ("0/750") | --focus-ring border + --focus-ring-soft glow | 2px --status-error, error helper | --surface-sunken, 40% text |
| Select / dropdown | same plus caret | same | same | same |
| Date / date-range / time | field plus calendar icon; range chip | same | same | same |
| Checkbox | ~18px, ~4px radius; checked fills --control-active | 2px focus ring | error stroke | 40% opacity |
| Radio | circle, 2px stroke; document-type choice | 2px focus ring | error stroke | 40% opacity |
| Toggle | pill, --control-active ON, gray OFF; encodes service active/inactive | 2px focus ring | n/a | 40% opacity |
| Quantity stepper | -/value/+ control | n/a | n/a | 40% opacity |
| Signature capture | off-white card, "Tap to put signature here" + pencil tile | n/a | required asterisk | n/a |
| Country-code phone | flag + code prefix + number | --focus-ring border | error stroke | 40% opacity |
Label and helper both sit on the Caption step - 13/18, --text-secondary for the label at 500, --text-tertiary for the helper. There is no 12px step on the master scale (dmd 4); the step below Caption is Micro at 11/16. Required fields carry an asterisk. Idle focus is desaturated - a --focus-ring border plus a --focus-ring-soft glow on a white background, never the saturated --brand-600 border or a --brand-50 fill. Committed controls (checked checkbox/radio, toggle ON, slider fill/thumb) fill --control-active (#4E4670), not the CTA violet.
The header .nav-brand carries the REAL Guesteria full lockup - the shipped assets/logos/guesteria--logo.svg (navy knockout), or assets/logos/guesteria--logo-light.svg (off-white knockout) on a dark ground - set at ~24px tall. Never an icon-plus-wordmark composition fabricated from the bare circular mark - that is struck at logo 4. Which file goes on which surface is the logo artifact's own table at logo 3. In the shell the standalone assets/logos/guesteria--icon.svg badge is the app / favicon slot; off product it may also stand in as the SHORT logo at small or square scale.
Two controls, not one strip. The centered QUEUE TABS are a three-way segmented control over the object kind; the All / Priority pair is a separate segmented control in the table TOOLBAR below them, beside the Filters chip, the list / kanban / calendar view switcher and the two create buttons (Front Desk/FD - Requests list - Guest.png). Merging them into one four-tab strip loses the fact that a queue and a filter are different axes.
INFERRED, not observed. Neither console screen carries a breadcrumb - both identify location with the top-bar page title plus the active rail item (Front Desk/FD - Requests list - Guest.png, Front Desk/FD - Chats 3.png). The pattern is drawn here because the console has a Management > Staff > person depth that needs one; treat it as a proposal.
The console left nav rail stays white, never a colored block. Top to bottom: the "Guesteria" wordmark + chevron; a property / workspace switcher card (property name "Verde Canario" + thumbnail + chevrons); then grouped nav. Group eyebrows are NOT tinted by meaning. Guests, Inbox and Management all render their eyebrow in one neutral grey; the only coloured item in the rail is the ACTIVE one, and it takes the brand violet regardless of which group it sits in (Front Desk/FD - Requests list - Guest.png, Front Desk/FD - Chats 3.png, FD_Settings/FD_Settings - Pre Check-In-Step 7.png).
The page ground stays white. A guest in the content is never a hand-rolled avatar + room badge - it is the .guest-chip component, so the room tag and the room-type code travel with it:
Many items carry dual count badges: a gray total plus a violet unread ("Chats 23 | 4", "Requests 28 | 2" - the shipped frames disagree on the Requests badge, which also renders 12 | 1). The active item takes the SAME violet in every group - a --brand-50 fill with --brand-700 text and a 3px --brand-600 left bar. There is no per-group active colour:
The guest app carries its own navigation anatomy: a bottom tab bar, a per-screen top app bar, and a slide-in drawer. The drawer DUPLICATES the tab bar rather than extending it, and the overlap is partial. Room, My Stay and Activities sit in both. Concierge and Requests - two of the five tabs - are in the tab bar ONLY; there is no Requests item in the drawer. Hotel and Hotel Services are in the drawer only. A guest who learns the app from the drawer never finds the chat (Guest/Guest-Dashboard+Sidebar1.png). Preserve the asymmetry.
5 tabs - Room, Activities, Concierge, Requests, My Stay - with a center emphasized circular "Concierge" tab linking to reception chat. A floating rounded surface. Concierge and Requests live here and nowhere else.
Circular back button, centered screen title ("Concierge", "Pre Check-In", "Scan"), language pill (flag + "EN") at right.
Brand header (circular hotel logo + name) + collapse toggle, a search field, a user block, a nav list with leading line icons and an expandable "Hotel" item, and a footer with a language switcher, "Download App", and Terms / Privacy.
Anchored popover, used for assignee pickers ("Robert Williams"), the date-range "Last 7 days" selector, row overflow (3-dot) menus, and the caret half of split-buttons. 32px row, --line-default separators.
Guesteria does not ship a command palette. Its console equivalent is a centered global search field in the top bar, present on every console screen, plus a per-list search inside panels; the guest drawer carries its own full-width "Search" input. Advanced search behavior below is illustrative - low-confidence, only the field itself is observed.
This will mark the request Canceled and notify the guest. This action can't be undone from the request list.
Centered, ~480px max width, 16px radius, --shadow-xl, scrim --surface-overlay. Primary CTA right of the footer, cancel at left.
Use for guest action menus and currency/option pickers where a dropdown would clip. Placement is inferred from the mobile-native pattern requirement, not directly observed in a twin.
Tooltip: ~4px radius, --surface-inverse background, --text-inverse, on collapsed nav icons and utility glyphs. 120ms open delay.
Monday, 16 June 2025 - Occupancy 420 80% / Guest Satisfaction 8.5/10.
~12px radius, --shadow-lg. Auto-dismiss info/success; keep error until dismissed.
The shipped queue runs THIRTEEN columns in this order: row checkbox, priority marker, Name, Rooms, Requests, Created, Due date, Status, Created by, Responsible, Payment, the manager's action split button, and an overflow ellipsis (Front Desk/FD - Requests list - Guest.png). There is no money on the row. The guest's own card carries the price and "Pay now"; the operator gets a Payment PILL - "Unpaid" red, "Paid" green - riding beside a separate status pill, so a request can be Approved and Unpaid at once. The abridgement below drops Created / Due date / Created by / Responsible for width; the priority marker demonstrates both of its states (an orange filled circle for high, a grey outline for normal). Sortable columns with up-arrow sort glyphs, select-all + row checkboxes, hairline row dividers, sticky header, and a per-row action cluster. Body 14/20; column headers muted gray. The guest cell is the .guest-chip component, and it is a THREE-COLOUR cluster, not one tint: a warm sand ROUNDED-SQUARE avatar tile carrying the initials, a NEUTRAL grey room-number pill overlapping its lower edge, the guest name in near-black, and the room-type code in the warm olive --ctx-2-700 (Front Desk/FD - Chats 3.png, enlarged). The manager action is the split-button, slate at the intermediate states and status-coloured only at Done and Canceled (11.2).
| ! | Guest | Request | Status | Room | Payment | |
|---|---|---|---|---|---|---|
| AS312 | Late check-out | Approved | 312 | Unpaid | ||
| AC112 | Breakfast in the room | Done | 112 | Paid | ||
| HS214 | Room Service #201 | New | 201 | Unpaid | ||
| JD312 | Baby Crib x2 | Canceled | -- | -- | ||
| RWRobert WilliamsFront Desk | Internal Chat | On Hold | -- | -- |
The two avatar shapes are the opposite way round from what a reader expects. A STAFF or operator row takes a CIRCULAR avatar - a photograph where one exists - with a grey role caption under the name and no room tag (Front Desk/FD - Requests list - Guest.png, the Created by column; Staff/staff - Chats.png). The GUEST-chip takes the rounded SQUARE tile with initials and the room pill. Code / IDs: reservation IDs render in mono with tabular numerals - 2947594234 - and so does every amount where an amount belongs, which on the console is the guest's request detail and never the queue row.
One component, three room types. The rounded-square avatar tile carries the initials in warm sand, the neutral grey tag near its bottom edge carries the room number, and the small uppercase code carries the room type in warm olive. Observed codes: FML, PCP, STC, ST-C, LSV, XT11, SGL, PLX (Front Desk/FD - Chats 3.png, Front Desk/FD - Requests list - Guest.png). The COMPONENT is console-only - the avatar tile plus the overlapping room pill plus the code line is an operator's addressing device. The room NUMBER and the room-type CODE are not console-only: the guest stay card reads "Family (FML) Room #312" and a staff task card reads "Room: #112 FML" (Guest/Guest-Dashboard+Sidebar1.png, Staff/staff - Dashboard - Listed Task.png).
A ranked variant shows Top-5 with progress bars; a scheduling variant is a weekly grid.
Shape encodes WHO, and it is inverted from the intuitive reading. Round = staff, operator or team - a photograph wherever one exists, with a grey role caption. Rounded square = a GUEST, initials on warm sand, carrying the room pill. Never draw a guest round or a colleague square.
| Variant | Background | Text | Use |
|---|---|---|---|
| Neutral | --surface-sunken | --text-secondary | Category pills (Restaurant, Room, Laundry), transport chips, assignee chips |
| Room pill | --ctx-3-600 neutral grey | #FFFFFF | The room NUMBER on the console guest-chip - solid neutral. The number itself also appears as plain text on guest and staff cards; only this pill is console-only |
Brand (.badge-brand) | --brand-50 | --brand-700 | Unread count badges, "Service" chip, brand-tied tags, the active state |
| Skyline (staff/ops) | --ctx-1-200 | --ctx-1-800 | Staff/ops data: Arrivals 45, Occupancy 420 80%, bell 8 |
| Earthy (guest) | --ctx-2-200 / --ctx-2-50 | --ctx-2-800 / --ctx-2-700 | Guest data: the avatar tile, stay dates, offer name, and the ROOM-TYPE CODE (FML, PCP, ST-C) where the surface renders it warm - the code reads warm olive on Front Desk/FD - Chats 3.png (R-B about 24) and neutral dark grey on Front Desk/FD - Requests list - Guest.png, so warm olive is a SURFACE-dependent rendering, not a global token. The room number beside it is neutral on both |
| Success | --status-success-soft | #065F46 | Approved, Done, Paid |
| Warning | --status-warning-soft | #92400E | New, On Hold |
| Error | --status-error-soft | #9F1239 | Canceled, Not sent |
Additional chip types from the product: removable preference tags; "TOP" / promo badges (orange) on service cards; language pills (flag + "EN"); date-range chips; the gray-total + violet-unread dual count badge in the nav. Filter chips ("All" / "Priority") are pills with an optional trailing "x"; the selected chip uses the violet variant.
.hl — BothThe inline highlight tag (.hl) is a separate primitive - NOT a badge. Use it sparingly to focus a PHRASE inside running copy with a contrast tint behind the text: .hl (violet) for a brand rule, .hl-staff for a staff rule, .hl-guest for a guest rule. Never a status signal.
Brand rule: violet marks the amount, the unread count and the active item.
Console rule: the rail stays white and its eyebrows stay grey.
Guest rule: the guest-app primary action stays navy on every screen, "Pay now" included.
Photos use cover: the frame is filled, the crop is accepted.
The in-product phone-preview mockup uses contain: nothing of the screen is cropped away. Decorative images take alt="" and role="presentation"; everything else always carries an alt. Images use srcset with 1x / 2x / 3x.
Hit targets: 44px is the floor on touch (the guest app is mobile-first). The desktop console is deliberately denser and its controls measure below that - .btn-sm 28px, a dropdown row 32px, the split button ~30px, a rail item 36px - because there the whole ROW is the target, not the label. Do not read 36px as a desktop minimum. Every interactive element has a non-colour affordance (icon, underline, border) in addition to colour - status pills carry a glyph and a label, not colour alone.
Lift copy off a photographic or coloured surface three ways, same primitives as the creatives but web-tuned: a RHYTHM tint over the image (a colour-coded overlay), a LIQUID-glass panel (frosted - over a dark image use .glass--ink so the light text reads), or a SOLID .island callout (a dashboard announcement). The island radius tracks its type; glass sits over a ground only.
.btn-liquid wears the .glass material on a button: a light frost takes a DARK label (over a light / photo-light ground); --ink is a dark frost with a LIGHT label (over a dark ground / photo); --ctx1 / --ctx2 mix a rhythm tone into the frost. A library glyph rides INSIDE the button (stroke=currentColor, so the icon recolours WITH the label as the rhythm tone changes). Like all glass, it sits over a GROUND, never the plain canvas.
Behaviour within the color rhythm: the SAME action (icon + label) recoloured by each rhythm tone - only the frost tint + the inherited text/icon colour shift, never the geometry.
The liquid approach beyond the buttons: a frosted .island.glass wrap-block + a liquid .tagwrap focus-wrap, over a COLOUR rhythm field and over a darker field. Light frost -> dark text over a light field; .glass--ink -> light text over a dark field / photo.
Run the whole flow from one calm console.
A message that reads over any ground.
A guest offer card is a PHOTO card, not a pricing-plan column. The photo is the card; over it sit an orange TOP badge and a grey translucent category chip; under it the name, then the price in brand violet. They lay out TWO-UP, in the catalogue grid, under a horizontal Featured / Recommended carousel band (Guest/Guest - Activities_grid.png, Guest/Guest - Dashboard - Check-in State.png). There is no feature list and no plan column on any guest screen - the earlier .feature-list / pricing-column reading was template residue, and it is withdrawn. The one card that carries a spec row is the upgrade offer, which sets two pills side by side instead of a bulleted list (Guest/Guest - Pre-check-in-Step 3.png).
Photo, badge, chip, name, violet price - in that order, two-up. The commit action is NOT on the card: it lives on the request detail the card opens, and it is the navy guest primary ("Pay now"), never a per-card button row. A catalogue screen is a Featured / Recommended carousel band above this grid.
12 Layout
Spacing and grid are inferred (the source defines no numeric spacing tokens; only "rounded / pill" plus approximate twin px). Base unit 4px - every spacing token is a multiple. Section rhythm 64px; subsections 32px; in-card stacking 16px. The console runs dense but gridded with generous card padding; the guest app runs roomy with one content card high on the screen.
| Dimension | Value |
|---|---|
| Spacing scale | 4, 8, 12, 16, 24, 32, 48, 64, 96, 128 |
| Container widths | the console is a full-bleed dashboard (cap ~1440 to keep tables scannable); the guest app is a 446px mobile artboard; marketing centers ~1200; reading content ~640 |
| Page gutter | 24px at <768, 32px at >=768, 48px at >=1280 |
| Grid | 12 columns on the console. The guest app runs TWO grids, chosen by screen kind: the dashboard and the wizard are a single column with horizontal card carousels (Guest/Guest - Dashboard - In stay State.png), and every CATALOGUE screen is a two-column grid of photo cards - Activities, Services, Amenities (Guest/Guest - Activities_grid.png, Guest/Guest - Amenities_grid view.png). The grid does not replace the carousel: Activities and Services each keep a horizontal Featured / Recommended carousel BAND above the grid, so a catalogue screen is a band plus a grid. A browse screen is a grid; a task screen is a column |
| Section rhythm | 64px between sections, 32px between subsections, 16px inside a card |
A horizontal rule built from the brand line (assets/curves/divider-1--wave.svg, traced from the divider-line asset): an asymmetric monoline that runs full 100% width and BLEEDS off both side edges, while the whole wave stays visible top-to-bottom. Height is a viewport tier (.dw-sm / .dw-md / .dw-lg = 10 / 20 / 30vh). The stroke is a near-tone of the ground. Three variants keep it from reading as a repeat, and all three are rendered below, in file order: asymmetric divider-1, calm divider-2, busy divider-3. It is a DERIVED full-width rule, so preserveAspectRatio="none" is allowed - not a cropped-corner brand curve. It is the ONLY sanctioned exception to the slice / named-edge law.
1 of 3 - divider-1--wave.svg, the ASYMMETRIC variant and the default: two shallow undulations that DRIFT upward across the width, leaving the left edge low and arriving high at the right. It is the DEEPEST of the three - the largest vertical travel across the 121-unit box. Use it where the sections above and below carry different weight, since the drift gives the rule a direction. All three are drawn here at .dw-md = 20vh, so the only thing that changes between them is the path.
2 of 3 - divider-2--wave-calm.svg, the CALM variant: one shallow S, near-symmetric about the centre and returning to within a hair of the height it started at. It is the QUIETEST of the three - the least vertical travel. Use it where the divider must not compete - between two dense sections, or under a heading that already carries a curve.
3 of 3 - divider-3--wave-busy.svg, the BUSY variant: the same one-S shape as the calm, but deeper, and flattened at crest and trough - both control pairs sit at one height - so it holds at the extremes and turns fast through the middle. Use it where the divider is the only ornament in view. Never run the same variant twice in a row - three variants exist so that consecutive dividers do not repeat.
13 Surface directions
Guesteria's surfaces are not one responsive layout: they are THREE tonally independent design directions sharing one brand — a white, dense Front-Desk / Tenant / Admin console (desktop web, 1296x848 artboards), a warm, airy Guest app (iOS, mobile web, WhatsApp, 446x948) and a cool, compact Staff app (mobile, WhatsApp, same 446x948). A viewer can name the surface from the page ground alone, with the type and photography cropped out. The surface sets only the CANVAS; component colour is carried by the OBJECT KIND it represents, not by the block, and not by the actor holding the phone.
The staff app is not the console on a phone and not the guest app for staff. Its ground is the arithmetic inverse of the guest ground, it re-implements the request card, the status pill and the bottom bar rather than reusing the guest ones, and its status vocabulary has already drifted from the other two - Done renders violet there while the green pill reads "Finished" (Staff/staff - Dashboard.png, Staff/staff - Dashboard - Listed Task.png, Staff/staff - Chats.png). Every shared component is tested three times.
Front Desk/FD - Requests list - Guest.png, Front Desk/FD - Requests - View request -Guest.png). Multi-column sortable tables, KPI tiles, a white left nav rail with a property switcher and dual count badges, and a top bar with global search (no command palette). Photography appears only as a 32-40px row thumbnail. One shell serves three roles - the same rail and top bar carry "Front Desk / Verde Canario" and "Guesteria Admin / Hotel Brand #1".Observed info-chips, read off the master Front-Desk screens and kept verbatim. Staff/ops chips carry the Skyline role; unread inbox counts and the active state stay violet.
--ctx-2-* (Earthy Comfort); the PRICE is violet and the pay action beside it is navy.Observed info-chips, read off the master Guest screens. Guest data carries the Earthy role; the price renders in the brand violet on every guest screen sampled.
The price 40 EUR is the brand violet; "Pay now" beside it is dark navy with a card glyph. Violet and navy have swapped the roles a reader expects: violet marks the AMOUNT, navy COMMITS (Guest/Guest - My requests1.png, Guest/Guest - Chats.png).
--ctx-1-50) carrying white task cards, each with a fixed-width photo strip down its left edge and a category tab on the photo. A flat opaque 4-tab bar - Dashboard, Schedule, Chats, Account - with no raised tab and no translucency. The filter row IS the count row: horizontally scrolling tiles where each tile is both the number and the filter. The CTA is full-width, ~40px, and coloured by the verb (Staff/staff - Dashboard.png).Observed on the master Staff screens. Two cards with the SAME status, Approved, carry different buttons - assignment picks the verb, not status alone:
"Done" is VIOLET here and "Finished" is the green one - a word the status table does not otherwise carry. Do not assume the guest app's status colours transfer.
Context is bound to the smallest element that carries the distinction, not to the block, so one row can hold several at once. A content-heavy row stays WHITE: tint only the low-detail header strip, then put the dense content in a white inner card. Below, a Front-Desk Requests work-row carries a guest avatar tile (warm) beside a neutral room pill and an olive room-type code, a violet-outlined per-message translate pill, and a SLATE Approve split-button — four colour jobs in a single row, none of them tinting the row itself:
Independence is real: a component may exist on one surface and not the others - the staff app has presence tiles and a shift grid that no other surface carries, and the guest app shows no staff identity at all, attributing every reply to "Cocierge". Tag every component by surface (Front-Desk / Guest / Staff / Both); tint it by the OBJECT KIND it carries (a guest request is cool, an internal request warm yellow, a note warm peach, a guest identity warm sand and olive), and keep the tint off every container.
14 User-story blocks
No one-off styling; every block is traceable to a real screen.
.guest-chip and a SLATE Approve split-button. Rebuilt from components.data-table + components.badges-chips. Screens: Front Desk/FD - Dashboard.png, Front Desk/FD - Requests list - Guest.png..guest-chip in the list, and a hanging translation pill under each bubble. Two things are OPERATOR-only. Merge fields render LITERALLY in the composer and in the operator's own outbound bubble ({{guestFirstName}}, {{guestProductPage}}) and resolve on send - the conversation-list preview of that same message already reads "Hey, Maria"; no guest screen carries a token (Front Desk/FD - Chats 3.png against Guest/Guest - Chats.png). And the transport chip ("WhatsApp") rides beside every timestamp on the console while the guest thread carries no transport mark at all. Translation is a per-message pill labelled by ACTION - Translate, Translating, See original - attached outside the bubble at its trailing edge. There is no thread mode, no language picker, and the word "AI" appears nowhere on any screen; the target language is a reservation attribute ("Preferred language: Spanish"), resolved before the first message. The in-flight "Translating" state sits on the OUTBOUND bubble, which is the tell that translation is a send-path step and not a display filter.sources/app/ui-approaches.md (Guest/Guest - Pre-check-out - Step 1.png, Guest/Guest - Pre-check-out - Step 2.png, Guest/Guest - Pre-check-out - Step 4.png). The denominator must be derived from the enabled step set - a hard-coded "N/M" per screen cannot survive a wizard whose length is a console setting. Screens: Guest/Guest - Pre-check-in-Step 1.png, FD_Settings/FD_Settings - Pre Check-In-Step 7.png.components.cards + components.buttons. Screens: Guest/Guest - Chats.png, Guest/Guest - My requests1.png.Guest/Guest - Chat - Rate the communication.png, Guest/Guest - Request_feedback.png). The same five gold stars carry the feedback back into the console's request detail. Warm canvas, neutral bill text, gold stars. Rebuilt from components.cards + components.badges-chips + components.form-fields.selection.md L155-160). Line items are the shipped part; summing them here would be an unsourced number.Rule: a story block ships only when it cites the source screen it reconstructs. No screen, no block.
15 Depth
Seven radius tokens, four shadow tiers. Cards step from sm to md on hover; modals and drawers sit on xl. Radius values are inferred from approximate twin pixels (cards ~12px, inputs ~8px, guest cards ~16px) - the source mandates "rounded / pill", not exact numbers.
16 Responsive
Six breakpoints. The guest app is mobile-first (xs-sm); the operator console is desktop-first (lg-2xl). Breakpoints are inferred; the PRD requires platform-native mobile patterns. Touch targets are 44px minimum on md and below.
| Token | Range | Strategy |
|---|---|---|
xs | < 480 | Guest and staff app default: one column for task screens, TWO columns for catalogue screens, bottom tab bar, bottom-sheet menus, sticky primary CTA |
sm | 480-767 | Same two grids, sticky bottom CTA |
md | 768-1023 | Console rail collapses; right panel stacks under content |
lg | 1024-1279 | Console full left rail + content + optional right panel |
xl | 1280-1535 | Default console dashboard layout |
2xl | >= 1536 | Console caps ~1440 to keep tables scannable, never wider |
17 Dashboard preview
The real Guesteria Front-Desk dashboard: a WHITE left nav rail with NEUTRAL group eyebrows and one violet active item + top bar + the central dashboard grid + a collapsible right "Guest Experience" panel, inside a rounded dark device frame. The page ground is white; the cool tint appears only on the low-detail panel headers. Each component is coloured by the object it carries - staff/ops counts Skyline, the guest in each work-list row a .guest-chip (warm tile, neutral room pill, olive code), the manager action a SLATE split-button, the dense table on white (Front Desk/FD - Dashboard.png).
| Request | Guest | Status | Room | Started | |
|---|---|---|---|---|---|
| Late check-out | AS312 | Approved | 312 | 9:00 AM | |
| Breakfast in the room | AC112 | Done | 112 | 8:30 AM | |
| Room Service #201 | HS214 | New | 201 | 10:00 AM | |
| Baby Crib x2 | JD312 | Canceled | -- | -- |
18 Agent prompt guide
brand violet #826AFF
brand deeper #532DF5
brand darkest #2D2F44
violet soft #C7BCFF
violet tint #F2F0FF
focus ring #A59CD3 (idle field focus border - desaturated, never the CTA)
control active #4E4670 (checked/toggle/slider fills - desaturated, never the CTA)
guest CTA navy #2D2F44 (--brand-800: EVERY guest primary - Next, Pay now, Confirm)
split slate #6D82A3 (--ctx-1-700: Set / Approve / To Do; only Done green, Canceled red)
staff verbs blue Get, orange Start, green Finish - one hue per verb, staff app only
.btn-staff #2E4258 (LEGACY alias, not shipped on any screen)
.btn-guest #443F2C (LEGACY alias, not shipped on any screen)
Skyline blue #A2B8D6 (ctx-1: staff/ops data)
Earthy beige #CAC19F (ctx-2: guest data + the guest-chip avatar tile)
olive / taupe #878065 (--ctx-2-700: wizard progress; ROOM-TYPE CODES where the surface renders them warm)
room pill grey #6E6B79 (--ctx-3-600: the room NUMBER, console only)
guest price #826AFF (--brand-600, in product #826BFF - violet, never neutral)
guest canvas #EAE7E1 (--surface-guest: the third surface token)
staff canvas #F3F7FC (--ctx-1-50: the inverse of the guest ground)
console canvas #FFFFFF (#F4F4F5 is a PANEL fill inside the page, not the ground)
card #FFFFFF
text #0A0A0B
muted #52525B
line #E4E4E7
success #13B981
warning #F59E0B
error #E11D48
info #2563EB
star gold #F5B100
radius card 12 (console) / 16 (guest)
radius btn 8
shadow card 0 1px 2px rgba(10,10,11,0.04)
shadow modal 0 24px 64px rgba(10,10,11,0.18)
font display Codec Pro
font body Source Sans 3
What an agent generating a Guesteria surface applies, and what it must never do.
--surface-canvas), warm guest (--surface-guest #EAE7E1), cool staff (--ctx-1-50). The surface only sets the ground, and only as a low-detail frame - it does not tint the components inside, and it never floods a data-dense block. Cool blue-grey on a console page is a grouped-PANEL fill, never the page ground.--ctx-1-*; guest data → Earthy --ctx-2-*; a guest request cool, an internal request warm yellow, a note warm peach. Apply it to the smallest element that carries the distinction - a button fill, a chip outline, a two-letter avatar tile - and keep every container neutral..guest-chip component - a warm rounded-SQUARE avatar tile, a NEUTRAL grey room-number pill on its lower edge, and the room-type code in warm olive (--ctx-2-700). A staff or operator row is a CIRCULAR avatar, a photo where one exists, with a grey role caption and no room tag. Never swap the two shapes.--brand-800, always, including "Pay now". Staff primary = the verb's own hue (Get blue, Start orange, Finish green). Console manager action = the split-button, slate at the intermediate states. Console create action = violet. Violet is otherwise a MARK, not a button: the price, the unread count, the active-nav fill, the translation pill..feature-list class stays in the stylesheet for non-product surfaces; no guest screen uses it..nav-links link's href="#id" pairs with a <section id="id"> in the body, ids unique; an inline scroll-spy lights the matching .nav-link (a desaturated --control-active underline via .nav-link.is-active) for the section in view. Wire ids before relying on it.--brand-600), on every guest screen - card grids, dashboard carousels, request cards and chat cards alike. The commit action beside it is navy. The system has no warm-red commerce hue.--focus-ring border + --focus-ring-soft glow on white; committed controls fill --control-active. Never set focus or an idle/committed control to the saturated --brand-600..guest-chip, with the room-type code in mono olive (FML / PCP / ST-C); color balances (green/red). Overdue is a RED DATE, not a pill - no "Overdue" badge exists anywhere.--focus-ring (#A59CD3) + --focus-ring-soft; committed controls use --control-active (#4E4670).--brand-800, "Pay now" included. Violet on a guest surface marks the price, not the button.--ctx-*-50/--brand fill. Tint a low-detail header strip and white-wrap the content; tint each component by the actor/data it carries.--brand-600) on every guest screen; a warm-red price hue is not a brand colour and stays excluded.width or height. Animate transform and opacity.#FFFFFF but text bottoms at #0A0A0B.