/* ═══════════════════════════════════════════════════════════════════════════
   StockFlow design system — refined command centre

   No build step, no external fonts, no CDN. This runs on Iraqi shared hosting
   over connections that are sometimes poor, and a stylesheet that waits on a
   font server is a stylesheet that shows an unstyled page for two seconds.
   The typography earns its keep through scale, weight and spacing instead of
   through a downloaded face.

   The governing idea: the data should be the brightest thing on the screen.
   So surfaces are quiet — one hairline and one shadow, no gradient headers,
   no page wash — and colour is spent on state rather than decoration. A table
   is not a card inside a card; it is a heading, a rule, and rows.

   Motion explains, never decorates: a row lifts to say it is interactive, a
   view slides a few pixels so you see that it changed, a saved banner arrives
   from above so the eye finds it. Everything obeys prefers-reduced-motion,
   and everything is written with logical properties so the whole interface
   mirrors in Arabic without a second stylesheet.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* One brand colour; everything else is derived from it, so white-labelling
     a client is a single value rather than a hunt through the file. */
  --brand: #3550cf;
  --brand-600: #2b41ab;
  --brand-700: #24378f;
  --brand-300: #7f93e6;
  --brand-100: #d7e0fa;
  --brand-50: #eef1fd;
  --accent: #6d55f0;

  --rail: #161b30;
  --rail-2: #12162a;

  --bg: #f5f6fa;
  --bg-deep: #eef0f6;
  --surface: #ffffff;
  --surface-2: #fafbfd;
  --line: #e3e6ee;
  --line-soft: #f0f2f7;

  --text: #11142a;
  --muted: #5f6880;
  --faint: #6b7285;

  --ok: #0c7a4d;
  --ok-bg: #e8f5ee;
  --ok-line: #b3ddc6;
  --warn: #9a5a00;
  --warn-bg: #fdf6e8;
  --warn-line: #f0dcb2;
  --bad: #c62f22;
  --bad-bg: #fdf1f0;
  --bad-line: #f3c6c1;

  --radius: 10px;
  --radius-sm: 8px;
  --radius-xs: 7px;
  --radius-pill: 999px;

  /* One contact shadow. Depth comes from the hairline; the shadow only stops
     a white card dissolving into a near-white page. */
  --shadow-xs: 0 1px 1px rgba(17, 20, 42, .03);
  --shadow: 0 1px 2px rgba(17, 20, 42, .05);
  --shadow-md: 0 1px 2px rgba(17, 20, 42, .06), 0 6px 18px -8px rgba(17, 20, 42, .14);
  --shadow-lg: 0 10px 40px -12px rgba(17, 20, 42, .26);
  --ring: 0 0 0 3px var(--brand-50);

  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --fast: 110ms;
  --normal: 180ms;
  --slow: 320ms;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", "Noto Sans Arabic", "Segoe UI Arabic", Arial, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body.rtl { direction: rtl; }

a { color: var(--brand); text-decoration: none; transition: color var(--fast) var(--ease); }
a:hover { color: var(--brand-700); text-decoration: underline; text-underline-offset: 2px; }

::selection { background: var(--brand-100); color: var(--brand-700); }

/* ─────────────────────────────── shell ─────────────────────────────────── */

.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 228px;
  flex: 0 0 228px;
  /* A dark navigator against a light workspace. Beyond looking less like a
     stock admin template, it does something useful: the eye stops treating
     the menu as content, so a dense table beside it reads more easily. Flat,
     because a gradient on the one element that never changes is decoration. */
  background: var(--rail);
  color: #9aa3c4;
  padding: 18px 10px 26px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.14) transparent;
}

.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.10); border-radius: 99px;
  border: 2px solid transparent; background-clip: content-box;
}
.sidebar:hover::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); background-clip: content-box; }

.brand {
  display: flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 16px; letter-spacing: -.02em;
  color: #fff;
  padding: 4px 9px 18px;
}

.brand .mark {
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--brand);
  display: grid; place-items: center;
  color: #fff;
  flex: none;
  transition: transform var(--normal) var(--ease-out);
}
.brand:hover .mark { transform: rotate(-8deg); }

.nav-group { margin-bottom: 18px; }

.nav-group .label {
  font-size: 9.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: rgba(255, 255, 255, .48);
  padding: 0 11px 6px;
}

