/* ==========================================================================
   Reservations — design system
   Written with CSS logical properties throughout, so switching the interface
   to Arabic flips the whole layout to RTL without a second stylesheet.
   ========================================================================== */

:root {
  /* The redesign, Oct 2026: the look of a Tabler dashboard in Liwan's own
     teal. A cool grey page, white cards with a hairline border and almost no
     shadow, quiet grey headings over the data, and colour kept for the things
     that are a state — free, occupied, owed. */

  /* Neutrals */
  --bg: #f6f8fb;
  --surface: #ffffff;
  --surface-2: #f8fafc;
  --surface-3: #f1f5f9;
  --border: #e6e8eb;
  --border-strong: #dadfe5;
  --text: #182433;
  --text-2: #49566c;
  --text-muted: #667382;
  --text-soft: #8a97ab;

  /* Tables: a light band of small grey headings, rules between the rows and
     none between the columns. */
  --table-head: #f6f8fb;
  --table-head-text: #667382;
  --table-grid: #e6e8eb;

  /* Brand */
  --brand: #0f766e;
  --brand-dark: #0b5a54;
  --brand-light: #d5efec;
  --brand-soft: #eef8f7;
  --brand-ring: rgba(15, 118, 110, .2);

  /* Room states — Tabler's own hues, each with the light wash it uses for a
     "-lt" badge, so a state looks the same on the board, in a table and on a
     badge. */
  --free: #2fb344;
  --free-bg: #eaf7ec;
  --free-br: #b5e3bd;
  --free-ink: #1d6b2b;

  --busy: #d63939;
  --busy-bg: #fbebeb;
  --busy-br: #f1b9b9;
  --busy-ink: #a42d2d;

  --arriving: #f59f00;
  --arriving-bg: #fef5e5;
  --arriving-br: #fcd99a;
  --arriving-ink: #8a5a00;

  --cleaning: #066fd1;
  --cleaning-bg: #e6f1fa;
  --cleaning-br: #a8cdef;
  --cleaning-ink: #0a4e95;

  --maintenance: #ae3ec9;
  --maintenance-bg: #f7ecfa;
  --maintenance-br: #dfb5ea;
  --maintenance-ink: #7a2a8f;

  --renovation: #d6336c;
  --renovation-bg: #fbebf0;
  --renovation-br: #f0b3c8;
  --renovation-ink: #9c234e;

  /* Bronze: nothing else on the board is brown, so the company's own use is
     never mistaken for "available". */
  --owner: #a0601a;
  --owner-bg: #f8eee3;
  --owner-br: #e6c9a8;
  --owner-ink: #7a4810;

  --other: #78716c;
  --other-bg: #f3f3f2;
  --other-br: #d6d3d1;

  --blocked: #49566c;
  --blocked-bg: #eef0f3;
  --blocked-br: #d4d9e0;

  /* Feedback */
  --danger: #d63939;
  --danger-bg: #fbebeb;
  --warn: #c77f00;
  --warn-bg: #fef5e5;
  --ok: #2fb344;
  --ok-bg: #eaf7ec;
  --info: #066fd1;
  --info-bg: #e6f1fa;

  --radius: 6px;
  --radius-lg: 8px;
  --radius-sm: 4px;
  --shadow-sm: 0 1px 1px rgba(24, 36, 51, .04);
  --shadow: 0 2px 4px rgba(24, 36, 51, .05), 0 1px 1px rgba(24, 36, 51, .04);
  --shadow-lg: 0 12px 28px rgba(24, 36, 51, .12), 0 2px 6px rgba(24, 36, 51, .05);

  --shell-max: 1640px;
  --topbar-h: 52px;

  /* The phone's petrol band. The web side no longer uses it — its bar is
     white — but the shared screens that read these keep working. */
  --header-from: #0b3b38;
  --header-to: #134e4a;
  --on-header: #ffffff;
  --on-header-quiet: #a7d8d2;
  --on-header-line: rgba(255, 255, 255, 0.22);
  --on-header-fill: rgba(255, 255, 255, 0.11);
  --pop: #5eead4;
  --pop-ink: #0b3b38;

  /* Controls are flat, as Tabler's are: a white face, a hairline border and
     a shadow one pixel deep. Kept as tokens so a screen that reads them
     changes with the rest. */
  --bevel: 0 1px 1px rgba(24, 36, 51, .04);
  --bevel-strong: 0 1px 1px rgba(24, 36, 51, .08);
  --bevel-press: inset 0 1px 2px rgba(24, 36, 51, .12);
  --face: #ffffff;
  --choice: #0f766e;
  --choice-dark: #0b5a54;
  --choice-glow: rgba(15, 118, 110, .25);

  /* The Arabic face is shipped with the system (see @font-face below), so the
     interface looks the same on the desk's machine, the manager's laptop and a
     phone, whether or not anything is installed on them. The names after it
     are only there for the seconds before the file arrives. */
  --font: "Liwan Arabic", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-ar: "Liwan Arabic", "Segoe UI", "Tahoma", "Dubai", "Noto Naskh Arabic", system-ui, sans-serif;
  --mono: "Cascadia Mono", "Consolas", ui-monospace, monospace;
}

[dir="rtl"] {
  --font: var(--font-ar);
}

/* Readex Pro, shipped with the system rather than borrowed from the machine it
   is opened on. Two weights: the regular for data, the heavier one for
   headings — the same pair the PDFs use, because config/pdf.py reads these
   very files. Both were cut from the family's variable font to fixed weights,
   so nothing here depends on a browser supporting variable fonts.

   To change the face for the whole system, drop two .ttf files into
   static/fonts/ and point these two rules at them. */
@font-face {
  font-family: "Liwan Arabic";
  src: url("../fonts/ReadexPro-Regular.0e2587bc2d76.ttf") format("truetype");
  font-weight: 100 550;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Liwan Arabic";
  src: url("../fonts/ReadexPro-SemiBold.e96c67223f7e.ttf") format("truetype");
  font-weight: 551 900;
  font-style: normal;
  font-display: swap;
}

*,
*::before,
*::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-dark); text-decoration: underline; }

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.3; }
h1 { font-size: 20px; }
h2 { font-size: 16px; }
h3 { font-size: 15px; }

/* ==========================================================================
   App shell
   ========================================================================== */
.app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* A closed dropdown is only visibility:hidden, so it still takes part in the
     document's scrollable area — the panels belonging to items near the edge
     stuck past it and put a horizontal scrollbar on every page. `clip` rather
     than `hidden`: it trims that overhang without creating a scroll
     container, so the sticky bar keeps sticking and open menus still hang
     down over the page. */
  overflow-x: clip;
}

/* ==========================================================================
   Application bar — Tabler's two white rows: the brand and the user on top,
   the navigation with its icons underneath, the screen you are on underlined
   in teal. It follows the page's direction, so in Arabic the brand is on the
   right where an Arabic reader starts.
   ========================================================================== */
.appbar {
  background: var(--surface);
  color: var(--text);
  border-block-end: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  position: sticky;
  top: 0;
  z-index: 40;
}

.appbar__top {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 58px;
  padding: 8px 32px;
  /* The row keeps its order in Arabic, as he asked: the mark on the left,
     the user tools on the right. Mirroring it moves furniture people have
     already learnt the place of, for no gain — the mark is Latin anyway.
     What is written inside the tools still reads as Arabic, below. */
  direction: ltr;
}
/* The greeting and the user menu are sentences, and read as Arabic. */
html[dir="rtl"] .usermenu__label,
html[dir="rtl"] .usermenu__menu { direction: rtl; }

.appbar__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.appbar__brand:hover { text-decoration: none; color: var(--text); }
.appbar__mark { width: 34px; height: 34px; border-radius: 8px; display: block; flex: none; }
/* Latin script in both interfaces, so the block is set left-to-right: in an
   Arabic page `flex-start` on a column would be the right edge, and the name
   would hang off the end of the strapline under it. */
.appbar__brandtext {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  align-items: flex-start;
  direction: ltr;
  unicode-bidi: isolate;
}
.appbar__name { font-size: 17px; font-weight: 650; letter-spacing: .1px; }
.appbar__subtitle {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.appbar__tools { display: flex; align-items: center; gap: 12px; flex: none; }
/* Which design a redesign preview is showing — only there. */
.appbar__preview {
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  background: var(--arriving-bg);
  color: var(--arriving-ink);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
}

/* Who is signed in, as Tabler draws it: a square of initials, the name and
   the role beside it. The whole of it opens the user menu. */
.usermenu { position: relative; z-index: 30; display: flex; }
.appbar .usermenu__trigger {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px 4px 6px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  cursor: pointer;
  text-align: start;
}
.appbar .usermenu:hover > .usermenu__trigger,
.appbar .usermenu:focus-within > .usermenu__trigger,
.appbar .usermenu.is-open > .usermenu__trigger {
  background: var(--surface-3);
}
.avatar {
  width: 34px;
  height: 34px;
  flex: none;
  display: inline-grid;
  place-items: center;
  border-radius: var(--radius);
  background: var(--brand-light);
  color: var(--brand-dark);
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1;
  text-transform: uppercase;
}
.usermenu__label { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.usermenu__label b { font-size: 13px; font-weight: 600; white-space: nowrap; }
.usermenu__label span { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
@media (max-width: 640px) { .usermenu__label { display: none; } }

/* Anchored at the end of the bar, so it opens inwards. Qualified with
   .appbar to outweigh `.topnav__menu { inset-inline-start: 0 }` further down:
   with both insets and a min-width the box is over-constrained, and in
   Arabic the browser dropped the wrong one. */
.appbar .usermenu__menu {
  inset-inline-start: auto;
  inset-inline-end: 0;
  top: calc(100% + 6px);
  min-width: 220px;
}
.usermenu__who { padding: 8px 12px 4px; line-height: 1.35; }
.usermenu__who b { display: block; font-size: 13px; color: var(--text); font-weight: 600; }
.usermenu__who span { font-size: 11.5px; color: var(--text-muted); }

.appbar .btn--bar {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}
.appbar .btn--bar:hover { background: var(--surface-3); }

/* ==========================================================================
   Horizontal nav with dropdowns
   Opens on hover and on keyboard focus with no script at all; app.js adds a
   click toggle on top of that, because a touch screen has neither.
   ========================================================================== */
.topnav {
  border-block-start: 1px solid var(--border);
  position: relative;
  z-index: 20;
}

.topnav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 2px;
  margin: 0;
  padding: 0 32px;
  list-style: none;
  /* Deliberately no overflow-x: setting it alone also promotes overflow-y,
     which would trap the absolutely-positioned dropdowns inside this row.
     flex-wrap handles a narrow window instead. */
}

.topnav__item { position: relative; display: flex; }

.topnav__link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 10px 11px;
  border: none;
  border-block-end: 2px solid transparent;
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: color .12s ease, border-color .12s ease;
}
.topnav__link:hover,
.topnav__item:hover > .topnav__link,
.topnav__item:focus-within > .topnav__link,
.topnav__item.is-open > .topnav__link {
  color: var(--text);
  text-decoration: none;
}
.topnav__link.is-active {
  color: var(--brand);
  font-weight: 600;
  border-block-end-color: var(--brand);
}

.topnav__icon { width: 18px; height: 18px; flex: none; opacity: .85; }
.topnav__chevron { width: 12px; height: 12px; flex: none; opacity: .6; transition: transform .15s ease; }
.topnav__item:hover > .topnav__link .topnav__chevron,
.topnav__item:focus-within > .topnav__link .topnav__chevron,
.topnav__item.is-open > .topnav__link .topnav__chevron { transform: rotate(180deg); }

.topnav__count {
  min-width: 18px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--brand-light);
  color: var(--brand-dark);
  font-size: 11px;
  font-weight: 650;
  line-height: 1.4;
  text-align: center;
}

.topnav__menu {
  position: absolute;
  inset-inline-start: 0;
  top: 100%;
  z-index: 50;
  min-width: 232px;
  max-width: calc(100vw - 24px);
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .12s ease, transform .12s ease, visibility .12s;
}
.topnav__item:hover > .topnav__menu,
.topnav__item:focus-within > .topnav__menu,
.topnav__item.is-open > .topnav__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* The last menus sit near the end of the bar — open them inwards so they
   don't run off the edge. */