.nav a {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 7px 11px;
  margin-bottom: 1px;
  border-radius: var(--radius-xs);
  color: #9aa3c4;
  font-size: 13px; font-weight: 500;
  text-decoration: none;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.nav a .ico {
  display: grid; place-items: center;
  width: 17px; height: 17px;
  opacity: .6;
  transition: opacity var(--fast) var(--ease);
  flex: none;
}

.nav a:hover {
  background: rgba(255, 255, 255, .05);
  color: #fff;
  text-decoration: none;
}
.nav a:hover .ico { opacity: 1; }

/* The current item is marked by a solid rail, not a glow. It should be
   findable in a glance and invisible the rest of the time. */
.nav a.active {
  background: rgba(255, 255, 255, .07);
  color: #fff;
  font-weight: 620;
}

.nav a.active::before {
  content: "";
  position: absolute;
  inset-inline-start: 0; top: 7px; bottom: 7px;
  width: 2px;
  border-radius: 99px;
  background: var(--brand-300);
}

.nav a.active .ico { opacity: 1; color: #b9c4ff; }

/* ─────────────────────────────── main ──────────────────────────────────── */

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

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 12px;
  padding: 0 26px;
  height: 56px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.topbar h1 { font-size: 17px; font-weight: 660; margin: 0; letter-spacing: -.018em; }
.topbar .spacer { flex: 1; }

/* ── the way back ──
   Left of the title, because that is where a reader's eye goes first and
   where every application on a phone puts it. Sized for a thumb (44px tall,
   the smallest target that can be hit without looking), not for a mouse. */
.backlink {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; margin-inline-start: -10px; padding: 0 11px 0 9px;
  border-radius: var(--radius-sm); color: var(--muted); text-decoration: none;
  font-size: 13px; font-weight: 570; white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.backlink:hover { background: var(--line-soft); color: var(--text); text-decoration: none; }
.backlink .ico { display: inline-flex; }
/* "Back" points the other way in Arabic, and so does the arrow. */
body.rtl .backlink svg { transform: scaleX(-1); }

/* The breadcrumb separator between the way back and the page's own title. */
.topbar .crumb-sep { color: #cfd4e2; font-size: 13px; }

@media (max-width: 620px) {
  .backlink-text { display: none; }
  .backlink { padding: 0 9px; }
}

.content { padding: 22px 26px; max-width: 1500px; width: 100%; animation: page-in var(--normal) var(--ease-out); }

@keyframes page-in {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: none; }
}

/* ── view transitions ──
   The main view is the only thing that moves between pages; the sidebar is
   never re-rendered, so it cannot lose your scroll position. Deliberately
   quick: 110ms out, 180ms in. A transition you have time to admire is a
   transition that will irritate the person who navigates this forty times an
   hour. */
.content.is-leaving {
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 110ms var(--ease-out), transform 110ms var(--ease-out);
}

.content.is-entering { animation: page-in 180ms var(--ease-out); }

/* ── loading bar ── */
.sf-progress {
  position: fixed; inset-block-start: 0; inset-inline-start: 0;
  height: 2px; width: 0; z-index: 999;
  background: var(--brand);
  opacity: 0; pointer-events: none;
}

.sf-progress.running {
  opacity: 1;
  width: 82%;
  transition: width 8s cubic-bezier(.05, .7, .1, 1);
}

.sf-progress.done {
  width: 100%; opacity: 0;
  transition: width 120ms ease-out, opacity 220ms 120ms ease-out;
}

/* ─────────────────────────────── cards ─────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: border-color var(--normal) var(--ease), box-shadow var(--normal) var(--ease);
}

.card .head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 13px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

.card .head h2 { font-size: 14.5px; font-weight: 650; margin: 0; letter-spacing: -.01em; }
.card .body { padding: 16px 20px; }
.card .body.tight { padding: 0; }

/* A heading that belongs to the page rather than to a box — the preferred way
   to introduce a table now that a table no longer needs a card around it. */
.sect {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  margin: 0 0 10px;
}
.sect h2 { font-size: 15px; font-weight: 640; margin: 0; letter-spacing: -.01em; }
.sect .count { font-size: 12.5px; color: var(--faint); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ─────────────────────────────── tables ────────────────────────────────── */

table { width: 100%; border-collapse: collapse; }

thead th {
  text-align: start;
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint);
  padding: 9px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 1;
  white-space: nowrap;
}

tbody td { padding: 9px 16px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; font-size: 13.5px; }

tbody tr { transition: background var(--fast) var(--ease); }
tbody tr:hover { background: var(--surface-2); }
tbody tr:last-child td { border-bottom: none; }

/* A band that divides a table into named groups — a department inside a
   payroll, an account inside a ledger — without starting a second table. */
tbody tr.group td {
  background: var(--surface-2);
  padding: 6px 16px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted);
}
tbody tr.group:hover td { background: var(--surface-2); }

tfoot th {
  padding: 11px 16px;
  border-top: 2px solid var(--line);
  background: var(--surface-2);
  font-weight: 700; font-size: 13px;
  text-align: start;
}

td.num, th.num { text-align: end; font-variant-numeric: tabular-nums; }

/* Numbers keep their own direction even in Arabic, so a minus sign stays on
   the correct side of the figure. Getting this wrong makes a negative look
   positive, which in an accounting system is not a cosmetic problem. */
.mono, td.num, th.num, .stat .v, .fig .v {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
  direction: ltr;
}
td.num { text-align: right; }
body.rtl td.num { text-align: left; }

/* A date, a phone number or a room range written inside Arabic prose comes
   out backwards, and nothing warns you.

   Unicode's bidi algorithm reclassifies European digits that follow Arabic
   letters as Arabic-Number, and the hyphen between them then stops being a
   separator: 2026-09-11 → 2026-09-13 renders as 13-09-2026 → 11-09-2026, so
   the two dates swap and each reads right to left. The same happens to
   +9647… and to (201-212). The rule above already saves every table cell,
   because .mono isolates them; inline prose had nothing.

   .lit marks a run that is a literal machine value rather than language. */
.lit {
  unicode-bidi: isolate;
  direction: ltr;
}

td.ok { color: var(--ok); }
td.bad { color: var(--bad); }

/* ─────────────────────────── the figures bar ───────────────────────────── */
/* Related figures belong in one object separated by hairlines — the way a
   ledger shows a total — not in four cards floating a gap apart. It reads as
   a single thought and costs a third of the height. */

.figures {
  display: flex;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
}

.fig {
  flex: 1; min-width: 0;
  padding: 13px 18px;
  border-inline-end: 1px solid var(--line-soft);
  display: flex; flex-direction: column; gap: 1px;
}
.fig:last-child { border-inline-end: none; }
/* The figure that answers the question the screen exists to ask. */
.fig.lead { background: var(--surface-2); flex: 1.15; }
.fig.lead .v { font-weight: 700; }

.fig .k {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint);
}
.fig .v { font-size: 21px; font-weight: 640; letter-spacing: -.02em; }
.fig .sub { font-size: 11.5px; color: var(--faint); }

@media (max-width: 900px) {
  .figures { flex-wrap: wrap; }
  .fig { flex: 1 1 45%; border-bottom: 1px solid var(--line-soft); }
}

/* ─────────────────────── what is waiting on a person ───────────────────── */
/* Before any statistic: the things that will not move until somebody does
   something about them. The stripe carries the urgency; the words carry the
   meaning. */

.waiting { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }

.wait-card {
  display: flex; flex-direction: column; gap: 3px;
  padding: 13px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--brand);
  border-radius: var(--radius);
  box-shadow: var(--shadow-xs);
  color: inherit; text-decoration: none;
  transition: box-shadow var(--fast) var(--ease), transform var(--fast) var(--ease);
}
a.wait-card:hover { text-decoration: none; box-shadow: var(--shadow-md); transform: translateY(-1px); }
.wait-card.warn { border-inline-start-color: var(--warn); }
.wait-card.bad { border-inline-start-color: var(--bad); }
.wait-card .k { font-size: 12.5px; color: var(--muted); }
.wait-card .t { font-size: 14.5px; font-weight: 640; letter-spacing: -.01em; }
.wait-card .sub { font-size: 12px; color: var(--faint); }

/* ─────────────────────────────── buttons ───────────────────────────────── */

.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit; font-size: 12.5px; font-weight: 570;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: var(--shadow-xs);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              color var(--fast) var(--ease), transform var(--fast) var(--ease),
              box-shadow var(--fast) var(--ease);
}

.btn:hover { background: var(--surface-2); border-color: #d2d7e4; text-decoration: none; }
.btn:active { transform: scale(.985); }
.btn:focus-visible { outline: none; box-shadow: var(--ring); border-color: var(--brand-300); }

.btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(17, 20, 42, .10);
}
.btn.primary:hover { background: var(--brand-600); border-color: var(--brand-600); }