.topnav__item--end > .topnav__menu { inset-inline-start: auto; inset-inline-end: 0; }

.topnav__menu li { list-style: none; }
.topnav__menu a,
.topnav__menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 12px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 400;
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
}
.topnav__menu a:hover,
.topnav__menu button:hover,
.topnav__menu a:focus-visible,
.topnav__menu button:focus-visible {
  background: var(--surface-3);
  color: var(--text);
  text-decoration: none;
}
.topnav__menu a.is-active { background: var(--brand-soft); color: var(--brand-dark); font-weight: 600; }
.topnav__menu svg { width: 16px; height: 16px; flex: none; color: var(--text-muted); }
.topnav__menu a:hover svg, .topnav__menu button:hover svg, .topnav__menu a.is-active svg { color: var(--brand); }
.topnav__menu .topnav__count { background: var(--busy-bg); color: var(--busy-ink); margin-inline-start: auto; }

/* The Setup panel: every settings screen at once, laid out in columns — one
   per section — instead of a list long enough to scroll. */
.topnav__menu--setup {
  /* Columns rather than a grid: the sections are different lengths, and this
     balances them into even columns on its own. */
  column-count: 3;
  column-gap: 18px;
  column-rule: 1px solid var(--border);
  width: max-content;
  max-width: calc(100vw - 24px);
  padding: 12px 14px;
  max-height: calc(100vh - var(--topbar-h) - 90px);
  overflow-y: auto;
}
.setup-menu__group {
  display: flex;
  flex-direction: column;
  min-width: 182px;
  /* A section never splits across two columns. */
  break-inside: avoid;
  page-break-inside: avoid;
  margin-block-end: 10px;
}
.setup-menu__group .topnav__heading {
  padding-block: 4px 6px;
  margin-block-end: 3px;
  border-block-end: 1px solid var(--border);
  color: var(--text-muted);
}
.topnav__menu--setup a { padding-block: 7px; }
/* A section with nothing but its heading would be a column of air. */
.setup-menu__group:has(.topnav__heading:only-child) { display: none; }

@media (max-width: 1100px) { .topnav__menu--setup { column-count: 2; } }
@media (max-width: 760px) { .topnav__menu--setup { column-count: 1; } }

.topnav__heading {
  padding: 8px 12px 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.topnav__divider { height: 1px; margin: 4px 6px; background: var(--border); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* The page's own header, as Tabler sets one: no bar of its own, just the
   title on the page's grey with the screen's buttons at the end of the same
   line. */
.topbar {
  min-height: var(--topbar-h);
  background: transparent;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 20px 32px 0;
  flex-wrap: wrap;
}
.topbar__title { font-size: 20px; font-weight: 600; color: var(--text); }
.topbar__spacer { flex: 1; }

/* The bar, the nav under it and the page all start 32px from the edge of the
   screen and use the whole of it — a page that leaves half of a wide screen
   empty has been turned down before. */
.content { padding: 16px 32px 32px; flex: 1; }
.content--wide { padding: 16px 32px 32px; }

/* ==========================================================================
   Cards, sections
   ========================================================================== */
.card {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.card__head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 52px;
  padding: 12px 20px;
  border-block-end: 1px solid var(--border);
}
.card__head h2, .card__head h3 { margin: 0; color: var(--text); }
.card__head h2 { font-size: 16px; font-weight: 600; }
.card__head h3 { font-size: 15px; font-weight: 600; }
.card__body { padding: 20px; }
/* Two cards one after the other on a page were drawn touching. */
.content > .card + .card,
.content > .card + details.card,
.content > details.card + .card { margin-block-start: 16px; }
/* `clip` trims the table's square corners inside the card's rounded ones
   without making a scroll container — a pinned heading inside would
   otherwise be measured against this box instead of the window. */
.card__body--flush { padding: 0; overflow: clip; }
.card__foot {
  padding: 12px 20px;
  border-block-start: 1px solid var(--border);
  background: transparent;
  border-end-start-radius: var(--radius-lg);
  border-end-end-radius: var(--radius-lg);
}

.stack { display: flex; flex-direction: column; gap: 16px; }
/* The same, for rows that belong together — one per unit on the check-in
   screen — where 16px between them reads as separate sections. */
.stack-sm { display: flex; flex-direction: column; gap: 8px; }

/* Main column + a narrower side column. minmax(0,…) stops a wide table inside
   from blowing the grid out instead of scrolling. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 16px;
  align-items: start;
}
.split--even { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
/* Two halves, not "as many as fit": a page whose cards pair off reads as two
   columns, and auto-fit would leave a third of a wide screen empty. */
.split--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* A card that takes the whole width of a split, for a row that needs it. */
.split .card--full { grid-column: 1 / -1; }
@media (max-width: 1180px) {
  .split { grid-template-columns: minmax(0, 1fr); }
}
.row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
/*
  A form that lives inside a table cell. Every control in this system is
  width: 100% by default, which is right in a column of fields and wrong
  here — three of them in one cell would each claim the whole column and
  stack into a tower three rows high.
*/
.cellform { display: flex; gap: 6px; align-items: center; flex-wrap: nowrap; }
.cellform select { width: auto; min-width: 124px; }
/* [type] rather than a bare `input`: the generic `input[type="text"]`
   rule further down this file carries the same specificity and would
   otherwise win on order, stretching a reference box to the full width
   of its cell and pushing everything beside it onto its own line. */
.cellform input[type] { width: 104px; }
/* Four controls in one table cell is one too many for a single line:
   the amount and how it went on the first, the reference and the
   press on the second, rather than a row that scrolls sideways. */
.cellform--wrap { flex-wrap: wrap; row-gap: 5px; }
.row--end { justify-content: flex-end; }
.row--between { justify-content: space-between; }
.grow { flex: 1; }

/* ==========================================================================
   KPI counters
   ========================================================================== */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
}
/* Tabler's small figure card: the label small and grey, the figure large,
   and the state it counts as a coloured line along the top edge. */
.kpi {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
}
.kpi::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  background: transparent;
}
.kpi--free::before { background: var(--free); }
.kpi--busy::before { background: var(--busy); }
.kpi--clean::before { background: var(--cleaning); }
.kpi--maint::before { background: var(--maintenance); }
.kpi--block::before { background: var(--blocked); }
.kpi--rate::before { background: var(--brand); }
.kpi--money::before { background: var(--maintenance); }

.kpi__label { font-size: 12.5px; color: var(--text-muted); font-weight: 500; }
html[dir="ltr"] .kpi__label { font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.kpi__value { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; margin-top: 4px; line-height: 1.25; font-variant-numeric: tabular-nums; white-space: nowrap; }
.kpi__sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

.meter { height: 4px; border-radius: 999px; background: var(--surface-3); overflow: hidden; margin-top: 10px; }
.meter__fill { height: 100%; background: var(--brand); border-radius: 999px; }

/* ==========================================================================
   Room board
   ========================================================================== */
.board-group { margin-block-end: 22px; }
.board-group__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-block-end: 10px;
}
.board-group__title { font-size: 14px; font-weight: 700; }
.board-group__meta { font-size: 12px; color: var(--text-muted); }

.board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(124px, 1fr));
  gap: 10px;
}

.room {
  position: relative;
  display: block;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 11px 9px;
  min-height: 92px;
  color: var(--text);
  transition: transform .09s ease, box-shadow .09s ease;
  overflow: hidden;
}
.room:hover {
  text-decoration: none;
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  z-index: 2;
}
.room::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 4px;
  background: var(--border-strong);
}

.room__number {
  font-size: 22px;
  font-weight: 750;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.room__type { font-size: 11px; color: var(--text-muted); font-weight: 600; }
.room__guest {
  font-size: 11.5px;
  margin-top: 5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.room__dates { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.room__flag {
  position: absolute;
  inset-block-start: 8px;
  inset-inline-end: 8px;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(15, 23, 42, .08);
}

.room--free { background: var(--free-bg); border-color: var(--free-br); }
.room--free::after { background: var(--free); }
.room--busy { background: var(--busy-bg); border-color: var(--busy-br); }
.room--busy::after { background: var(--busy); }
.room--arriving { background: var(--arriving-bg); border-color: var(--arriving-br); }
.room--arriving::after { background: var(--arriving); }
.room--cleaning { background: var(--cleaning-bg); border-color: var(--cleaning-br); }
.room--cleaning::after { background: var(--cleaning); }
.room--maintenance { background: var(--maintenance-bg); border-color: var(--maintenance-br); }
.room--maintenance::after { background: var(--maintenance); }
.room--renovation { background: var(--renovation-bg); border-color: var(--renovation-br); }
.room--renovation::after { background: var(--renovation); }
.room--owner { background: var(--owner-bg); border-color: var(--owner-br); }
.room--owner::after { background: var(--owner); }
.room--other { background: var(--other-bg); border-color: var(--other-br); }
.room--other::after { background: var(--other); }
.room--blocked { background: var(--blocked-bg); border-color: var(--blocked-br); }
.room--blocked::after { background: var(--blocked); }
.room--blocked .room__number, .room--other .room__number { color: var(--text-muted); }

.legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; color: var(--text-muted); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i {
  width: 12px; height: 12px; border-radius: 3px; display: inline-block;
  border: 1.5px solid var(--border-strong);
}
.legend .l-free { background: var(--free-bg); border-color: var(--free); }
.legend .l-busy { background: var(--busy-bg); border-color: var(--busy); }
.legend .l-arriving { background: var(--arriving-bg); border-color: var(--arriving); }
.legend .l-cleaning { background: var(--cleaning-bg); border-color: var(--cleaning); }
.legend .l-maintenance { background: var(--maintenance-bg); border-color: var(--maintenance); }
.legend .l-renovation { background: var(--renovation-bg); border-color: var(--renovation); }
.legend .l-owner { background: var(--owner-bg); border-color: var(--owner); }
.legend .l-other { background: var(--other-bg); border-color: var(--other); }
.legend .l-blocked { background: var(--blocked-bg); border-color: var(--blocked); }

/* ==========================================================================
   Timeline (units × nights)
   ========================================================================== */
.timeline-wrap { border-radius: var(--radius-lg); border: 1px solid var(--border); background: var(--surface); }
.timeline { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 900px; font-size: 12px; }
.timeline th, .timeline td { border-block-end: 1px solid var(--border); border-inline-end: 1px solid var(--border); padding: 0; }
.timeline thead th {
  position: sticky; top: 0; z-index: 5;
  background: var(--table-head);
  color: var(--table-head-text);
  padding: 8px 4px;
  font-weight: 500;
  text-align: center;
  white-space: nowrap;
  font-size: 12px;
  line-height: 1.35;
}
.timeline th.tl-unit, .timeline td.tl-unit {
  position: sticky;
  inset-inline-start: 0;
  z-index: 6;
  background: var(--surface);
  min-width: 132px;
  padding: 5px 10px;
  text-align: start;
  font-weight: 650;
  border-inline-end: 2px solid var(--border-strong);
}
.timeline thead th.tl-unit { z-index: 7; background: var(--table-head); text-align: center; }
.tl-today {
  background: var(--brand-soft) !important;
  box-shadow: inset 2px 0 0 var(--brand), inset -2px 0 0 var(--brand);
}
/* Today is marked down the column itself, on the body cells. In the header it
   used to take the pale wash as well — a pale background under pale text, so
   the one date anybody looks for was the one they could not read. The band is
   the band. */
.timeline thead th.tl-today {
  background: var(--brand-soft) !important;
  color: var(--brand-dark) !important;
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--brand) !important;
}
.tl-weekend { background: #f8fafc; }
.timeline tbody tr:hover td:not(.tl-unit) { background: #f6fafa; }
.timeline tbody tr:hover td.tl-unit { background: var(--brand-soft); }
.tl-cell { height: 32px; position: relative; }
/* A heading row for each kind of unit on the timeline. */
.timeline tbody tr.tl-group td {
  background: var(--surface-2);
  border-block-start: 2px solid var(--border-strong);
  height: auto;
  padding-block: 6px;
}
.timeline tbody tr.tl-group td.tl-unit { font-weight: 800; font-size: 12.5px; color: var(--brand-dark); background: var(--surface-2); }
.timeline tbody tr.tl-group:hover td, .timeline tbody tr.tl-group:hover td.tl-unit { background: var(--surface-2); }
.tl-group__count {
  display: inline-block; min-width: 20px; padding: 0 6px; margin-inline-start: 6px;
  border-radius: 999px; background: var(--brand-light); color: var(--brand-dark);
  font-size: 11px; font-weight: 700; text-align: center;
}

/* The period being shown, under the filter bar. */
.tl-range { font-size: 12.5px; font-weight: 650; color: var(--text); margin-block-end: 10px; }
.tl-quick { display: inline-flex; gap: 4px; }
.tl-clipped {
  margin-inline-start: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--warn-bg);
  color: var(--warn);
  font-size: 11.5px;
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   The bars. Every state carries its own hue in `--c`, and the chip builds a
   raised, lit-from-above solid out of it: a lighter face at the top, the
   colour itself in the middle, a darker foot, a white top edge and a shadow
   on the row below. `background-color` is set before the gradient on purpose
   — a browser without color-mix() drops the gradient and still gets the flat
   colour rather than an invisible chip.

   A room that is off the market is striped as well as coloured, so it never
   has to be told apart from a guest by shade alone.
   -------------------------------------------------------------------------- */
.tl-chip,
.legend i.tl-key {
  /* Flat, as Tabler draws a bar: the state's colour and nothing on top of it
     but, for a room off the market, the stripes in --stripes. */
  background-color: var(--c);
  background-image: var(--stripes, none);
}

.tl-chip {
  position: absolute;
  inset-block: 4px;
  inset-inline: 1.5px;
  border-radius: var(--radius-sm);
  padding-inline: 7px;
  font-size: 11.5px;
  font-weight: 500;
  color: #fff;
  display: flex;
  align-items: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: filter .12s ease, box-shadow .12s ease;
}
.tl-chip:hover {
  text-decoration: none;
  color: #fff;
  filter: brightness(1.06);
  box-shadow: 0 2px 6px rgba(24, 36, 51, .25);
  z-index: 3;
}

/* One hue per state, spaced around the wheel so no two read alike at this
   size. The four stay colours follow the life of a booking — promised,
   here, gone — and borrow the room board's own vocabulary where it has one
   (amber arriving, red occupied, violet maintenance). */
.tl-chip--tent  { --c: #066fd1; }  /* sky — pencilled in, not confirmed */
.tl-chip--res   { --c: #f59f00; }  /* amber — confirmed, due to arrive */
.tl-chip--in    { --c: #d63939; }  /* red — in house */
.tl-chip--done  { --c: #2fb344; }  /* green — stayed and left */
.tl-chip--maint { --c: #ae3ec9; }  /* violet — maintenance */
.tl-chip--reno  { --c: #d6336c; }  /* deep rose — renovation */
.tl-chip--owner { --c: #92400e; }  /* bronze — the company's own use */
.tl-chip--other { --c: #78716c; }  /* stone — off the market for anything else */

.tl-chip--maint, .tl-chip--reno, .tl-chip--owner, .tl-chip--other {
  --stripes: repeating-linear-gradient(
    135deg,
    rgba(255, 255, 255, .26) 0 5px,
    rgba(255, 255, 255, 0) 5px 11px
  );
}

/* The key swatches reuse the chips' own paint, so the legend cannot drift
   away from what the table draws. */
.legend i.tl-key {
  width: 22px;
  height: 13px;
  border: none;
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   Moving a stay from the timeline: a button that lives on the chip and only
   appears when the pointer is on it, so the calendar still reads as a
   calendar rather than a row of controls.
   -------------------------------------------------------------------------- */
.tl-move {
  position: absolute;
  inset-block-start: 4px;
  inset-inline-end: 3px;
  z-index: 4;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  border-radius: 5px;
  background: rgba(255, 255, 255, .92);
  color: #0f172a;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s ease, transform .12s ease;
}
.tl-cell:hover .tl-move,
.tl-move:focus-visible { opacity: 1; }
.tl-move:hover { transform: scale(1.08); background: #fff; }
/* A tablet at the desk has no hover, and an invisible button is no button. */
@media (hover: none) { .tl-move { opacity: .85; } }

/* The extras rows on the booking form: a line per thing charged for, with the
   remove button lined up with the inputs rather than with their labels. */
.extras { display: flex; flex-direction: column; gap: 8px; }
.extras__row {
  display: grid;
  grid-template-columns: 1.4fr 1.4fr .8fr .5fr .9fr auto;
  gap: 10px;
  align-items: end;
}
.extras__row .field { margin: 0; }
.extras__drop { padding: 8px 10px; align-self: end; color: var(--text-muted); }
.extras__row + .extras__row label { display: none; }
@media (max-width: 860px) {
  .extras__row { grid-template-columns: 1fr 1fr; }
  .extras__row + .extras__row label { display: block; }
}

/* The prices grid: a box per unit type and source, narrow enough that a
   property with eight sources still fits across the page. */
.rate-input { width: 110px; text-align: center; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   Cards in the corner: a decision landing while somebody is on another screen.
   Bottom of the page on the side the language starts from, above everything,
   and out of the way of the cursor.
   -------------------------------------------------------------------------- */
.toasts {
  position: fixed;
  inset-block-end: 18px;
  inset-inline-start: 18px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(380px, calc(100vw - 36px));
  pointer-events: none;
}
.toast {
  position: relative;
  display: block;
  padding: 11px 34px 11px 13px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--brand);
  background: var(--surface);
  box-shadow: 0 10px 28px rgba(15, 23, 42, .18);
  color: var(--text);
  pointer-events: auto;
  animation: toast-in .18s ease-out;
}
.toast:hover { text-decoration: none; background: var(--surface-2); }
.toast.is-going { opacity: 0; transition: opacity .6s ease; }
.toast__title { display: block; font-weight: 750; font-size: 13.5px; }
.toast__body { display: block; font-size: 12.5px; color: var(--text-muted); margin-block-start: 2px; }
.toast__close {
  position: absolute;
  inset-block-start: 6px;
  inset-inline-end: 8px;
  border: none;
  background: none;
  color: var(--text-soft);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.toast--ok { border-inline-start-color: var(--ok); }
.toast--bad { border-inline-start-color: var(--danger); }
.toast--ask { border-inline-start-color: var(--arriving); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.move-options { display: flex; flex-direction: column; gap: 6px; max-height: 320px; overflow-y: auto; }
.move-option {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.move-option:hover { border-color: var(--brand); background: var(--brand-soft); }
.move-option__number { font-weight: 700; font-size: 15px; min-width: 56px; }
.move-option__type { flex: 1; color: var(--text-muted); font-size: 13px; }
.move-option__same {
  font-size: 11px;
  font-weight: 700;
  color: var(--free);
  background: var(--free-bg);
  border: 1px solid var(--free-br);
  border-radius: 999px;
  padding: 1px 8px;
}
.move-option__same:empty { display: none; }
.move-option__price { font-weight: 700; font-size: 12.5px; color: var(--text-muted); white-space: nowrap; }
.move-option__price--up { color: var(--danger); }
.move-option__price--down { color: var(--ok); }
.move-option__go { color: var(--text-soft); }
[dir="rtl"] .move-option__go { transform: scaleX(-1); display: inline-block; }

/* The same kind of room: the move that needs no conversation with the guest. */
.move-option--same { border-color: var(--free-br); background: var(--free-bg); }
.move-option--same .move-option__number { color: var(--free); }

.legend--tl { align-items: center; row-gap: 6px; }
.legend__group {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.legend__sep { width: 1px; height: 16px; background: var(--border-strong); }

/* ==========================================================================
   Tables
   ========================================================================== */
/* Tabler's table: a pale band of small grey headings, a rule under every
   row and none between the columns, words from the start of the cell and
   figures to its end so a column of money lines up on its last digit.
   In English the headings are small capitals, as Tabler sets them; Arabic
   has no capitals, so there they are simply small and grey. */
.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th {
  text-align: start;
  font-size: 12px;
  font-weight: 600;
  color: var(--table-head-text);
  background: var(--table-head);
  padding: 10px 12px;
  border: 0;
  border-block-end: 1px solid var(--table-grid);
  white-space: nowrap;
}
html[dir="ltr"] .table th { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; }
.table td {
  padding: 11px 12px;
  border: 0;
  border-block-end: 1px solid var(--table-grid);
  vertical-align: middle;
  text-align: start;
}
.table tbody tr:last-child td { border-block-end: 0; }
.table tbody tr:hover td { background: var(--surface-2); }
.table .num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table th.num { text-align: end; }
.table .center { text-align: center; }
/* A booking number, a guest's name: a link in a cell does not break across
   lines — HTL-26-33008 on three lines was a number nobody could read. */
.table td > a { white-space: nowrap; }
.table .total-row td,
.table tfoot td { font-weight: 600; background: var(--surface-2); border-block-start: 1px solid var(--border-strong); }
.table--compact td { padding: 7px 10px; }
.table--compact th { padding: 8px 10px; }
/* Inside a card the first and last columns keep the card's own margin, so
   the table's edge lines up with the card's heading above it. */
.card .table tr > :first-child { padding-inline-start: 20px; }
.card .table tr > :last-child { padding-inline-end: 20px; }
/* The second, quieter line in a cell: the booking's number under the guest,
   the unit type under the unit, the nights under the dates. */
.cell-sub { display: block; font-size: 12px; color: var(--text-muted); font-weight: 400; line-height: 1.35; }
.table .money { font-weight: 500; }
.table tfoot .money, .table .total-row .money { font-weight: 600; }

/* A person in a list: their initials in a soft square, the name, and a line
   under it. Four tones, picked from the name, so a column of guests is not a
   column of identical tiles. */
.who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.who__text { min-width: 0; }
.who__name { color: var(--text); font-weight: 500; white-space: nowrap; }
.who__name:hover { color: var(--brand); }
.avatar--t0 { background: var(--brand-light); color: var(--brand-dark); }
.avatar--t1 { background: var(--cleaning-bg); color: var(--cleaning-ink); }
.avatar--t2 { background: var(--maintenance-bg); color: var(--maintenance-ink); }
.avatar--t3 { background: var(--arriving-bg); color: var(--arriving-ink); }
.who .avatar { width: 32px; height: 32px; font-size: 12px; }

/* What has been paid, as a bar under the figure. */
.pay-col { width: 150px; min-width: 130px; }
.paybar__line { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; color: var(--text-2); }
.paybar__pct { color: var(--text-muted); font-size: 12px; }
.paybar { height: 4px; margin-top: 5px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.paybar i { display: block; height: 100%; border-radius: 999px; background: var(--text-soft); }
.paybar i.is-full { background: var(--free); }
.paybar i.is-part { background: var(--arriving); }
.paybar i.is-none { background: var(--busy); width: 3px !important; }
.stay-sub { display: flex; align-items: center; gap: 4px; }
.stay-sub svg { width: 12px; height: 12px; flex: none; }

/* ==========================================================================
   Headings that stay put
   A column heading that has scrolled off the top takes the meaning of its
   column with it, so it is pinned the way the save bar at the foot of a form
   is pinned: to the window, just under the application bar.

   That only works while nothing between the table and the page scrolls —
   an element that scrolls on one axis scrolls on both, and a heading inside
   one is measured against it instead of against the window. So the sideways
   scroller is given only to the tables that are actually too wide for their
   card: app.js measures them and marks them `is-wide`, and those get a
   ceiling of whatever is left of the window, with the heading pinned to the
   top of the box. Every other table — nearly all of them — keeps its heading
   under the bar however far the page is scrolled.
   ========================================================================== */
.table thead th {
  position: sticky;
  /* Under the application bar, whose real height app.js publishes. */
  top: var(--appbar-h, 96px);
  z-index: 3;
  /* `border-collapse: collapse` hands the borders to the table, so a pinned
     heading is left with none of its own; a shadow draws the line instead. */
  box-shadow: 0 1px 0 var(--table-grid);
}

.card__body--flush.is-wide,
.table-wrap.is-wide,
.timeline-wrap {
  overflow: auto;
  /* Never so short that the table is a slit, even on a laptop screen. */
  max-height: max(320px, calc(100vh - var(--appbar-h, 96px) - 84px));
}
.is-wide .table thead th { top: 0; }

/* A bar of actions over a long list. It stays under the application bar while
   the rows go past — a button at the foot of two hundred rows is a button
   nobody reaches — and the table's own heading stacks underneath it, which is
   why app.js publishes its height. */
.actionbar {
  position: sticky;
  top: var(--appbar-h, 96px);
  z-index: 4;
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--surface-2);
  border-block-end: 1px solid var(--border);
}
.actionbar .field { margin: 0; }
.actionbar input { min-width: 150px; }
/* The count of what is ticked, on the button that acts on it. */
.pill {
  display: inline-block;
  min-width: 20px;
  padding: 1px 7px;
  margin-inline-start: 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .22);
  font-size: 12px;
  font-weight: 700;
}
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.card:has(.actionbar) .table thead th {
  top: calc(var(--appbar-h, 96px) + var(--actionbar-h, 0px));
}
.is-wide .table thead th,
.card:has(.actionbar) .is-wide .table thead th { top: 0; }

.empty {
  padding: 34px 20px;
  text-align: center;
  color: var(--text-muted);
}
.empty__icon { font-size: 28px; opacity: .35; filter: grayscale(1); display: block; margin-block-end: 8px; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 36px;
  padding: 7px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.3;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.btn:hover { background: var(--surface-2); border-color: #c5ccd6; color: var(--text); text-decoration: none; }
.btn:active { box-shadow: var(--bevel-press); }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--brand-ring); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { flex: none; }
.btn--primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
.btn--danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn--danger:hover { background: #bf3030; border-color: #bf3030; color: #fff; }
.btn--ghost { border-color: transparent; background: transparent; box-shadow: none; }
.btn--ghost:hover { background: var(--surface-3); border-color: transparent; }
.btn--sm { min-height: 30px; padding: 4px 10px; font-size: 12.5px; }
.btn--lg { min-height: 42px; padding: 10px 20px; font-size: 14.5px; }
.btn--block { width: 100%; }

.btn-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }

/* ==========================================================================
   Badges & pills
   ========================================================================== */
/* Tabler's light badge: a square-cornered wash of the state's colour with
   the colour itself, darkened, for the words. No outline. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.35;
  background: var(--surface-3);
  color: var(--text-2);
  border: 0;
  white-space: nowrap;
}
.badge--ok { background: var(--free-bg); color: var(--free-ink); }
.badge--busy { background: var(--busy-bg); color: var(--busy-ink); }
.badge--warn { background: var(--arriving-bg); color: var(--arriving-ink); }
.badge--info { background: var(--cleaning-bg); color: var(--cleaning-ink); }
.badge--muted { background: var(--blocked-bg); color: var(--blocked); }
.badge--dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* A booking source: its own colour as a dot with a halo, and its name in
   the ordinary text colour beside it — the way the Tabler model showed it.
   The colour arrives as --tag from the source record. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  width: fit-content;
  padding: 0;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  background: none;
  color: var(--text-2);
  border: 0;
}
.tag::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--tag, #8a97ab);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tag, #8a97ab) 18%, #fff);
}

/* ==========================================================================
   Forms
   ========================================================================== */
.field { margin-block-end: 16px; }
.field > label,
.label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  margin-block-end: 6px;
  color: var(--text);
}
/* The line of explanation under a box. Asked for gone: the labels say what
   the fields are, and a paragraph under every one of them made a short form
   read as a long one. One rule, so it comes back by deleting it. */
.field .help, .check .help, .help { display: none; }
.field .error { font-size: 12px; color: var(--danger); margin-top: 4px; font-weight: 500; }

input[type="text"], input[type="number"], input[type="date"], input[type="time"],
input[type="email"], input[type="password"], input[type="tel"], input[type="datetime-local"],
input[type="search"],
select, textarea {
  width: 100%;
  min-height: 36px;
  padding: 7px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font: inherit;
  font-size: 13.5px;
  line-height: 1.4;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
  transition: border-color .12s ease, box-shadow .12s ease;
}
input::placeholder, textarea::placeholder { color: var(--text-soft); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--brand) 55%, #fff);
  box-shadow: 0 0 0 3px var(--brand-ring);
}
textarea { min-height: 76px; resize: vertical; }
/*
  A search field is the one input a browser still draws its own way: Safari
  gives it a capsule and its own inset, and both it and Chrome reserve room
  inside for the little clear button. Left alone it sits a different height
  and shape from the select next to it on the same filter bar. Declaring the
  appearance away hands it back to the rule above, which is what every other
  box on the screen is wearing. The clear button stays — it is useful, and it
  no longer changes the field's size.
*/
input[type="search"] { -webkit-appearance: none; appearance: none; }
input[readonly], input:disabled, select:disabled { background: var(--surface-2); color: var(--text-muted); }

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 0 14px; }
.grid-2 .field--wide { grid-column: 1 / -1; }

/* --------------------------------------------------------------------------
   "What is left, by kind of room" — the second counter row on the board.
   Deliberately lighter than the KPI tiles above it: this is a reference strip
   you scan, not a headline.
   -------------------------------------------------------------------------- */
.type-bar {
  display: flex;
  align-items: stretch;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/*
  The line that says what the row under it answers. Small, quiet, and above
  the numbers rather than beside them: it is there to be read once, when
  somebody wonders why two counts of the same hotel disagree.
*/
.board-says {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin-block-end: 8px;
  font-size: 13px;
}
.board-says strong { font-weight: 700; color: var(--text); }
.board-says .muted { font-size: 12px; }

.type-bar__label {
  flex: none;
  align-self: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-soft);
  max-width: 78px;
  line-height: 1.3;
}
.type-bar__tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.type-tile {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 7px 10px 8px;
  background: var(--surface-2);
}
.type-tile__name {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.type-tile__figures { display: flex; align-items: baseline; gap: 5px; margin-block: 2px 5px; }
.type-tile__pct { font-size: 18px; font-weight: 750; color: var(--free); }
.type-tile__sep { color: var(--text-soft); }
.type-tile__count { font-size: 18px; font-weight: 750; color: var(--text); }
.type-tile__of { font-size: 11.5px; color: var(--text-soft); }
.type-tile__bar { height: 4px; border-radius: 999px; background: var(--border); overflow: hidden; }
.type-tile__bar i { display: block; height: 100%; background: var(--free); border-radius: 999px; }

/* Nothing left of this kind — the number that changes a conversation. */
.type-tile--none { background: var(--busy-bg); border-color: var(--busy-br); }
.type-tile--none .type-tile__pct,
.type-tile--none .type-tile__count { color: var(--busy); }
.type-tile--none .type-tile__bar i { background: var(--busy); }

@media (max-width: 720px) {
  .type-bar { flex-direction: column; gap: 8px; }
  .type-bar__label { max-width: none; }
}

/* The running total at the head of the price section on the booking form. */
.quote-summary {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 12px 14px;
  margin-block-end: 16px;
  max-width: 420px;
}
.quote-summary__line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  font-size: 13.5px;
  color: var(--text-muted);
  padding-block: 3px;
}
/* `display: flex` above beats the browser's own `[hidden] { display: none }`,
   so without this the discount, the payment and the deposit lines would sit
   on every booking showing 0.000 — which is the trap every element in this
   system that ships hidden has to be given its own line for. */
.quote-summary__line[hidden] { display: none; }
.quote-summary__line strong { color: var(--text); font-weight: 650; }
.quote-summary__line--total {
  margin-block-start: 6px;
  padding-block-start: 8px;
  border-block-start: 1px solid var(--border-strong);
  font-size: 15px;
  color: var(--text);
  font-weight: 650;
}
.quote-summary__line--total strong { font-size: 19px; font-weight: 750; }
.quote-summary__currency { font-size: 12px; color: var(--text-muted); }
.field__error { color: var(--danger); font-size: 12px; margin-block-start: 4px; }
.form-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-block-start: 4px;
}

/* The property logo: shown at the size it prints at, on a chequerboard so a
   transparent PNG reads as transparent rather than as a white block. */
.logo-field {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px;
  margin-block-end: 16px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.logo-field__preview {
  flex: none;
  width: 130px;
  height: 74px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%),
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%);
  background-size: 14px 14px;
  background-position: 0 0, 7px 7px;
  overflow: hidden;
}
.logo-field__preview img { max-width: 118px; max-height: 62px; object-fit: contain; }
.logo-field__input { flex: 1; min-width: 0; }
.logo-field__input input[type="file"] { font-size: 13px; }

.logo-thumb {
  display: grid;
  place-items: center;
  width: 62px;
  height: 34px;
  object-fit: contain;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: #fff;
}
.logo-thumb--empty { color: var(--text-soft); font-size: 12px; background: var(--surface-2); }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 0 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 0 14px; }

.check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  padding: 7px 0;
}
.check input { width: 16px; height: 16px; margin: 1px 0 0; flex: none; }

fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; margin: 0 0 14px; }
legend { font-size: 12px; font-weight: 700; color: var(--text-muted); padding-inline: 6px; text-transform: uppercase; letter-spacing: .04em; }

/* Guest lookup results on the booking form */
.guest-hits { display: flex; flex-direction: column; gap: 5px; margin-block-end: 12px; }
.guest-hit {
  display: flex;
  flex-direction: column;
  gap: 1px;
  text-align: start;
  padding: 7px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font: inherit;
  cursor: pointer;
}
.guest-hit:hover { border-color: var(--brand); background: var(--brand-soft); }
.guest-hit__name { font-size: 13.5px; font-weight: 650; }
.guest-hit__meta { font-size: 11.5px; color: var(--text-muted); }
.guest-hit--blocked { border-color: var(--busy-br); background: var(--busy-bg); }
.guest-hit--blocked:hover { border-color: var(--busy); background: var(--busy-bg); }

/* Availability, grouped by unit type: ask for a number, or open the drawer
   and pick particular rooms. */
.type-group {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-block-end: 10px;
  background: var(--surface-2);
}
.type-group__head {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  padding: 11px 14px;
}
.type-group__name { font-size: 14.5px; font-weight: 700; }
.type-group__pick { padding: 0 14px 12px; }
.type-group__pick > summary {
  cursor: pointer;
  font-size: 12px;
  font-weight: 650;
  color: var(--text-muted);
  padding: 4px 0;
  list-style: revert;
}
.type-group__pick > summary:hover { color: var(--brand); }
.type-group:has([data-qty-input]:not([value="0"])) { border-color: var(--brand-light); }

/* One switch for one choice: the new booking's "booking for" and "term". A
   tray with the options side by side, the chosen one lifted out of it in
   white — his choice, 20 Oct 2026, over two wide raised bars. The radio
   inside is the real control; the label is what is pressed. */
.seg {
  display: inline-flex;
  gap: 4px;
  max-width: 100%;
  padding: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.seg__opt {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 18px;
  border: 1px solid transparent;
  border-radius: 9px;
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 650;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.seg__opt svg { flex: none; color: var(--text-soft); transition: color .15s ease; }
.seg__opt input { position: absolute; opacity: 0; pointer-events: none; }
.seg__opt:hover { color: var(--text); }
.seg__opt:hover svg { color: var(--text-muted); }
.seg__opt:has(input:checked) {
  background: var(--surface);
  border-color: var(--border);
  color: var(--brand-dark);
  font-weight: 800;
  box-shadow: 0 1px 3px rgba(15, 23, 42, .12), 0 1px 1px rgba(15, 23, 42, .06);
}
.seg__opt:has(input:checked) svg { color: var(--brand); }
.seg__opt:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 1px; }

/* The new booking, in the middle of the screen — his layout, 20 Oct 2026. */
.booking-form { max-width: 1240px; margin-inline: auto; width: 100%; }

/* Its stay on one twelve-column grid, so every row lines up edge to edge:
   the two switches over the two dates, the property over the nights and the
   party, ending where the children's box ends. The row below it shares the
   same width between however many boxes it has. */
.stay-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0 14px; align-items: start; }
.stay-grid > .field { min-width: 0; }
.stay-grid > .field[hidden], .stay-cols > .field[hidden] { display: none; }
.stay-c2 { grid-column: span 2; }
.stay-c3 { grid-column: span 3; }
.stay-c6 { grid-column: span 6; }
.stay-c4 { grid-column: span 4; }
.stay-org { grid-column: span 3; }
.stay-grid:has(> .stay-org:not([hidden])) > .stay-c6 { grid-column: span 3; }
.stay-grid .seg { display: flex; width: 100%; }
.stay-grid .seg__opt { flex: 1 1 0; min-width: 0; padding-inline: 10px; }
.stay-grid input[type="number"] { text-align: center; }
/* What the dates come to, drawn as the boxes beside it are drawn. */
.stay-count {
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 13.5px;
  font-weight: 800;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.stay-cols { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 0 14px; }
.stay-cols > .field { min-width: 0; }
@media (max-width: 760px) {
  .stay-c3, .stay-c4, .stay-c6, .stay-org { grid-column: 1 / -1; }
  .stay-grid:has(> .stay-org:not([hidden])) > .stay-c6 { grid-column: 1 / -1; }
  .stay-grid > .stay-c3:has(input[type="date"]) { grid-column: span 6; }
  .stay-c2 { grid-column: span 4; }
  .stay-cols { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A long let's rent, typed beside the number of units. */
.type-group__rent { margin: 0; width: 160px; }
.type-group__rent[hidden] { display: none; }

/* Selectable unit cards in the booking form */
.pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 9px; }
.pick {
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 9px 11px;
  cursor: pointer;
  background: var(--surface);
  display: block;
  position: relative;
}
.pick:hover { border-color: var(--brand); }
.pick input { position: absolute; opacity: 0; }
.pick__no { font-size: 17px; font-weight: 700; }
.pick__meta { font-size: 11px; color: var(--text-muted); }
.pick__rate { font-size: 12.5px; font-weight: 700; color: var(--brand); margin-top: 3px; font-variant-numeric: tabular-nums; }
.pick:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-soft);
  box-shadow: 0 0 0 2px var(--brand-light);
}

/* ==========================================================================
   Messages
   ========================================================================== */
/* `hidden` alone does not hide this: the browser's own rule loses to the
   `display` below. Without this line the empty notice under the discount field
   on a new booking is drawn on every one of them. */
/* The corner button on a room tile. The tile itself is a link, so this sits
   over it rather than inside it. */
.room-slot { position: relative; display: flex; }
.room-slot > .room { flex-grow: 1; }
/* Always there. It was drawn only on hover, which on a board of sixty tiles
   means nobody ever finds it — and a control nobody can see is a control that
   does not exist. It sits quietly until it is pointed at. */
.room__ask {
  position: absolute;
  inset-block-end: 5px;
  inset-inline-start: 5px;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid rgba(15, 23, 42, .1);
  border-radius: 9px;
  background: rgba(255, 255, 255, .88);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .1);
  transition: background .12s ease, color .12s ease, transform .06s ease;
  /* Above the tile even while the tile is hovered: `.room:hover` lifts itself
     to z-index 2, and without this the link covers the button the moment the
     pointer arrives — so it vanishes under the cursor and the click opens a
     booking instead. */
  z-index: 3;
}
.room__ask svg { width: 17px; height: 17px; }
.room__ask:hover,
.room__ask:focus-visible {
  background: #fff;
  color: var(--brand);
  border-color: var(--brand);
  outline: none;
}
.room__ask:active { transform: translateY(1px); }
/* The tile's own last line stops short of the button rather than running
   under it — the room number is the loudest thing on the board and nothing
   may sit on top of it. */
.room-slot--asks .room { padding-inline-start: 42px; }

.alert[hidden] { display: none; }
/* Tabler's alert: a white card with the state's colour down its starting
   edge, and the words in the ordinary text colour. */
.alert {
  padding: 12px 16px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-strong);
  border-inline-start: 4px solid var(--text-soft);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-block-end: 16px;
}
.alert--success { border-inline-start-color: var(--ok); }
.alert--error { border-inline-start-color: var(--danger); background: var(--danger-bg); }
.alert--warning { border-inline-start-color: var(--arriving); }
.alert--info { border-inline-start-color: var(--info); }

/* ==========================================================================
   Modal
   ========================================================================== */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, .45);
  display: none;
  z-index: 60;
  padding: 24px;
  overflow-y: auto;
}
.modal-backdrop.is-open { display: block; }
.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  max-width: 560px;
  margin: 40px auto;
  overflow: hidden;
}
.modal--wide { max-width: 860px; }
.modal__head {
  padding: 14px 18px;
  border-block-end: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.modal__body { padding: 18px; }
.modal__foot { padding: 13px 18px; border-block-start: 1px solid var(--border); background: var(--surface-2); display: flex; gap: 8px; justify-content: flex-end; }
.modal__close { background: none; border: none; font-size: 22px; line-height: 1; cursor: pointer; color: var(--text-muted); }

/* ==========================================================================
   Misc utilities
   ========================================================================== */
.muted { color: var(--text-muted); }
.soft { color: var(--text-soft); }
.small { font-size: 12px; }
.tiny { font-size: 11px; }
.bold { font-weight: 700; }
.num { font-variant-numeric: tabular-nums; }
.money { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
.money--due { color: var(--danger); }
/* Same red, for screens that call it a shortfall rather than a debt. */
.money--bad { color: var(--danger); }
.money--ok { color: var(--ok); }
/* Held for somebody else: neither owed nor earned, so neither red nor green. */
.money--held { color: var(--warn, #b45309); }
.center { text-align: center; }
.end { text-align: end; }
.mt-0 { margin-top: 0; } .mt-1 { margin-top: 8px; } .mt-2 { margin-top: 16px; } .mt-3 { margin-top: 24px; }
.mb-0 { margin-bottom: 0; } .mb-1 { margin-bottom: 8px; } .mb-2 { margin-bottom: 16px; }
.hidden { display: none !important; }
.nowrap { white-space: nowrap; }

.tabs { display: flex; gap: 4px; border-block-end: 1px solid var(--border); margin-block-end: 16px; flex-wrap: wrap; }
.tab {
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 650;
  color: var(--text-muted);
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
}
.tab:hover { color: var(--text); text-decoration: none; }
.tab.is-active { color: var(--brand); border-block-end-color: var(--brand); }

/*
  A card that folds. The summary is the card's own head, so a closed one looks
  like a heading somebody can press rather than like a card that failed to
  load, and the marker sits on the far side where a disclosure arrow belongs
  in either direction.
*/
.card--folded > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.card--folded > summary::-webkit-details-marker { display: none; }
.card--folded > summary::after {
  content: "";
  width: 7px;
  height: 7px;
  margin-inline-start: auto;
  border-inline-end: 2px solid var(--text-muted);
  border-block-end: 2px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform .15s ease;
}
.card--folded[open] > summary::after { transform: rotate(-135deg); }
.card--folded > summary:hover { background: var(--surface-2); }

/* Printed pages are read later and have no one to press anything: a folded
   section prints open or it prints as a heading with nothing under it. */
@media print {
  .card--folded:not([open]) > *:not(summary) { display: revert; }
  .card--folded > summary::after { display: none; }
}

/* --------------------------------------------------------------------------
   Steps

   A long form shown one section at a time. The numbers are the point: these
   sections are a sequence, not a set of drawers — you cannot pick a room
   before you have said which nights, and you cannot price the stay before
   either. Tabs would say they are interchangeable, and they are not.

   Every rule here applies only once the script has marked the form, so a
   browser that never ran it shows the five sections stacked, which is what
   this page was before steps existed.
   -------------------------------------------------------------------------- */
.steps {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  border-block-end: 1px solid var(--border);
  margin-block-end: 16px;
}
/* A step the booking does not need — Extras on a long let — is skipped and
   its tab hidden. The display below beats the browser's own
   [hidden] { display: none }, as it has elsewhere in this file, so the tab
   has to be told twice. */
.step[hidden] { display: none; }

.step {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  font-size: 13px;
  font-weight: 650;
  color: var(--text-muted);
  background: none;
  border: 0;
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  font-family: inherit;
  cursor: pointer;
}
.step:hover { color: var(--text); }
.step__n {
  width: 21px;
  height: 21px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 800;
  background: var(--border);
  color: var(--text-muted);
  /* A step number is a number in any language, and an Arabic page would
     otherwise mirror "1 Stay" into "Stay 1" inside the pill. */
  direction: ltr;
  unicode-bidi: isolate;
}
.step.is-done .step__n { background: var(--ok); color: #fff; }
.step.is-active { color: var(--brand); border-block-end-color: var(--brand); }
.step.is-active .step__n { background: var(--brand); color: #fff; }
/* The one that still needs something. Marked rather than announced, so the
   clerk can see where the complaint at the top of the page belongs. */
.step.is-wrong { color: var(--danger); }
.step.is-wrong .step__n { background: var(--danger); color: #fff; }

/* `hidden` alone loses to any author rule that sets a display, and this one
   is a section with a card in it. Every element in this system that ships
   hidden needs its own line like this. */
.step-panel[hidden] { display: none; }

.steps__nav { gap: 8px; flex-wrap: wrap; }
.steps__nav .grow { flex: 1 1 auto; }

.filters {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  padding: 14px 20px 16px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  margin-block-end: 16px;
}
.filters .field { margin: 0; min-width: 140px; }
.filters .field > label { font-size: 12.5px; color: var(--text-muted); margin-block-end: 5px; }
/*
  One height across the bar. A date field carries a calendar button inside it
  and stands three pixels taller than a select beside it; the boxes are
  aligned along their bottom edge, so that difference shows as a row whose
  tops do not line up. Everything is brought up to the tallest rather than
  cut down to the shortest, so no control on any filter bar ends up smaller
  than it is today.
*/
.filters input, .filters select, .filters .btn { min-height: 38px; }
.filters .field:has(input[type="search"]) { min-width: 260px; }

/* Login */
/*
  The sign-in screen stands on a photograph of hotel and residential towers,
  which between them is what this system is for. Marina Dubai Skyline, by Timo
  Volz, under the Unsplash License — free for commercial use. The credit and
  the licence are written down in static/img/CREDITS.md.

  WebP at 1600px: 211 KB, which is the price of a real photograph instead of a
  drawing, paid once on the only screen that loads with nothing cached.

  The colour underneath is the picture's own sky, so the screen is already the
  right colour in the moment before the photograph arrives.
*/
:root { --login-wash: rgba(255, 255, 255, 0.62); }

.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 20px;
  background-color: #dceaf2;
  /* A wash of white over the picture, so it reads as a watermark behind the
     work rather than as a photograph somebody has to look past. One value
     controls it — raise it to fade the city further, lower it to bring it
     back — and it is the same value on the phone. */
  background-image:
    linear-gradient(var(--login-wash), var(--login-wash)),
    url("../img/login-city.6adc12a3e57f.webp");
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: cover;
}
/* A brand band across the top, the form on white underneath — the same card
   the HR system signs in with, in this app's own colours. */
.login-card {
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  /* Deeper than the shared shadow: on the old dark ground the card was the
     only light thing and needed no help standing off it. On a pale sky it
     does. */
  box-shadow: 0 16px 40px rgba(24, 36, 51, 0.12), 0 2px 6px rgba(24, 36, 51, 0.05);
  overflow: hidden;
  /* Above the towers whatever the screen height. */
  position: relative;
  z-index: 1;
}
/*
  The band keeps its own direction. "Liwan" is a brand and sits beside its
  mark the way it is drawn, so in Arabic the logo would otherwise swap to the
  right and the language buttons to the left, which is the same change the
  top bar of the system itself was asked for and given.

  Only the band. Everything below it — the labels, the fields, the button —
  mirrors as Arabic should.
*/
.login-card__head {
  direction: ltr;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 22px;
  background: var(--surface);
  border-block-end: 1px solid var(--border);
}
.login-card__brand { display: flex; align-items: center; gap: 11px; }

/*
  Held, not toggled. A password left showing is a password somebody walks away
  from — so it shows while the eye is under the finger or the pointer, and is
  covered again the moment either leaves.
*/
.peek { position: relative; display: block; }
.peek > input { padding-inline-end: 44px; }
.peek__eye {
  position: absolute;
  inset-inline-end: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
}
.peek__eye:hover, .peek__eye:focus-visible { color: var(--brand); background: var(--surface-2); }
.peek__eye svg { width: 20px; height: 20px; display: block; }
.peek__eye .peek__off { display: none; }
.peek.is-showing .peek__eye .peek__on { display: none; }
.peek.is-showing .peek__eye .peek__off { display: block; }
.login-card__mark { width: 42px; height: 42px; border-radius: 10px; display: block; }
.login-card__text { display: flex; flex-direction: column; line-height: 1.2; }
.login-card__name { color: var(--text); font-size: 20px; font-weight: 650; letter-spacing: .2px; }
.login-card__sub {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
  direction: ltr;
  unicode-bidi: isolate;
}
.login-card__body { padding: 26px 24px 28px; }
.login-card__body .field { margin-block-end: 16px; }
/* 16px, because anything smaller makes iOS zoom the page the moment the
   keyboard opens and the card is then half off the screen. */
.login-card__body input { padding: 13px 14px; font-size: 16px; min-height: 50px; }
.login-card__already {
  margin: 0 0 16px;
  text-align: center;
  font-size: 15px;
  font-weight: 600;
}
.login-card__quit {
  display: block;
  width: 100%;
  min-height: 48px;
  border: 0;
  border-block-start: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.login-card__quit:active { background: var(--border); }
/* `hidden` alone does not hide an element a class has given a `display` to:
   the browser's own rule loses to any rule in a stylesheet. Every element in
   this system that ships hidden needs its own line like this one. */
.login-card__quit[hidden] { display: none; }

/*
  On a phone the card is a sheet at the foot of the screen and the sky is
  above it.

  It used to be the whole screen — full width, full height, no shadow — which
  was right while the ground behind it was a flat colour: nothing was being
  covered. A drawing is being covered now, and on a phone the phone is where
  almost every sign-in happens, so a background nobody on a phone ever sees is
  a background that does not exist.

  Anchored to the bottom rather than centred for the ordinary reason: that is
  where the thumb is. The sky is a flex item rather than the page's own
  background, so the towers stand on the top edge of the sheet instead of
  being hidden behind it — and it gives way first when the keyboard opens.
*/
@media (max-width: 480px) {
  .login-page {
    padding: 0;
    /* The screen exactly, not at least the screen: only a container with a
       height of its own can make the sky give way to the form. `safe` is the
       insurance — when the card alone is taller than the screen the whole
       thing falls back to starting at the top, and scrolls, rather than
       overflowing upwards where nobody can reach it. */
    height: 100dvh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    justify-content: safe flex-end;
    /* The wide rule centres its one child. Left in place here it would centre
       the sky as well — and an empty box centred on its cross axis is 0px
       wide, so the drawing was being painted into nothing. */
    align-items: stretch;
    /* Moved to ::before, which is the only part of the page it should cover. */
    background-image: none;
  }
  .login-page::before {
    content: "";
    /* Takes whatever room is left over, and gives it all back when there is
       none: on a short screen — a small phone with the keyboard open — a sky
       that insisted on its height would push the sign-in button below the
       fold, which is the one thing on this screen that must never happen. */
    flex: 1 1 auto;
    height: 132px;
    min-height: 0;
    background-image:
      linear-gradient(var(--login-wash), var(--login-wash)),
      url("../img/login-city.6adc12a3e57f.webp");
    background-repeat: no-repeat;
    background-position: center bottom;
    background-size: cover;
  }
  /* Both of these ship hidden, and `hidden` alone loses to any author rule
     that sets a display — as a flex item a stray one would be a gap the width
     of the screen between the towers and the card. */
  .login-page > form[hidden] { display: none; }
  .login-card {
    max-width: none;
    /* Never squashed: whatever has to give on a short screen, it is the sky. */
    flex: 0 0 auto;
    border: 0;
    border-radius: 20px 20px 0 0;
    /* Upwards, since the sheet's only visible edge is its top one. */
    box-shadow: 0 -10px 30px rgba(11, 46, 43, 0.16);
    display: flex;
    flex-direction: column;
  }
  .login-card__head { padding: 20px 20px; }
  .login-card__body { padding: 24px 20px 26px; }
  /* The sheet ends at the foot of the screen now, so whichever of these two is
     the last thing in it has to clear the phone's home indicator. Inside the
     app that is the way-out button; in a browser it is the form itself. */
  .login-card__quit { padding-block-end: calc(env(safe-area-inset-bottom, 0px) + 14px); }
  .login-card:has(.login-card__quit[hidden]) .login-card__body {
    padding-block-end: calc(env(safe-area-inset-bottom, 0px) + 26px);
  }
}

/* --------------------------------------------------------------------------
   Language toggle — a segmented EN / AR control rather than a single button
   showing the language you are not on, which left people guessing whether it
   named the current language or the one it would switch to. Both are always
   visible and the one you are on is raised.
   -------------------------------------------------------------------------- */
.lang-toggle {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.lang-toggle__btn {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .5px;
  padding: 4px 11px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.lang-toggle__btn:hover { color: var(--text); }
.lang-toggle__btn.is-on,
.lang-toggle__btn.is-on:hover {
  background: var(--surface);
  color: var(--brand-dark);
  box-shadow: 0 1px 2px rgba(24, 36, 51, .12);
}

/* ==========================================================================
   Print — registration card and invoice
   ========================================================================== */
.print-doc { display: none; }

@media print {
  /* The address, on every sheet. */
  .doc__foot {
    position: fixed;
    inset-block-end: 0;
    inset-inline: 0;
    border-block-start: 1px solid #cbd5e1;
    background: #fff;
    padding-block: 6px;
  }
  /* Room for it, so the last rows of a table do not print underneath. */
  .doc { padding-block-end: 46px; }

  /* Paper has no scrolling. Anything the screen keeps inside a scroll box —
     the shell pinned to the window height, a wide table in its own horizontal
     scroller — is clipped to that box when the browser paginates, which is why
     a preview came out blank or with the right-hand columns missing. All of it
     is unpinned here and left to flow down the page. */
  html, body { height: auto; overflow: visible; }
  .app { display: block; min-height: 0; overflow: visible; }
  .content, .content--wide { padding: 0; }
  .card__body--flush, .timeline-wrap, .table-wrap {
    overflow: visible !important;
    max-height: none !important;
  }
  /* On paper nothing scrolls, so nothing needs pinning — and a pinned
     heading would print on top of the rows. */
  .table thead th, .timeline thead th, .timeline th.tl-unit, .timeline td.tl-unit {
    position: static !important;
  }

  body { background: #fff; font-size: 12px; }
  .appbar, .topbar, .no-print, .btn, .filters, .tabs { display: none !important; }
  .card { border: none; box-shadow: none; }
  .card + .card, .split > * + * { margin-block-start: 10px; }
  /* Side-by-side columns are narrower than A4 is wide — stack them instead. */
  .split, .split--even { display: block; }
  .kpis { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }

  /* Keep a table together as far as the page allows, and repeat its header on
     every page it runs onto — otherwise page two is a wall of numbers with no
     column names. */
  .table { font-size: 10.5px; }
  .table th, .table td { padding: 5px 7px; }
  .table th { font-size: 11.5px; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .table thead { display: table-header-group; }
  .table tr, .kpi, .alert { break-inside: avoid; }

  /* The colour IS the information on this system — a red overdue figure, an
     amber warning banner. Chrome drops backgrounds when printing unless asked. */
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  .print-doc { display: block; }
  .page-break { page-break-after: always; }
  @page { size: A4; margin: 12mm; }
}

.doc {
  max-width: 190mm;
  margin: 0 auto;
  background: #fff;
  padding: 22px 26px;
  color: #0f172a;
}
.doc__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 20px;
  border-block-end: 2px solid var(--brand);
  padding-block-end: 12px;
  margin-block-end: 16px;
}
.doc__brand { display: flex; align-items: center; gap: 14px; }
.doc__logo { max-width: 116px; max-height: 58px; object-fit: contain; }
.doc__title { font-size: 19px; font-weight: 750; }
.doc__sub { font-size: 12px; color: var(--text-muted); }
.doc__ref { text-align: end; font-size: 12px; }
.doc__ref strong { display: block; font-size: 15px; }
/* Where the address lives now. Under the document on screen; on paper it is
   fixed to the foot of the sheet, which is what makes it repeat on every
   page — a second page of an invoice with no address on it is a loose sheet
   of numbers. */
.doc__foot {
  margin-block-start: 18px;
  padding-block-start: 10px;
  border-block-start: 1px solid var(--border);
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
}
/* A telephone number is read left to right in any language. */
.doc__foot-tel { direction: ltr; unicode-bidi: isolate; }

/* A guest document is laid out for A4 and must not spill off it. The screen
   lets a wide table scroll sideways, which is right everywhere else in this
   system and wrong here: there is no sideways on paper, and the preview is
   meant to show what will print. So inside a document a table is held to the
   width of the page and its cells wrap instead. */
.doc .table-wrap { overflow: visible; }
.doc table { width: 100%; max-width: 100%; table-layout: fixed; }
.doc table th, .doc table td {
  white-space: normal;
  overflow-wrap: anywhere;
}
.doc h3 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-muted);
  margin-block: 16px 7px;
  border-block-end: 1px solid var(--border);
  padding-block-end: 4px;
}
.doc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px 18px; }
.doc-field { font-size: 12.5px; }
.doc-field > span:first-child {
  display: block;
  font-size: 10.5px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.doc-policy { font-size: 11px; line-height: 1.65; white-space: pre-wrap; }
.doc-warning {
  border: 1.5px solid var(--danger);
  background: var(--danger-bg);
  border-radius: 6px;
  padding: 9px 12px;
  font-size: 11.5px;
  font-weight: 600;
  color: #7f1d1d;
  margin-block: 10px;
}
.doc-sign {
  display: flex;
  justify-content: space-between;
  gap: 30px;
  margin-top: 28px;
  font-size: 12px;
}
.doc-sign div { flex: 1; }
.doc-sign .line { border-block-end: 1px solid var(--text); height: 42px; margin-block-end: 5px; }

/* ==========================================================================
   Narrow screens — the board and the folio must stay usable on a tablet at
   the desk and on a phone in a sales agent's hand.
   ========================================================================== */
@media (max-width: 900px) {
  /* The nav row wraps onto as many lines as it needs rather than turning into
     a drawer — every entry stays one tap away. */
  .appbar__top { flex-wrap: wrap; gap: 8px; }
  .appbar__who { display: none; }
  .topnav__list { padding-inline: 8px; }
  .topnav__link { padding: 9px 10px; font-size: 13px; }
  .board { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
  .content { padding: 14px; }
}

@media (max-width: 620px) {
  /* Below this the dropdown panels are wider than the screen, so they drop
     into the flow underneath their trigger instead of floating. */
  .topnav__item.is-open { flex-wrap: wrap; }
  .topnav__item.is-open > .topnav__menu {
    position: static;
    width: 100%;
    margin-block: 4px;
    box-shadow: var(--shadow);
  }
}


/* The counters live here rather than in the admin theme: the register under
   Accounting and the admin's own payments list share the same partial, so
   they have to share the same rules. */
/* ==========================================================================
   Counters over the payments list
   A list of a hundred rows does not answer "how much came in on KNET this
   month". These do, from the same rows — and each one is a link that narrows
   the list to itself.
   ========================================================================== */
.pay-summary { margin-block-end: 14px; }
.pay-summary__top {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: stretch;
  margin-block-end: 10px;
}
.pay-card {
  flex: 1 1 170px;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 18px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  text-decoration: none !important;
  color: inherit !important;
  transition: border-color .12s ease, box-shadow .12s ease;
}
/* The state as a line along the top, as on every other figure card. */
.pay-card::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  background: transparent;
}
a.pay-card:hover { border-color: #c5ccd6; box-shadow: var(--shadow); }
.pay-card--in::before { background: var(--brand); }
.pay-card--out::before { background: var(--busy); }
.pay-card--net::before { background: var(--info); }
.pay-card--held::before { background: var(--arriving); }
.pay-card__label { font-size: 12.5px; font-weight: 500; color: var(--text-muted); }
.pay-card__value { font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pay-card__sub { font-size: 12px; color: var(--text-muted); }

.pay-summary__tools { display: flex; align-items: center; gap: 8px; }

/* One counter per way the money moved, "all of them" in front: flat white
   tiles that take you to their own rows, the one being looked at outlined in
   teal on a teal wash. */
.pay-summary__methods {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: stretch;
}
.pay-chip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  text-align: start;
  gap: 1px;
  min-width: 132px;
  padding: 10px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  text-decoration: none !important;
  color: inherit !important;
  transition: border-color .12s ease, background .12s ease;
}
.pay-chip:hover { border-color: #c5ccd6; background: var(--surface-2); }
.pay-chip.is-on {
  border-color: var(--brand);
  background: var(--brand-soft);
  box-shadow: 0 0 0 1px var(--brand) inset;
}
.pay-chip.is-on .pay-chip__label { color: var(--brand-dark); }
.pay-chip--all { min-width: 150px; }
.pay-chip__label { font-size: 12px; font-weight: 500; color: var(--text-muted); }
.pay-chip__value {
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pay-chip__sub { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
.pay-summary__empty { color: var(--text-soft, #94a3b8); font-size: 13px; }

/* A form that is a single column of fields — a password, a short set of
   details — kept to a readable width instead of stretching across the page. */
.form-narrow { max-width: 460px; }

/* Pictures attached to a booking — the OTA email a seller photographed. Small
   enough to sit in the summary card, and each one opens full size. */
.shots { display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: 6px; }
.shots__one {
  display: block;
  width: 92px;
  height: 92px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden;
  background: var(--surface-2);
}
.shots__one img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shots__one:hover { border-color: var(--brand); }

/* Putting finished stays out of the way on the timeline. It says so while it
   is on, because a chart that has quietly gone emptier reads as a hotel that
   was quietly emptier. */
.tl-hide {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
}
/* "Bookable, but not ready to hand over" on a room in the booking picker. */
.pick__notready {
  margin-block-start: 3px;
  font-size: 10.5px;
  font-weight: 650;
  color: var(--warn);
}

/* The deposit, under the sum rather than in it: it is the guest's money
   being held, not the property's money being earned. */
.quote-summary__line--aside {
  margin-block-start: 6px;
  padding-block-start: 6px;
  border-block-start: 1px dashed var(--border);
  color: var(--text-muted);
  font-size: 12.5px;
}

.tl-hide input { margin: 0; cursor: pointer; }
/* How many stays it would put away. A filter that says what it will do is a
   filter somebody can decide about without trying it. */
.tl-hide__count {
  min-width: 18px;
  padding-inline: 5px;
  border-radius: 999px;
  background: var(--border);
  color: var(--text);
  font-size: 11px;
  font-weight: 750;
  text-align: center;
  /* A count is a number in any language. */
  direction: ltr;
  unicode-bidi: isolate;
}
.tl-hide.is-on .tl-hide__count { background: rgba(255, 255, 255, .25); color: inherit; }
.tl-hide.is-on {
  background: var(--brand-light);
  border-color: var(--brand);
  color: var(--brand-dark);
}

/* ---------------------------------------------------------------------------
   Settings > Employee app — the sheet that is printed and handed over.

   A square and, beside it, the same address as something to copy. Side by side
   on a desk, stacked on a narrow screen: whoever sets a phone up often has
   this page open on the phone next to it.
--------------------------------------------------------------------------- */
.setup-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  align-items: flex-start;
}

.setup-code {
  flex: 0 0 auto;
  text-align: center;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-card, 14px);
  background: var(--surface);
}
.setup-code svg { display: block; }

.setup-manual { flex: 1 1 22rem; min-width: 0; }

.setup-manual h3 {
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 10px;
}
.setup-manual h3 + * { margin-top: 0; }
.setup-manual > h3:not(:first-child) { margin-top: 26px; }

.setup-code-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.setup-code-row code {
  display: inline-block;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-control, 8px);
  background: var(--surface-2);
  /* Copied off the screen or off paper by hand, so l/1 and O/0 have to be
     distinguishable. */
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 1.05rem;
  font-weight: 600;
  /* A code reads left to right on an Arabic page as much as on an English
     one — mirrored it is wrong rather than merely odd. */
  direction: ltr;
  min-width: 0;
  overflow-wrap: anywhere;
  /* Grouped in fours, so a little extra tracking makes the groups read as
     groups when somebody is typing it off a printed sheet. */
  letter-spacing: 0.04em;
  user-select: all;
}

.setup-caption { color: var(--text-muted); font-size: 0.86rem; margin: 10px 0 0; }
.setup-steps {
  margin: 0;
  padding-inline-start: 1.2rem;
  line-height: 2;
  color: var(--text);
}
.setup-warning { margin-top: 26px; }

/* The sheet in two parts once the app can be downloaded from it: getting the
   app, then pointing it here. Numbered, because the second needs the first. */
.setup-part + .setup-part {
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.setup-part__title {
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 16px;
}

@media print {
  /* The sheet, and nothing else that happens to be on the page. */
  .appbar, .topbar, .no-print { display: none !important; }
  body, .setup-sheet { background: #fff !important; color: #000 !important; }
  .setup-sheet { border: 0 !important; box-shadow: none !important; }
}

/* ---------------------------------------------------------------------------
   "Something has changed" — the one thing a stale screen says for itself.

   Shown only when the page is out of date AND somebody has been typing long
   enough that reloading under their hands would lose work. Every other time
   the page simply refreshes and this is never seen.
--------------------------------------------------------------------------- */
.stalebar {
  position: fixed;
  inset-block-end: 18px;
  inset-inline-start: 50%;
  transform: translateX(-50%);
  z-index: 60;
  padding: 10px 18px;
  border: 0;
  border-radius: 999px;
  background: var(--brand-dark, #0f766e);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(15, 23, 42, 0.22);
}
.stalebar:hover { background: var(--brand, #0d9488); }
/* The page direction flips, but a pill centred on the screen should not
   drift: translateX is applied after the inset, and in RTL the start edge is
   the right one. */
html[dir="rtl"] .stalebar { transform: translateX(50%); }

/* The privacy policy's link under the sign-in card. Quiet: it is there
   because a store requires it to be reachable and because somebody may want
   it, not because it is part of signing in. */
.login-card__legal {
  margin: 14px 0 0;
  text-align: center;
  font-size: 0.8rem;
}
.login-card__legal a { color: var(--text-2); text-decoration: none; background: rgba(255, 255, 255, .75); padding: 3px 10px; border-radius: 999px; }
.login-card__legal a:hover { color: var(--brand-dark); text-decoration: none; }

/* The monthly target boxes. Narrow and right-aligned: they hold money, and a
   column of money that does not line up is a column nobody can scan. */
.target-box {
  width: 120px;
  text-align: end;
  font-variant-numeric: tabular-nums;
}

/* A whole year of them: twelve boxes a seller, narrower, and the month in
   progress marked so it is found at a glance. */
.targets-year th, .targets-year td { padding-inline: 6px; }
.targets-year__pick { gap: 8px; align-items: center; }
.targets-year__pick select { min-width: 7.5rem; }
.targets-year .target-box { width: 100%; min-width: 96px; }
/* The cells of the month in progress are lit; its heading keeps the dark
   bar the rest of the row has — lit, its white name was white on white —
   and is marked by a line under it instead. */
.targets-year td.is-now { background: var(--brand-soft); }
.targets-year th.is-now { box-shadow: inset 0 -4px 0 #5eead4; }

/* Money that is owed but not payable yet — rent renewing, a sale settling
   late, a balance waiting on a target. Not red: nothing is wrong with it. */
.money--soft { color: #b45309; }

/* ==========================================================================
   The user guide
   ========================================================================== */
/* Running text, not a dashboard: a measure that stops at about eighty
   characters, because a paragraph the full width of a desktop screen is one
   the eye loses its place in halfway along. */
.manual-text p, .manual-steps { max-width: 68ch; }
.manual-text p { line-height: 1.7; }
.manual-steps { margin: 10px 0 0; padding-inline-start: 22px; }
.manual-steps li { margin-bottom: 6px; line-height: 1.6; }
.manual-note {
  margin-top: 12px;
  padding: 10px 12px;
  border-inline-start: 3px solid var(--primary);
  background: var(--surface-2, rgba(20, 184, 166, .06));
  border-radius: var(--radius-sm, 6px);
  font-size: .92rem;
}
.manual-screens {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

/* ==========================================================================
   A count that opens
   ========================================================================== */
/* Eight bookings listed inline under one seller is a wall of text in a column
   somebody is reading across. The count is what belongs in the table; the
   list behind it is what they open when they want to check a figure. */
.disclose > summary {
  cursor: pointer;
  color: var(--primary);
  font-weight: 600;
  white-space: nowrap;
  list-style: none;
}
.disclose > summary::-webkit-details-marker { display: none; }
/* The marker is drawn rather than inherited, so it points the right way
   when the page is mirrored. */
.disclose > summary::after {
  content: "A";
  display: inline-block;
  margin-inline-start: 5px;
  transform: rotate(90deg);
  transition: transform .15s;
}
[dir="rtl"] .disclose > summary::after { content: "9"; }
.disclose[open] > summary::after { transform: rotate(-90deg); }
.disclose__body { margin-top: 6px; display: grid; gap: 3px; }

/* ==========================================================================
   Choosing which units a check-in or check-out is for
   ========================================================================== */
/* A block arrives on two coaches. Shown only when there is more than one
   unit to choose between, and every box starts ticked — so pressing
   straight through is the whole booking, as it always was. */
.unit-picks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 6px 0 4px;
}
.unit-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  background: var(--surface);
  cursor: pointer;
}
.unit-pick:has(input:checked) {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.unit-pick input { width: auto; margin: 0; }
/* A unit somebody has already been in. Shown rather than left out: "301 is
   not in this list" is a question, and "301, already occupied" is an
   answer. */
.unit-pick--off { opacity: .55; cursor: not-allowed; }

/* ==========================================================================
   What is wrong with the room
   ========================================================================== */
/* Pressed, not written. The people who find the faults are the people who
   clean the rooms, and several of them cannot write a sentence — so these
   are large enough to hit with a thumb on a phone, and the drawing carries
   the meaning rather than the word under it. */
.faults {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  gap: 8px;
  margin: 8px 0 4px;
}
.fault {
  /* So the box below, taken out of the layout, is still positioned against
     this tile — otherwise the page becomes its frame and a keyboard focus
     scrolls somewhere nobody is looking. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 86px;
  padding: 10px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 10px);
  background: var(--surface);
  color: var(--body-fg);
  cursor: pointer;
  text-align: center;
  transition: border-color .12s, box-shadow .12s, background .12s;
}
/* The box itself is off screen but still reachable by keyboard and still
   what the form posts: the tile is its label. */
.fault input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.fault__icon { color: var(--muted-fg, #64748b); flex: none; }
.fault__label { font-size: .82rem; line-height: 1.25; }
.fault:has(input:checked) {
  border-color: var(--primary);
  background: var(--primary-soft, rgba(20, 184, 166, .10));
  box-shadow: inset 0 0 0 1px var(--primary);
}
.fault:has(input:checked) .fault__icon { color: var(--primary); }
.fault:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
/* On a task already reported: the same drawings, read-only and small. */
.fault-tags { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.fault-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: .78rem;
}


/* ==========================================================================
   Whose bill a line is on
   ========================================================================== */
/* Only ever drawn on a booking that has two bills. The tag is the button
   that moves the line, because the answer and the way to change it are the
   same thing: the desk reads the column to find the line that is on the
   wrong side, and the thing it reads is the thing it presses. */
.sidetag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 14ch;
  padding: 2px 9px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted-fg, #64748b);
  font: inherit;
  font-size: .76rem;
  line-height: 1.5;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: border-color .12s, color .12s, background .12s;
}
.sidetag:hover { border-color: var(--primary); color: var(--primary); }
.sidetag--company {
  border-color: var(--primary);
  background: var(--primary-soft, rgba(20, 184, 166, .10));
  color: var(--primary);
}
/* The same tag for somebody who may not move it: it still has to read the
   same, and a button that refuses when pressed is worse than no button. */
.sidetag--flat { cursor: default; }
.sidetag--flat:hover { border-color: var(--border); color: var(--muted-fg, #64748b); }
.sidetag--flat.sidetag--company:hover { border-color: var(--primary); color: var(--primary); }

.billsplit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 12px;
}
.billside {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 10px);
  background: var(--surface);
}
.billside--company {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.billside__money {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: .82rem;
  color: var(--muted-fg, #64748b);
}
.billside__money b { color: var(--body-fg); }


/* A room the system is holding for a guest, not one the desk has chosen. Quiet
   on purpose: it is not a warning, only a reminder that the desk may still
   give this guest a different room of the same type. */
.room__held {
  display: inline-block;
  margin-top: 2px;
  padding: 0 6px;
  border: 1px dashed currentColor;
  border-radius: 999px;
  opacity: .7;
  line-height: 1.5;
}


/* ==========================================================================
   A booking's attached papers
   ========================================================================== */
/* A picture small enough to recognise at a glance — which booking site, which
   card — and opened full size by pressing it. A PDF is a tile that says so,
   because a browser cannot draw a thumbnail of one without a library. */
.papers { display: flex; flex-direction: column; gap: 10px; }
.paper {
  display: flex;
  align-items: center;
  gap: 10px;
}
.paper__look {
  flex: none;
  width: 64px;
  height: 64px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
}
.paper__look img { width: 100%; height: 100%; object-fit: cover; }
.paper__pdf {
  font-weight: 800;
  font-size: .78rem;
  color: var(--busy, #b91c1c);
  letter-spacing: .04em;
}
.paper__meta { flex: 1; min-width: 0; }


/* ==========================================================================
   What the inspector found, on the check-out screen
   ========================================================================== */
/* One block per unit leaving. Green when it was looked at and nothing was
   wrong; red-edged while something is waiting for the desk's answer, because
   that unit cannot be checked out until it has one. */
.departures { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.departure {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  padding: 8px 10px;
  background: var(--surface);
}
.departure--clear { border-color: var(--ok, #16a34a); }
.departure--open {
  border-color: var(--busy, #b91c1c);
  box-shadow: inset 3px 0 0 var(--busy, #b91c1c);
}
html[dir="rtl"] .departure--open { box-shadow: inset -3px 0 0 var(--busy, #b91c1c); }
.finding {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
.finding__what { min-width: 12rem; }

/* ---------------------------------------------------------------------------
   A colour field: the colour well, which opens every colour, and a row of
   ready ones. See config/widgets.py.
--------------------------------------------------------------------------- */
.colour-pick { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.colour-pick__well {
  inline-size: 3.25rem;
  block-size: 2.5rem;
  padding: 3px;
  border: 1px solid var(--border-strong, #cbd5e1);
  border-radius: 10px;
  background: var(--surface, #fff);
  cursor: pointer;
}
.colour-pick__well::-webkit-color-swatch-wrapper { padding: 0; }
.colour-pick__well::-webkit-color-swatch { border: 0; border-radius: 7px; }
.colour-pick__well::-moz-color-swatch { border: 0; border-radius: 7px; }
.colour-pick__hint { font-size: 0.82rem; color: var(--text-muted, #64748b); }
.colour-pick__swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex-basis: 100%;
}
.colour-pick__swatch {
  inline-size: 1.75rem;
  block-size: 1.75rem;
  border-radius: 50%;
  border: 2px solid var(--surface, #fff);
  background: var(--swatch);
  box-shadow: 0 0 0 1px rgba(15, 23, 42, .18);
  cursor: pointer;
  padding: 0;
  transition: transform .12s ease, box-shadow .12s ease;
}
.colour-pick__swatch:hover { transform: scale(1.12); }
.colour-pick__swatch.is-on { box-shadow: 0 0 0 2px var(--surface, #fff), 0 0 0 4px var(--swatch); }
.colour-pick__swatch:focus-visible { outline: 2px solid var(--primary, #0f766e); outline-offset: 2px; }

/* ==========================================================================
   Rates calendar and bulk update — templates/properties/rate_calendar.html,
   rate_bulk.html. Kood's request, 20 Oct 2026, after Expedia's rates screens:
   every plan's price by day under its kind of unit, typed into in place.
   ========================================================================== */
.rc-nav, .rc-span { display: inline-flex; gap: 4px; align-items: center; }
.rc-span .btn.is-on { background: var(--brand); border-color: var(--brand); color: #fff; }
.rc-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; margin: -4px 2px 12px; }
.rc-key {
  display: inline-block;
  width: 14px; height: 14px;
  margin-inline-end: 6px;
  vertical-align: -2px;
  border-radius: 4px;
  border: 1px solid var(--table-grid);
  background: var(--surface);
  position: relative;
}
.rc-key.is-own { background: var(--info-bg); border-color: var(--cleaning-br); }
.rc-key.is-weekend { background: var(--surface-2); }
.rc-key.has-offer::after,
.rc-cell.has-offer::after {
  content: "";
  position: absolute;
  inset-block-start: 3px;
  inset-inline-end: 3px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ok);
}

.rc-table { font-size: 12.5px; }
.rc-table th.rc-day { padding: 6px 4px; min-width: 54px; line-height: 1.25; }
.rc-day__name { display: block; font-size: 11px; font-weight: 600; opacity: .8; }
.rc-day__number { display: block; font-size: 15px; }
.rc-table th.rc-day.is-weekend { background: #0d3b38; }
.rc-table th.rc-day.is-today { box-shadow: inset 0 -4px 0 var(--brand-light), 0 1px 0 var(--table-head); }

/* The names stay where they are while the days scroll past them. */
.rc-table .rc-name {
  position: sticky;
  inset-inline-start: 0;
  z-index: 2;
  min-width: 230px;
  max-width: 300px;
  text-align: start;
  background: var(--surface);
}
.rc-table th.rc-name { z-index: 5; background: var(--table-head); text-align: start; }
.rc-type td { background: var(--brand-soft); text-align: start; padding-block: 8px; }
.rc-type__in { position: sticky; inset-inline-start: 12px; display: inline-block; }
.rc-type__name { font-size: 14px; font-weight: 800; color: var(--brand-dark); }
.rc-free td { color: var(--text-muted); font-size: 12px; padding-block: 5px; }
.rc-free td.is-full { color: var(--busy); font-weight: 800; }
.rc-plan__name { font-weight: 700; color: var(--text); }
a.rc-plan__name:hover { color: var(--brand); }
.rc-plan__open { margin-inline-start: 6px; color: var(--text-soft); vertical-align: -1px; }
.rc-plan__open:hover { color: var(--brand); }

.rc-table td.is-weekend { background: var(--surface-2); }
.rc-cell {
  position: relative;
  cursor: pointer;
  user-select: none;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  padding: 9px 4px;
  transition: background-color .25s;
}
.rc-cell:hover { box-shadow: inset 0 0 0 2px var(--brand); }
.rc-cell:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--brand); }
.rc-cell.is-past { color: var(--text-muted); }
.rc-table td.rc-cell.is-own { background: var(--info-bg); color: #1d4ed8; font-weight: 800; }
.rc-table td.rc-cell.is-picked { background: var(--brand-light); box-shadow: inset 0 0 0 1px var(--brand); }
.rc-table td.rc-cell.is-saved { background: var(--free-bg); }
.rc-cell.is-saving { opacity: .55; }
.rc-cell.is-error { box-shadow: inset 0 0 0 2px var(--danger); }
.rc-cell.is-editing { padding: 0; }
.rc-input {
  width: 100%;
  min-width: 64px;
  height: 100%;
  min-height: 36px;
  border: 2px solid var(--brand);
  border-radius: 0;
  text-align: center;
  font: inherit;
  font-weight: 700;
  background: var(--surface);
}
.rc-off { color: var(--text-soft); }
.rc-table td.rc-monthly { text-align: start; padding-inline-start: 16px; }

.rc-bar {
  position: fixed;
  inset-block-end: 18px;
  inset-inline-end: 18px;
  z-index: 150;
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 28px rgba(15, 23, 42, .18);
  font-weight: 700;
  font-size: 13px;
}
.rc-bar[hidden] { display: none; }
.rc-status {
  position: fixed;
  inset-block-start: calc(var(--appbar-h, 96px) + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 160;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--text);
  color: #fff;
  font-size: 12.5px;
  font-weight: 700;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s;
}
.rc-status.is-shown { opacity: 1; }
.rc-status.is-ok { background: var(--free); }
.rc-status.is-bad { background: var(--danger); }

/* The bulk update, in three numbered steps. */
.rb-step, .rb-preview { margin-block-end: 16px; }
.rb-step__number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-weight: 800;
  flex: none;
}
.rb-preview { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.rb-default { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); }
.rb-range { align-items: flex-end; }
.rb-range .field { margin: 0; }
.rb-weekdays { display: flex; flex-wrap: wrap; gap: 8px; margin-block: 14px 4px; }
.rb-chip { position: relative; cursor: pointer; }
.rb-chip input { position: absolute; opacity: 0; pointer-events: none; }
.rb-chip span {
  display: inline-block;
  padding: 7px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
  font-weight: 650;
  transition: background-color .15s, color .15s;
}
.rb-chip input:checked + span { background: var(--brand); border-color: var(--brand); color: #fff; }
.rb-chip input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
.rb-months[hidden] { display: none; }
.rb-months { margin-block-start: 14px; padding-block-start: 14px; border-block-start: 1px solid var(--border); }
.rb-months__nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-block-end: 10px; }
.rb-months__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px; }
.rb-month__title { font-weight: 800; text-align: center; margin-block-end: 6px; color: var(--brand-dark); }
.rb-month table { width: 100%; border-collapse: separate; border-spacing: 2px; }
.rb-month th { font-size: 11px; font-weight: 700; color: var(--text-muted); padding: 2px; text-align: center; }
.rb-month td { padding: 0; text-align: center; }
.rb-d {
  width: 100%;
  height: 30px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  font: inherit;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  color: var(--text);
}
.rb-d:hover { background: var(--brand-light); }
.rb-d.is-on { background: var(--brand); color: #fff; font-weight: 800; }
.rb-d.is-on:hover { background: var(--brand-dark); }
.rb-plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
.rb-type { position: relative; margin: 0; padding-block-start: 16px; }
.rb-type legend { text-transform: none; letter-spacing: 0; font-size: 13.5px; color: var(--brand-dark); }
.rb-type__all { position: absolute; inset-block-start: -2px; inset-inline-end: 10px; }
.rb-by { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; margin-block-end: 10px; }
.rb-by .label { margin: 0; }
.rb-by .check { padding: 0; }
.rb-value { max-width: 260px; }
.rb-week { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 0 12px; }
.rb-week[hidden], .rb-value[hidden], [data-rb-figures][hidden] { display: none; }

/* Why this price — templates/properties/price_explained.html. */
.px-go label { visibility: hidden; }
.px-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.px-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.px-stat span { font-size: 12.5px; color: var(--text-muted); font-weight: 650; }
.px-stat strong { font-size: 18px; font-weight: 800; color: var(--text); }
.px-nights td, .px-plans td { vertical-align: top; }
.px-rivals, .px-why { text-align: start !important; max-width: 46ch; }
.px-rivals > div + div { margin-block-start: 4px; }
@media (max-width: 760px) {
  .px-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A rate plan's own screen — templates/properties/rate_plan_form.html. */
.pf-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.pf-chips .rb-chip[hidden] { display: none; }
.pf-active { margin-inline-start: 6px; }
.pf-own { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 220px)); gap: 0 14px; }
.pf-own > .field[hidden] { display: none; }
.pf-days__what { margin-block-start: 16px; padding-block-start: 14px; border-block-start: 1px solid var(--border); }
[data-pf-day-price][hidden] { display: none; }
.pf-day-list { margin-block-start: 10px; }
.rb-d.has-mark { position: relative; box-shadow: inset 0 0 0 1px var(--cleaning-br); background: var(--info-bg); }
.rb-d.has-mark::after {
  content: "";
  position: absolute;
  inset-block-end: 3px;
  left: 50%;
  width: 4px; height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--info);
}
.rb-d.is-on.has-mark { background: var(--brand); }
.rb-d:disabled { color: var(--text-soft); background: transparent; cursor: default; opacity: .45; }
.pf-promo {
  padding: 14px 16px 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}
.pf-promo + .pf-promo { margin-block-start: 12px; }
.pf-promo [hidden], .pf-promo[hidden] { display: none; }
.pf-promo__flags { display: flex; gap: 8px; align-items: flex-end; padding-block-start: 22px; }
.pf-drop input:checked + span { background: var(--danger); border-color: var(--danger); color: #fff; }
.pf .errorlist { list-style: none; margin: 4px 0 0; padding: 0; color: var(--danger); font-size: 12px; font-weight: 650; }