.btn.danger { color: var(--bad); border-color: var(--bad-line); background: var(--bad-bg); }
.btn.danger:hover { background: #fbe4e2; border-color: #ecb5ae; }

.btn.ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--muted); }
.btn.ghost:hover { background: var(--line-soft); color: var(--text); }

/* Row actions. These were 28px tall — under the 32px floor the front desk's
   own buttons respect — and the Edit/Delete pair sat three pixels apart, with
   nothing but colour between "open this" and "destroy this". */
.btn.sm { padding: 5px 11px; font-size: 11.5px; min-height: 32px; border-radius: var(--radius-xs); }

/* A cell of row actions spaces them properly; inline forms inside a table cell
   have no margin of their own, which is where the three pixels came from. */
td.right, td.actions {
  white-space: nowrap;
}
td.right > *, td.actions > * { vertical-align: middle; }
td.right > form, td.actions > form { margin-inline-start: 8px; }
td.right > .btn + .btn, td.actions > .btn + .btn { margin-inline-start: 8px; }
.btn.tall { padding: 10px 18px; font-size: 13.5px; min-height: 44px; }

/* ─────────────────────────────── forms ─────────────────────────────────── */

label.f {
  display: block;
  font-size: 11px; font-weight: 650; letter-spacing: .01em;
  color: var(--muted);
  margin-bottom: 5px;
}

input, select, textarea {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid #dfe3ec;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit; font-size: 13.5px;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

input:hover, select:hover, textarea:hover { border-color: #cdd3e1; }

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand-300);
  box-shadow: var(--ring);
}

input::placeholder { color: #6b7285; }
input:disabled, select:disabled { background: var(--bg-deep); color: var(--muted); cursor: not-allowed; }

input.small, select.small { padding: 5px 9px; font-size: 12.5px; border-radius: var(--radius-xs); }

select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' stroke='%23939bb0' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-inline-end: 30px;
}
body.rtl select { background-position: left 10px center; padding-inline-end: 11px; padding-inline-start: 30px; }

input[type=checkbox] { width: auto; accent-color: var(--brand); }

/* Table cells hold bare inputs on the setup screens; they should read as part
   of the row until touched. */
td input, td select { border-color: transparent; background: transparent; }
td input:hover, td select:hover { border-color: var(--line); background: var(--surface); }
td input:focus, td select:focus { border-color: var(--brand-300); background: var(--surface); }

table.fields td input, table.fields td select {
  border-color: #dfe3ec; background: var(--surface);
}
table.fields td input:hover, table.fields td select:hover { border-color: var(--brand-300); }

/* ── a settings row ──
   What the setting is on the left with its sentence of help underneath, the
   control on the right. A table forced the help text into a column too narrow
   to read it in, which is how a screen that exists to explain itself stopped
   explaining anything. */
.srow {
  display: grid; grid-template-columns: minmax(0, 1fr) 210px; gap: 24px;
  align-items: start;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line-soft);
}
.srow:last-child { border-bottom: none; }
.srow.is-locked { background: #fbfbfd; }
.srow .sname { font-size: 13.5px; font-weight: 600; }
.srow .shelp { font-size: 12.5px; color: var(--muted); max-width: 74ch; }
.srow .sctl { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.srow .sctl input, .srow .sctl select { text-align: end; }
.srow .unit { font-size: 12.5px; color: var(--faint); flex: none; }

@media (max-width: 760px) {
  .srow { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .srow .sctl { justify-content: flex-start; }
}

/* ── the settings page ──
   A jump list beside the sections, because someone opens this page hunting one
   figure and should not have to scroll past four modules to reach it. */
.settings-layout {
  display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 24px;
  align-items: start;
  max-width: 1220px;
}
.settings-jump {
  position: sticky; top: 76px;
  display: flex; flex-direction: column; gap: 1px;
  margin-top: 16px;
}
.settings-jump .label {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); padding: 0 11px 6px;
}
.settings-jump a {
  padding: 7px 11px; border-radius: var(--radius-xs);
  font-size: 12.5px; color: var(--muted); text-decoration: none;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.settings-jump a:hover { background: var(--line-soft); color: var(--text); text-decoration: none; }

.settings-main > .card:first-child { margin-top: 16px; }
/* An anchored section should not land under the sticky top bar. */
.settings-main .card[id] { scroll-margin-top: 72px; }

@media (max-width: 980px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); }
  .settings-jump { position: static; flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .settings-jump .label { display: none; }
  .settings-jump a { border: 1px solid var(--line); background: var(--surface); }
}

/* ────────────────────────── pills, alerts, misc ────────────────────────── */

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2.5px 10px;
  border-radius: var(--radius-pill);
  font-size: 11.5px; font-weight: 640; letter-spacing: .01em;
  background: var(--bg-deep); color: var(--muted);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.pill.ok { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
.pill.warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }
.pill.bad { background: var(--bad-bg); color: var(--bad); border-color: var(--bad-line); }
.pill.brand { background: var(--brand-50); color: var(--brand-600); border-color: var(--brand-100); }

/* Every state carries a dot as well as a word, so it survives a grayscale
   print of a payslip and a colour-blind reader. */
.pill.ok::before, .pill.warn::before, .pill.bad::before, .pill.brand::before {
  content: ""; width: 5px; height: 5px; border-radius: 99px;
  background: currentColor; flex: none;
}
/* Only what is waiting on a person pulses — and it has to be said explicitly.
   .pill.warn is used for VIP, for a closed period, for a reversed entry and
   for a forecast date, so hanging the animation on it set eleven closed
   periods blinking in unison, for ever, on a screen staff keep open all day. */
.pill.is-waiting::before { animation: pulse 2.4s var(--ease) infinite; }
@keyframes pulse { 0%, 100% { opacity: .4; } 50% { opacity: 1; } }

.alert {
  padding: 12px 16px;
  border-radius: var(--radius);
  margin-bottom: 16px;
  font-size: 13.5px;
  border: 1px solid var(--line);
  background: var(--surface);
  animation: alert-in var(--normal) var(--ease-out);
}
@keyframes alert-in {
  from { opacity: 0; transform: translateY(-5px); }
  to { opacity: 1; transform: none; }
}

.alert.ok { background: var(--ok-bg); color: #0a6b42; border-color: var(--ok-line); }
.alert.bad { background: var(--bad-bg); color: #96271c; border-color: var(--bad-line); }
.alert.warn { background: var(--warn-bg); color: #855000; border-color: var(--warn-line); }

.small { font-size: 12px; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.right { text-align: end; }
.nowrap { white-space: nowrap; }

/* ─────────────────────────────── layout ────────────────────────────────── */

.grid { display: grid; gap: 16px; }
.grid.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 1180px) { .grid.c4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 820px) { .grid.c4, .grid.c3, .grid.c2 { grid-template-columns: 1fr; } }

/* On a portrait tablet the rail was 2,149px tall and the content began below
   it — a receptionist scrolled past two screens of menu to reach the board.
   The intent was always for the links to wrap; they could not, because the
   flex children were the groups rather than the links themselves. */
@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .sidebar {
    width: auto; flex: none; height: auto; max-height: 40vh;
    position: static; padding: 12px 10px;
  }
  .nav { display: flex; flex-wrap: wrap; gap: 2px; }
  .nav-group { display: contents; }
  .nav-group .label { flex: 0 0 100%; padding-top: 8px; }
  .nav a { flex: 0 0 auto; }
  .nav a.active::before { display: none; }
}

/* The folio's two columns, written here rather than inline on the element.

   An inline grid-template-columns beats any media query, so the folio stayed
   two columns at every width and the card clipped its own Void buttons off
   the right edge below about 1100px — .card has overflow:hidden, so they were
   not merely awkward, they were unreachable. Voiding a mis-posted line is the
   only way to correct a folio, and on a tablet it could not be pressed. */
.grid.folio-split { grid-template-columns: 1fr; }
@media (min-width: 1100px) {
  .grid.folio-split { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
}

/* ──────────────────────────── stat tiles ──────────────────────────────── */
/* Kept for the few places a single figure genuinely stands alone. Where four
   of them sit in a row, .figures is the better object. */

.stat {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: box-shadow var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.stat:hover { box-shadow: var(--shadow-md); }

.stat .k { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
           text-transform: uppercase; color: var(--faint); }
.stat .v { display: block; font-size: 24px; font-weight: 640; letter-spacing: -.025em; margin-top: 3px; }

/* ───────────────────────── responsive & motion ─────────────────────────── */

@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .sidebar {
    width: 100%; flex: none; height: auto; position: static;
    border-inline-end: none; border-bottom: 1px solid var(--line);
    padding-bottom: 12px;
  }
  .nav { display: flex; flex-wrap: wrap; gap: 4px; }
  .nav-group { margin-bottom: 10px; width: 100%; }
  .content { padding: 18px 14px; }
  .topbar { padding: 0 16px; }
}

/* Someone who has asked their system to stop animating has usually asked for
   a reason. Everything still works; it simply arrives. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ─────────────────────────────── print ─────────────────────────────────── */

@media print {
  body { background: #fff; }
  .sidebar, .topbar, .no-print, .btn { display: none !important; }
  .content { padding: 0; max-width: none; animation: none; }
  .card, .figures { border: 1px solid #ddd; box-shadow: none; break-inside: avoid; }
  .card .head { background: none; }
  thead th { background: none; color: #000; }
}

/* A button that is working says so, and nothing moves while it does.

   That was the intention; the spinner was an extra flex child, so a 13px
   circle plus the 7px gap grew the button by 24px. On the payroll run the
   Approve button sits 8px from Discard draft, so pressing Approve slid a
   destructive button leftward under the cursor that had just clicked. The
   spinner is now laid over the button's own box and the label is hidden
   rather than pushed, so the width never changes. */
.btn.is-busy { pointer-events: none; opacity: .75; position: relative; }
.btn.is-busy > *, .btn.is-busy { color: inherit; }
.btn.is-busy > * { visibility: hidden; }
.btn.is-busy::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 13px; height: 13px;
  border-radius: 99px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ═══════════════════════ workshop console ═══════════════════════
   The deployment console is our tool, not the product. It says so — quietly
   in the sidebar, and unmissably whenever a client's system is being
   demonstrated, because "which system am I looking at" must never be a
   question you have to answer by reading the data. */

.brand-tag {
  font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; margin-inline-start: 2px;
  background: rgba(124, 92, 255, .22); color: #c9bcff;
  border: 1px solid rgba(124, 92, 255, .35);
}

/* Leaving a demonstration is a POST — it changes session state — but it
   belongs in the menu, so it has to look like every other menu item. */
.nav-form { margin: 0; }

.nav-exit {
  display: flex; align-items: center; gap: 11px; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: start;
  font: inherit; color: #aeb6d4; font-size: 13.5px; font-weight: 500;
  padding: 8px 12px; border-radius: var(--radius-sm);
  transition: background var(--fast), color var(--fast);
}

.nav-exit:hover { background: rgba(255, 255, 255, .06); color: #fff; }

.demo-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 26px;
  background: linear-gradient(90deg, rgba(124, 92, 255, .16), rgba(63, 91, 216, .10));
  border-block-end: 1px solid rgba(124, 92, 255, .28);
  font-size: 13px;
}

.demo-bar .demo-text { flex: 1; min-width: 220px; }
.demo-bar .demo-note { color: var(--muted); margin-inline-start: 8px; }

/* A slow pulse rather than a fast blink: present in peripheral vision without
   competing with the work. */
.demo-dot {
  width: 8px; height: 8px; border-radius: 50%; background: #7c5cff; flex: none;
  box-shadow: 0 0 0 3px rgba(124, 92, 255, .22);
  animation: pulse 2.4s ease-in-out infinite;
}

.btn.ghost { background: transparent; box-shadow: none; }

@media (max-width: 860px) { .demo-bar { padding: 9px 14px; } }

/* ── module picker in the console ── */
.module-pick {
  display: flex; gap: 10px; align-items: flex-start; padding: 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); cursor: pointer;
  background: var(--surface); transition: border-color var(--fast), box-shadow var(--fast);
}
.module-pick:hover { border-color: var(--brand-300); box-shadow: var(--ring); }
/* Planned modules read as a plan: quieter, dashed, no lift on hover. What can
   be sold and what cannot must not look the same. */
.module-pick.planned { border-style: dashed; background: var(--surface-2); color: var(--muted); }
.module-pick.planned:hover { border-color: var(--warn-line); box-shadow: none; }
.module-pick.planned b { color: var(--muted); font-weight: 600; }

/* A card head can hold several things: title, count, then actions pushed to
   the end. The spacer takes the slack so justify-content need not change. */
.card .head .spacer { flex: 1; }

/* ── licence card on the dashboard ──
   A left rail in the semantic colour, so its state reads before its words. */
.licence-card { border-inline-start: 4px solid var(--ok); }
.licence-card.warn { border-inline-start-color: var(--warn); }
.licence-card.bad { border-inline-start-color: var(--bad); }
.licence-card .chip {
  width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; flex: none;
  background: var(--ok-bg); color: var(--ok);
}
.licence-card.warn .chip { background: var(--warn-bg); color: var(--warn); }
.licence-card.bad .chip { background: var(--bad-bg); color: var(--bad); }
.licence-card b.ok { color: var(--ok); } .licence-card b.warn { color: var(--warn); } .licence-card b.bad { color: var(--bad); }

/* ═══════════════════════════ the till ═══════════════════════════
   A cashier's screen: big targets, a menu on one side, the bill on the
   other, and nothing that is not about the sale in front of them. Sized for
   a tablet held sideways; on a phone it stacks. */

.till {
  display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: 16px;
  min-height: calc(100vh - 120px);
}
@media (max-width: 980px) { .till { grid-template-columns: minmax(0, 1fr); } }

.till-menu { display: flex; flex-direction: column; gap: 12px; min-width: 0; }

.till-cats { display: flex; gap: 8px; flex-wrap: wrap; }
.till-cats .cat {
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
  padding: 10px 16px; border-radius: 999px; font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
  transition: background var(--fast), border-color var(--fast), color var(--fast);
}
.till-cats .cat.active { background: var(--brand); border-color: var(--brand); color: #fff; }

.till-items {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; align-content: start;
}
.till-items .item {
  display: flex; flex-direction: column; justify-content: space-between; gap: 8px; min-height: 92px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 14px; text-align: start; cursor: pointer; font: inherit; color: var(--text);
  box-shadow: var(--shadow-xs);
  transition: transform var(--fast) var(--ease), box-shadow var(--fast), border-color var(--fast);
}
.till-items .item:hover { border-color: var(--brand-300); box-shadow: var(--shadow); }
.till-items .item:active, .till-items .item.pop { transform: scale(.97); border-color: var(--brand); }
.till-items .item .name { font-weight: 600; line-height: 1.3; }
.till-items .item .price { font-family: ui-monospace, Menlo, Consolas, monospace; color: var(--muted); font-size: 13px; }

.till-ticket {
  display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; position: sticky; top: 74px;
  max-height: calc(100vh - 100px);
}
.till-head { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; padding: 14px 16px; border-bottom: 1px solid var(--line-soft); }
.till-head .ticket-no { font-weight: 700; font-size: 16px; letter-spacing: -.01em; }
.till-open { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; align-items: center; }
.chip-btn {
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text); font: inherit; font-size: 12.5px; font-weight: 600;
  padding: 6px 10px; border-radius: 999px; cursor: pointer;
}
.chip-btn.active { background: var(--brand-50); border-color: var(--brand-300); color: var(--brand-700); }
.chip-btn.primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.table-in { width: 72px; padding: 6px 8px; border-radius: 999px; border: 1px solid var(--line); font-size: 12.5px; }

.till-lines { flex: 1; overflow-y: auto; min-height: 120px; }
.till-lines .line {
  display: grid; grid-template-columns: 44px 1fr auto 32px; gap: 8px; align-items: center;
  padding: 9px 12px 9px 16px; border-bottom: 1px solid var(--line-soft); font-size: 14px;
  animation: page-in 180ms var(--ease-out);
}
.till-lines .line .qty { color: var(--muted); font-family: ui-monospace, monospace; }
.till-lines .line .nm { font-weight: 500; }
.till-lines .line .rm {
  width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--line); background: var(--surface);
  color: var(--muted); cursor: pointer; font-size: 16px; line-height: 1;
}
.till-lines .line .rm:hover { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad); }

.till-totals { padding: 12px 16px 6px; border-top: 1px solid var(--line-soft); font-size: 13.5px; }
.till-totals > div { display: flex; justify-content: space-between; padding: 3px 0; }
.till-totals b { font-family: ui-monospace, Menlo, Consolas, monospace; font-weight: 600; }
.till-totals .grand { font-size: 18px; padding-top: 8px; margin-top: 4px; border-top: 1px dashed var(--line); }
.till-totals .grand b { font-weight: 700; }

.till-actions { display: grid; grid-template-columns: 1fr 1fr 1.6fr; gap: 8px; padding: 10px 16px 14px; }
.till-actions .btn { padding: 12px; font-size: 14px; }
.till-actions .btn.big { font-size: 16px; }
.till-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 16px; border-top: 1px solid var(--line-soft); background: var(--surface-2); }
#status.bad { color: var(--bad); font-weight: 600; }

/* Dialogs: a dimmed screen and one card. No library. */
/* The hidden attribute must win over any display the class sets — a dialog
   that is display:grid by class would otherwise be visible while "hidden". */
[hidden] { display: none !important; }
.till-modal { position: fixed; inset: 0; z-index: 50; background: rgba(20, 23, 42, .45); display: grid; place-items: center; padding: 16px; }
.till-dialog { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow-lg); width: min(460px, 100%); padding: 20px 22px; animation: page-in 160ms var(--ease-out); }
.till-dialog h3 { margin: 0 0 14px; font-size: 17px; display: flex; justify-content: space-between; }
.till-dialog label { display: grid; grid-template-columns: 110px 1fr; align-items: center; gap: 10px; margin: 8px 0; font-size: 13.5px; }
.till-dialog label input { font-size: 16px; padding: 10px 12px; }
.till-dialog .tenders input { text-align: end; }
.till-dialog .quick { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.till-dialog .pay-line { display: flex; justify-content: space-between; font-size: 15px; padding: 6px 0; }
.till-dialog .pay-line b { font-family: ui-monospace, monospace; }
.till-dialog .pay-line b.bad { color: var(--bad); }
.till-dialog .dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.till-dialog .btn.big { padding: 12px 20px; font-size: 15px; }

/* ═══════════════════════ Front desk — built for fingers ═══════════════════════
   Targets are 56px or taller, states are colour plus a word (never colour
   alone), and the room a receptionist tapped stays lit while its panel is open. */
.fd-top { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.fd-top .date { font-size: 18px; font-weight: 700; letter-spacing: -.01em; }
.fd-top .date small { display: block; font-size: 12px; color: var(--muted); font-weight: 500; }
.fd-kpis { display: flex; gap: 8px; flex-wrap: wrap; }
.fd-kpis > a, .fd-kpis > span { display: inline-flex; flex-direction: column; min-width: 92px; min-height: 56px; padding: 8px 14px; border-radius: 12px; border: 1px solid var(--line); background: var(--surface); text-decoration: none; color: var(--text); justify-content: center; }
.fd-kpis .n { display: block; font-size: 22px; font-weight: 700; line-height: 1; font-family: ui-monospace, Menlo, Consolas, monospace; }
.fd-kpis .k { display: block; font-size: 11.5px; color: var(--muted); margin-top: 3px; }
.fd-kpis a:hover { border-color: var(--brand-300); }
.fd-kpis a.active { border-color: var(--brand); box-shadow: var(--ring); }

.fd-filters { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 14px; }
.fd-filters .chip-btn, .fd-chip { min-height: 44px; padding: 8px 16px; font-size: 14px; border-radius: 22px; border: 1px solid var(--line); background: var(--surface); color: var(--text); cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
.fd-filters .chip-btn.active, .fd-chip.active { background: var(--brand); border-color: var(--brand); color: #fff; }

.fd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
.fd-tile { position: relative; min-height: 112px; border-radius: 14px; border: 2px solid var(--line); background: var(--surface); padding: 10px 12px; text-align: start; cursor: pointer; display: flex; flex-direction: column; gap: 4px; transition: transform 120ms var(--ease-out), box-shadow 120ms; color: var(--text); text-decoration: none; -webkit-tap-highlight-color: transparent; }
.fd-tile:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); text-decoration: none; }
.fd-tile:hover span { text-decoration: none; }
.fd-tile:active { transform: scale(.97); }
.fd-tile.selected { box-shadow: var(--ring); border-color: var(--brand); }
.fd-tile .no { font-size: 22px; font-weight: 800; letter-spacing: -.02em; font-family: ui-monospace, Menlo, Consolas, monospace; line-height: 1; }
.fd-tile .type { font-size: 11.5px; color: var(--muted); }
.fd-tile .who { font-size: 12.5px; font-weight: 600; margin-top: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The status word and the connecting-room list share the bottom line rather
   than one floating over the other. The list was absolutely positioned, so on
   a room with two doors it ran straight into the word beside it. */
.fd-tile .foot { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.fd-tile .st { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.fd-tile .hk { position: absolute; top: 10px; inset-inline-end: 10px; width: 12px; height: 12px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px var(--line); }
.fd-tile .hk.dirty { background: var(--warn); } .fd-tile .hk.clean { background: var(--ok); } .fd-tile .hk.inspected { background: var(--brand); } .fd-tile .hk.pickup { background: #b96f00; opacity: .55; }
.fd-tile .conn { font-size: 10.5px; color: var(--muted); white-space: nowrap; unicode-bidi: isolate; direction: ltr; }
.fd-tile.vacant { background: #f4fbf7; border-color: #cbe9d8; } .fd-tile.vacant .st { color: var(--ok); }
.fd-tile.dirty { background: #fff8ea; border-color: #f1dcae; } .fd-tile.dirty .st { color: var(--warn); }
.fd-tile.occupied { background: #eef2fe; border-color: #c6d2f7; } .fd-tile.occupied .st { color: var(--brand-600); }
.fd-tile.departing { background: #eef2fe; border-color: var(--brand); border-style: dashed; } .fd-tile.departing .st { color: var(--brand-700); }
.fd-tile.arriving { background: #fbf5ff; border-color: #dcc7fb; border-style: dashed; } .fd-tile.arriving .st { color: var(--accent); }
.fd-tile.ooo, .fd-tile.oos { background: var(--bg-deep); border-color: var(--line); color: var(--muted); } .fd-tile.ooo .st, .fd-tile.oos .st { color: var(--bad); }
.fd-tile[hidden] { display: none; }

.fd-legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; color: var(--muted); margin: 12px 0 0; }
.fd-legend i { display: inline-block; width: 12px; height: 12px; border-radius: 3px; vertical-align: -2px; margin-inline-end: 4px; border: 1px solid var(--line); }

/* the panel that opens when a tile is tapped */
.fd-panel { position: fixed; top: 0; bottom: 0; inset-inline-end: 0; width: min(420px, 100%); background: var(--surface); box-shadow: var(--shadow-lg); z-index: 60; transform: translateX(105%); transition: transform 200ms var(--ease-out); display: flex; flex-direction: column; }
[dir=rtl] .fd-panel { transform: translateX(-105%); }
.fd-panel.open { transform: none; }
.fd-panel .ph { padding: 18px 20px 12px; border-bottom: 1px solid var(--line-soft); display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.fd-panel .ph .no { font-size: 30px; font-weight: 800; font-family: ui-monospace, Menlo, Consolas, monospace; letter-spacing: -.02em; line-height: 1; }
.fd-panel .ph .sub { color: var(--muted); font-size: 13px; margin-top: 4px; }
.fd-panel .pb { padding: 16px 20px; overflow-y: auto; flex: 1; }
.fd-panel .pb h4 { margin: 14px 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.fd-panel .feat { display: flex; gap: 6px; flex-wrap: wrap; }
.fd-panel .feat span { font-size: 12px; padding: 4px 9px; border-radius: 8px; background: var(--bg-deep); }
.fd-panel .guest { font-size: 17px; font-weight: 650; }
.fd-panel .pa { padding: 12px 20px 18px; border-top: 1px solid var(--line-soft); display: grid; gap: 8px; }
.fd-panel .pa .btn, .fd-actions .btn { min-height: 56px; font-size: 15.5px; border-radius: 12px; justify-content: center; }
.fd-panel .pa form { display: contents; }
.fd-close { width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line); background: var(--surface); font-size: 20px; cursor: pointer; }
.fd-scrim { position: fixed; inset: 0; background: rgba(20,23,42,.25); z-index: 55; }

/* big buttons anywhere on the desk */
.fd-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
/* The desk's own buttons are sized for a finger on a busy counter. `.tall`
   is the general comfortable target and stays modest; `.huge` is the desk. */
.fd-actions .btn.tall, .fd-panel .btn.tall { min-height: 56px; font-size: 15.5px; border-radius: 12px; }
.btn.huge { min-height: 68px; font-size: 18px; border-radius: 14px; }

/* steppers: numbers by thumb */
.fd-step { display: inline-flex; align-items: center; border: 1px solid var(--line); border-radius: 12px; overflow: hidden; background: var(--surface); }
.fd-step button { width: 56px; height: 56px; border: 0; background: var(--surface-2); font-size: 24px; cursor: pointer; color: var(--brand); }
.fd-step button:active { background: var(--brand-100); }
.fd-step input { width: 64px; height: 56px; border: 0; text-align: center; font-size: 20px; font-weight: 700; border-radius: 0; }
.fd-step input:focus { box-shadow: none; }
.fd-date { min-height: 56px; font-size: 17px; padding: 10px 14px; border-radius: 12px; }

/* wizard */
.fd-wiz { display: flex; gap: 6px; margin: 0 0 16px; }
.fd-wiz span { flex: 1; text-align: center; padding: 10px 6px; border-radius: 10px; background: var(--bg-deep); color: var(--muted); font-size: 13px; font-weight: 600; }
.fd-wiz span.on { background: var(--brand); color: #fff; }
.fd-wiz span.done { background: var(--ok-bg); color: var(--ok); }
.fd-pane[hidden] { display: none; }

.fd-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
.fd-card { border: 2px solid var(--line); border-radius: 16px; padding: 16px; background: var(--surface); cursor: pointer; text-align: start; display: flex; flex-direction: column; gap: 6px; min-height: 150px; transition: transform 120ms var(--ease-out); }
.fd-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.fd-card.selected { border-color: var(--brand); box-shadow: var(--ring); }
.fd-card.none { opacity: .55; cursor: not-allowed; }
.fd-card .nm { font-size: 17px; font-weight: 700; }
.fd-card .beds { color: var(--muted); font-size: 13px; }
.fd-card .price { margin-top: auto; font-size: 20px; font-weight: 800; font-family: ui-monospace, Menlo, Consolas, monospace; }
.fd-card .price small { font-size: 12px; color: var(--muted); font-weight: 500; font-family: inherit; }
.fd-card .avail { font-size: 12.5px; font-weight: 600; }
.fd-card .avail.ok { color: var(--ok); } .fd-card .avail.low { color: var(--warn); } .fd-card .avail.none { color: var(--bad); }
.fd-card .feat { display: flex; gap: 4px; flex-wrap: wrap; }
.fd-card .feat span { font-size: 11px; padding: 2px 7px; border-radius: 6px; background: var(--bg-deep); color: var(--muted); }

.fd-roompick { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 8px; }
.fd-roompick .fd-tile { min-height: 84px; }
.fd-roompick .fd-tile.taken { opacity: .45; cursor: not-allowed; }

.fd-summary { background: var(--bg-deep); border-radius: 14px; padding: 16px 18px; display: grid; gap: 6px; }
.fd-summary .row { display: flex; justify-content: space-between; font-size: 14px; }
.fd-summary .row b { font-family: ui-monospace, Menlo, Consolas, monospace; }
.fd-summary .row.total { font-size: 18px; padding-top: 8px; border-top: 1px dashed var(--line); margin-top: 4px; }

.fd-guestpick { position: relative; }
.fd-guestpick .hits { position: absolute; z-index: 10; inset-inline: 0; top: 100%; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow-lg); max-height: 320px; overflow-y: auto; }
.fd-guestpick .hits button { display: flex; justify-content: space-between; width: 100%; min-height: 56px; padding: 10px 14px; border: 0; border-bottom: 1px solid var(--line-soft); background: none; text-align: start; cursor: pointer; font-size: 14.5px; }
.fd-guestpick .hits button:hover { background: var(--brand-50); }
.fd-guestpick .hits small { color: var(--muted); }
.fd-form input, .fd-form select, .fd-form textarea { min-height: 52px; font-size: 16px; }
.fd-form textarea { min-height: 80px; }

/* tenders as buttons, like the till */
.fd-tenders { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }
.fd-tenders label { border: 2px solid var(--line); border-radius: 12px; padding: 12px; text-align: center; cursor: pointer; font-weight: 600; min-height: 56px; display: flex; align-items: center; justify-content: center; }
.fd-tenders input { display: none; }
.fd-tenders input:checked + span { color: var(--brand-700); }
.fd-tenders label:has(input:checked) { border-color: var(--brand); background: var(--brand-50); }
.fd-quick { display: flex; gap: 8px; flex-wrap: wrap; }
.fd-quick .chip-btn { min-height: 44px; padding: 8px 14px; font-size: 14px; border-radius: 22px; }
.fd-quick input, .fd-quick select { width: auto; }
.fd-quick.grow input { flex: 1; }

/* the folio */
.fd-folio-lines .void td { text-decoration: line-through; color: var(--faint); }
.fd-balance { font-size: 28px; font-weight: 800; font-family: ui-monospace, Menlo, Consolas, monospace; letter-spacing: -.02em; }
.fd-balance.credit { color: var(--ok); } .fd-balance.due { color: var(--bad); }

/* tape chart */
.fd-chart { overflow-x: auto; }
.fd-chart table { border-collapse: separate; border-spacing: 0; min-width: 900px; }
.fd-chart th, .fd-chart td { border-bottom: 1px solid var(--line-soft); border-inline-end: 1px solid var(--line-soft); padding: 0; height: 44px; }
.fd-chart th.day { font-size: 11px; font-weight: 600; color: var(--muted); text-align: center; min-width: 56px; }
.fd-chart th.day.today { background: var(--brand-50); color: var(--brand-700); }
.fd-chart th.day.we { background: var(--surface-2); }
.fd-chart td.room { position: sticky; inset-inline-start: 0; background: var(--surface); padding: 0 12px; font-weight: 700; font-family: ui-monospace, Menlo, Consolas, monospace; min-width: 110px; z-index: 2; }
.fd-chart td.room small { display: block; font-family: inherit; font-weight: 500; color: var(--muted); font-size: 11px; }
.fd-chart td.cell { position: relative; min-width: 56px; }
.fd-chart td.cell a.free { display: block; width: 100%; height: 100%; }
.fd-chart td.cell a.free:hover { background: var(--ok-bg); }
.fd-chart td.cell.ooo { background: repeating-linear-gradient(45deg, var(--bg-deep), var(--bg-deep) 6px, #fff 6px, #fff 12px); }
.fd-chart .bar { position: absolute; top: 6px; bottom: 6px; inset-inline-start: 50%; border-radius: 8px; padding: 0 10px; font-size: 12px; font-weight: 600; color: #fff; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-decoration: none; z-index: 1; }
.fd-chart .bar.confirmed, .fd-chart .bar.tentative { background: var(--accent); }
.fd-chart .bar.tentative { opacity: .7; }
.fd-chart .bar.checked_in { background: var(--brand); }
.fd-chart .bar:hover { filter: brightness(1.08); }

/* housekeeping */
.fd-hk-floor { margin-bottom: 18px; }
.fd-hk-floor h3 { margin: 0 0 8px; font-size: 14px; color: var(--muted); }
.fd-hk-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }
.fd-hk-actions .btn { min-height: 64px; font-size: 16px; border-radius: 12px; }

/* setup */
.fd-bedrows .row { display: grid; grid-template-columns: 1fr 120px 44px; gap: 8px; margin-bottom: 6px; }
.fd-checks { display: flex; gap: 8px; flex-wrap: wrap; }
.fd-checks label { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 10px; font-size: 13px; cursor: pointer; min-height: 40px; }
.fd-checks label:has(input:checked) { border-color: var(--brand); background: var(--brand-50); }
.fd-rategrid input { width: 110px; text-align: end; }

@media (max-width: 720px) {
  .fd-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
  .fd-tile .no { font-size: 19px; }
}
@media print {
  .fd-panel, .fd-scrim, .fd-filters, .fd-kpis { display: none !important; }
}

/* ─────────────────────────── the set-up wizard ──────────────────────────
   One question per screen, on a column narrow enough to read and wide enough
   to type in. The rail is not decoration: someone halfway through a set-up
   wants to know how much is left before they commit to starting. */
.wiz { max-width: 1180px; }

/* One strip divided by hairlines rather than a wrapping row of pills — eight
   chips on two lines read as clutter, and told you nothing a single line of
   named segments does not. */
.wiz-rail {
  display: flex;
  list-style: none; margin: 0 0 18px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow-xs);
  overflow: hidden;
}
.wiz-rail li {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 7px;
  padding: 9px 12px;
  border-inline-end: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: 12px; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wiz-rail li:last-child { border-inline-end: none; }
.wiz-rail .n {
  display: grid; place-items: center;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--line-soft); color: var(--faint);
  font-size: 10px; font-weight: 700;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  flex: none;
}
.wiz-rail li.done .n { background: var(--ok-bg); color: var(--ok); }
.wiz-rail li.here { background: var(--surface-2); color: var(--text); font-weight: 640; }
.wiz-rail li.here .n { background: var(--brand); color: #fff; }

@media (max-width: 1000px) {
  .wiz-rail { flex-wrap: wrap; }
  .wiz-rail li { flex: 1 1 33%; border-bottom: 1px solid var(--line-soft); }
}

.wiz-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px 16px; }
.wiz-grid .wide { grid-column: 1 / -1; }
@media (max-width: 760px) { .wiz-grid { grid-template-columns: 1fr; } }

/* ── one person, one block ──
   A header strip carrying who this is, then their fields on a single row, then
   a full-width rule. Reading across a person beats reading down a column of
   repeated labels, and the rule is what stops six people becoming one wall. */
.wiz-people { display: flex; flex-direction: column; }

.wiz-person-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 20px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-soft);
  font-size: 13px;
}
.wiz-person-head .n {
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: var(--radius-xs);
  background: var(--brand-50); color: var(--brand);
  font-size: 11px; font-weight: 700;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  flex: none;
}
.wiz-person-head.is-empty .n { background: var(--line-soft); color: var(--faint); }
.wiz-person-head .who { font-weight: 620; }
.wiz-person-head .hint { color: var(--faint); font-size: 12px; }
.wiz-person-head .spacer { flex: 1; }

.wiz-person {
  display: grid;
  grid-template-columns: 2.2fr 1fr 1.4fr 1.4fr 1.6fr 1.3fr;
  gap: 14px;
  padding: 14px 20px 18px;
  border-bottom: 1px solid var(--line);
}
.wiz-person:last-of-type { border-bottom: none; }

@media (max-width: 1100px) { .wiz-person { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 700px) { .wiz-person { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ── what a property sells ──
   A tile is a fixed three-part object: what it is, which account it credits,
   what it costs. Nothing is positioned on top of anything, so nothing can
   hang outside the box. */
.wiz-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(212px, 1fr)); gap: 12px; }

.wiz-group { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.wiz-group:last-child { margin-bottom: 0; }
.wiz-group-label {
  /* A row header inside the step's single grid, not the heading of a grid
     of its own. */
  grid-column: 1 / -1;
  margin-top: 6px;
  display: flex; align-items: center; gap: 10px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint);
}
.wiz-group-label::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }

.wiz-tile {
  display: flex; flex-direction: column; gap: 8px;
  padding: 13px 14px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.wiz-tile:hover { border-color: #cdd3e1; }
.wiz-tile:has(input[type=checkbox]:checked) { border-color: var(--brand); box-shadow: var(--ring); }
.wiz-tile.is-there { background: var(--surface-2); }

.wiz-tile-head { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; }
.wiz-tile.is-there .wiz-tile-head { cursor: default; }
.wiz-tile-head input[type=checkbox] { margin: 3px 0 0; flex: none; }
.wiz-tile-head b { font-size: 13.5px; font-weight: 620; line-height: 1.32; }
.wiz-tile.is-there .wiz-tile-head b { color: var(--muted); }

.wiz-tile .acct { font-size: 11.5px; color: var(--faint); line-height: 1.45; }
.wiz-tile .price { display: flex; align-items: center; gap: 8px; }
.wiz-tile .price input { text-align: end; }
.wiz-tile .price .unit { font-size: 11px; color: var(--faint); flex: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.wiz-foot { display: flex; align-items: center; gap: 10px; margin-top: 18px; flex-wrap: wrap; }
.wiz-foot .spacer { flex: 1; }
.wiz-later { display: flex; align-items: center; gap: 10px; margin-top: 22px; flex-wrap: wrap; }


/* ═══════════════════════════ sign in ═══════════════════════════
   The first screen anybody sees, and the only one that was never styled:
   .login-wrap, .login-card, .login-head and .field appear in the view and
   appeared nowhere here, so it rendered as a full-width card glued to the
   top-left corner with a browser-default heading and no gap between a label
   and its field. */

.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--bg-deep);
}

.login-card { width: min(400px, 100%); }
.login-card .body { padding: 28px 26px 24px; }

.login-head { text-align: center; margin-bottom: 22px; }
.login-head .mark {
  width: 46px; height: 46px; margin: 0 auto 12px;
  border-radius: 13px;
  background: var(--brand);
  color: #fff;
  display: grid; place-items: center;
  font-size: 21px;
}
.login-head h1 { font-size: 22px; font-weight: 680; letter-spacing: -.02em; margin: 0 0 4px; }

.field { margin-bottom: 15px; }
.field .f { display: block; margin-bottom: 5px; }
.field input { width: 100%; }


/* The settings form's action bar: out of the way until something changes,
   then pinned to the bottom of the viewport so it is never a scroll away. */
.settings-save {
  position: sticky;
  bottom: 12px;
  margin-top: 16px;
  z-index: 10;
  box-shadow: var(--shadow-md);
}
.settings-save .body { padding: 14px 18px; }

/* A setting's key is a machine value, so .mono makes it read left to right —
   and `text-align: start` inside an LTR run then resolves to the left, putting
   the key at the opposite edge of the column from the name it belongs to. */
body.rtl .srow .mono { text-align: end; }


/* The empty state, one shape everywhere. It used to be written inline at each
   table with three different paddings, so the same row was 16px tall on one
   screen and 40px on the next. */
tr.is-empty td {
  padding: 22px 16px;
  text-align: center;
  color: var(--muted);
}
