/*
 * Asili design system — African Script's colours: black, green, a little pink.
 *
 * Black is the ground and the ink. Green is the single working accent: navigation,
 * primary actions, anything the eye should land on. Pink is the flourish and stays one —
 * the brand mark and the business date, and little else. Spend it more widely and it
 * stops meaning anything.
 *
 * Semantic colour (ok / warning / danger) is kept separate from the brand accent, so
 * "this room is clean" and "this is the primary button" never read as the same thing.
 *
 * One token layer, used by every screen. Colours are defined once on :root and
 * redefined for dark mode — never hardcoded in a component rule, so a screen cannot
 * end up readable in one theme and not the other.
 *
 * System fonts throughout: a front desk screen must paint instantly on a slow
 * connection, and a webfont round-trip is the wrong place to spend that budget.
 */

:root {
  /* Native controls — date pickers, dropdown lists, scrollbars — follow this. */
  color-scheme: light;

  --paper:       #F7F7F4;
  --surface:     #FFFFFF;
  --surface-2:   #EFEFEB;
  --surface-3:   #E4E5DF;
  --ink:         #0B0D0B;
  --ink-2:       #464A46;
  --ink-3:       #7A807B;
  --rule:        #DDDED8;
  --rule-soft:   #E9EAE5;

  --accent:      #0E7C36;
  --accent-ink:  #FFFFFF;
  --accent-soft: #DDF1E2;
  --pink:       #C1256E;
  --pink-soft:  #FBE2EF;

  /* SmartSchool's navigation colours. Edges and dots only, never text: text keeps
     --accent and --pink, which hold their contrast in both themes. */
  --nav-green:   #15E515;
  --nav-pink:    #FF1493;
  --nav-hover:   color-mix(in srgb, #15E515 10%, transparent);
  --nav-current: color-mix(in srgb, #FF1493 8%, transparent);

  --ok:          #17693F;
  --warn:        #9A6516;
  --danger:      #A32B27;
  --ok-soft:     #DCEEE3;
  --warn-soft:   #F6E9D0;
  --danger-soft: #F6DDDB;

  --radius:      6px;
  --radius-sm:   4px;

  /* The gap between stacked blocks on a page — a card after a card, an alert above a table.
     It was written inline a hundred and sixty times, as 18px below and 16px above, which
     nobody chose: it accumulated. Both values are kept exactly as they were so that moving
     them into here changed no screen, and they are now two numbers rather than a hundred and
     sixty (2026-10-20). Unify them when somebody decides which is right. */
  --gap-below:   18px;
  --gap-above:   16px;

  /* The height of anything you type in or press. One number, so a field, a dropdown and a
     button standing side by side are the same size — which is most of what "consistent"
     means on a screen. */
  --control-h:   38px;
  --shadow:      0 1px 2px rgba(11,13,11,.07), 0 8px 24px -18px rgba(11,13,11,.38);

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  --sidebar-w: 232px;
  --topbar-h:  56px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:       #080A08;
    --surface:     #111411;
    --surface-2:   #191D19;
    --surface-3:   #232823;
    --ink:         #ECEFEB;
    --ink-2:       #A4ACA5;
    --ink-3:       #737B74;
    --rule:        #262B26;
    --rule-soft:   #1C201C;

    --accent:      #35D960;
    --accent-ink:  #04140A;
    --accent-soft: #0E2C17;
    --pink:       #FF74B1;
    --pink-soft:  #331526;
    --nav-hover:   color-mix(in srgb, #15E515 12%, transparent);
    --nav-current: color-mix(in srgb, #FF1493 16%, transparent);
    color-scheme: dark;

    --ok:          #4ED97F;
    --warn:        #D6A44A;
    --danger:      #E4695F;
    --ok-soft:     #0F2B1A;
    --warn-soft:   #2C2412;
    --danger-soft: #321917;

    --shadow:      0 1px 2px rgba(0,0,0,.4), 0 8px 24px -18px rgba(0,0,0,.85);
  }
}

:root[data-theme="dark"] {
  --paper:       #080A08;
  --surface:     #111411;
  --surface-2:   #191D19;
  --surface-3:   #232823;
  --ink:         #ECEFEB;
  --ink-2:       #A4ACA5;
  --ink-3:       #737B74;
  --rule:        #262B26;
  --rule-soft:   #1C201C;
  --accent:      #35D960;
  --accent-ink:  #04140A;
  --accent-soft: #0E2C17;
  --pink:       #FF74B1;
  --pink-soft:  #331526;
  --nav-hover:   color-mix(in srgb, #15E515 12%, transparent);
  --nav-current: color-mix(in srgb, #FF1493 16%, transparent);
  color-scheme: dark;
  --ok:          #4ED97F;
  --warn:        #D6A44A;
  --danger:      #E4695F;
  --ok-soft:     #0F2B1A;
  --warn-soft:   #2C2412;
  --danger-soft: #321917;
  --shadow:      0 1px 2px rgba(0,0,0,.4), 0 8px 24px -18px rgba(0,0,0,.85);
}

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

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; line-height: 1.2; letter-spacing: -0.01em; font-weight: 650; }
h1 { font-size: 22px; }
h2 { font-size: 18px; }
h3 { font-size: 15px; }
p  { margin: 0 0 .9em; }
a  { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

.mono   { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.num    { font-variant-numeric: tabular-nums; }
.muted  { color: var(--ink-2); }
.subtle { color: var(--ink-3); }

.eyebrow {
  font-family: var(--mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
}

/* ---------- app shell ---------- */

.shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100%; }

.sidebar {
  background: var(--surface); border-right: 1px solid var(--rule);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh;
}

.brand {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 14px 18px; border-bottom: 1px solid var(--rule-soft);
}
.brand-logo { display: block; height: 40px; width: auto; max-width: 100%; object-fit: contain; }
.brand .sub { font-size: 10.5px; color: var(--ink-3); letter-spacing: .04em; }

.nav { padding: 10px 8px; overflow-y: auto; flex: 1; }
.nav-group { margin-bottom: 16px; }
.nav-group > .eyebrow { padding: 0 10px 6px; display: block; }

/* SmartSchool's colours: green where the pointer is, pink where the reader is. The bright tones
   mark edges and dots; text keeps the palette's own accent and pink, which hold their contrast
   on a white page as well as a black one. */
.nav-link, .nav-sublink {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 10px 7px 11px; border-left: 3px solid transparent; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--ink-2); font-size: 13.5px; font-weight: 500; text-decoration: none;
}
.nav-link:hover, .nav-sublink:hover {
  background: var(--nav-hover); border-left-color: var(--nav-green); color: var(--ink); text-decoration: none;
}
.nav-link.is-active, .nav-branch.is-active > .nav-link {
  background: var(--nav-current); border-left-color: var(--nav-pink); color: var(--ink); font-weight: 650;
}
summary.nav-link { cursor: pointer; list-style: none; user-select: none; }
summary.nav-link::-webkit-details-marker { display: none; }
summary.nav-link::after {
  content: ""; margin-left: auto; width: 6px; height: 6px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); opacity: .55; transition: transform .15s ease;
}
.nav-branch[open] > summary.nav-link::after { transform: rotate(45deg); }
.nav-sub { display: grid; gap: 1px; margin: 2px 0 6px 13px; padding-left: 6px; border-left: 1px solid var(--rule); }
.nav-sublink { font-size: 13px; padding: 5px 10px; }
.nav-sublink.is-active { background: var(--nav-current); border-left-color: var(--nav-pink); color: var(--pink); font-weight: 650; }
.nav-sublink.is-active::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--nav-pink); flex: none; }
.nav-toggle { display: none; }
@media (prefers-reduced-motion: reduce) { summary.nav-link::after { transition: none; } }

.sidebar-foot { padding: 12px 14px; border-top: 1px solid var(--rule-soft); font-size: 12px; color: var(--ink-3); }

/* ---------- topbar ---------- */

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

.topbar {
  height: var(--topbar-h); flex: none;
  display: flex; align-items: center; gap: 14px;
  padding: 0 22px; background: var(--surface);
  border-bottom: 1px solid var(--rule); position: sticky; top: 0; z-index: 20;
}

.property-switch { display: flex; align-items: center; gap: 8px; }
.property-switch select {
  font: inherit; font-weight: 600; color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--rule);
  border-radius: var(--radius-sm); padding: 5px 10px; max-width: 260px;
}

.business-date {
  display: flex; align-items: baseline; gap: 7px;
  padding: 4px 10px; background: var(--pink-soft);
  border-radius: var(--radius-sm); font-size: 12px; color: var(--ink);
}
.business-date .lbl { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
                      text-transform: uppercase; color: var(--pink); }
.business-date .val { font-family: var(--mono); font-weight: 600; }

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }

.who { text-align: right; line-height: 1.25; }
.who .name { font-weight: 600; font-size: 13px; }
.who .role { font-size: 11px; color: var(--ink-3); }

.avatar {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
}

/* ---------- content ---------- */

.content { padding: 26px 22px 60px; flex: 1; }
.page-head { margin-bottom: 22px; }
.page-head h1 { margin-bottom: 4px; }
.page-head p { color: var(--ink-2); margin: 0; }

.card {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.card-head { padding: 14px 18px; border-bottom: 1px solid var(--rule-soft);
             display: flex; align-items: center; gap: 12px; }
.card-body { padding: 18px; }

/*
 * Small panels side by side, instead of one to a row (fix list M59).
 *
 * A screen like a booking stacks two dozen cards, several holding one short field under a
 * heading — so the thing somebody came to do is four screens down, and most of the width is
 * empty. This lays those panels out in as many columns as the window will take, and collapses
 * to one on a phone without a media query.
 *
 * `align-items: start` matters: without it every panel in a row stretches to the tallest, and
 * a one-field panel beside a long explanation becomes a box of empty space.
 *
 * The column count is stated rather than `auto-fit`, which would give five narrow columns of
 * form fields on a wide desk screen — worse than the stack it replaces. Two on a laptop, three
 * on a large screen, one on a phone.
 *
 * It replaces `.pos-layout`, which did the same thing for three screens under a name borrowed
 * from the till, and hardcoded its gap instead of carrying the rhythm token.
 *
 * Nothing is hidden by it. The destructive actions stay full width below, where they are apart
 * from the ordinary ones rather than one more box in a grid.
 */
/*
 * A message exactly as it was sent (fix list M60 P1).
 *
 * Wrapped rather than scrolled sideways, because an email body is read, and pre-formatted so the
 * line breaks somebody wrote are the ones shown — a rent demand's figures sit on their own lines
 * and reflowing them is how an amount ends up beside the wrong label.
 */
.plain { margin: 0; padding: 14px; background: var(--surface-2); border: 1px solid var(--rule-soft);
         border-radius: var(--radius-sm); font: 13px/1.6 var(--mono); color: var(--ink);
         white-space: pre-wrap; overflow-wrap: anywhere; }

/*
 * A fieldset used as a panel (fix list M64).
 *
 * The browser draws its own border and legend chrome, which fights the card's and leaves the
 * legend floating in the border. Stripped back so `.card` is the only thing drawing the box, and
 * the legend sits where a card heading sits.
 */
fieldset.card { padding: 0; min-width: 0; }
fieldset.card > legend { float: left; width: 100%; padding: 13px 17px 0; }
fieldset.card > .card-body { clear: both; display: grid; gap: 9px; }

.card-columns { display: grid; gap: var(--gap-above); align-items: start;
                grid-template-columns: 1fr; }
@media (min-width: 1000px) { .card-columns { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1600px) { .card-columns { grid-template-columns: 1fr 1fr 1fr; } }

/* A panel that must keep the full width inside the grid — a table, or a run of dates. */
.card-columns .card-wide { grid-column: 1 / -1; }

.grid { display: grid; gap: 14px; }
.grid-tiles { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

.tile { background: var(--surface); border: 1px solid var(--rule);
        border-radius: var(--radius); padding: 16px 18px; }
.tile .k { display: block; margin-bottom: 8px; }
.tile .v { font-size: 24px; font-weight: 700; letter-spacing: -.02em;
           font-variant-numeric: tabular-nums; line-height: 1.1; }
.tile .n { font-size: 12px; color: var(--ink-3); margin-top: 4px; }

/* ---------- forms ---------- */

label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }

input[type=text], input[type=email], input[type=password], input[type=number], input[type=search],
input[type=tel], input[type=url], input[type=date], input[type=time], input[type=month],
input[type=week], input[type=datetime-local], input:not([type]), select, textarea {
  width: 100%; font: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius-sm); padding: 8px 11px; min-height: var(--control-h);
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft); }
input[type=color] { width: 44px; height: 36px; padding: 2px; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius-sm); }
input[type=file] {
  width: 100%; font: inherit; font-size: 13px; color: var(--ink-2);
  background: var(--surface); border: 1px dashed var(--rule); border-radius: var(--radius-sm); padding: 6px;
}
input[type=file]::file-selector-button {
  font: inherit; font-weight: 600; margin-right: 10px; padding: 6px 12px; cursor: pointer;
  color: var(--ink); background: var(--surface-2); border: 1px solid var(--rule); border-radius: var(--radius-sm);
}
input[type=checkbox], input[type=radio], input[type=range], progress { accent-color: var(--accent); }
select option, select optgroup { background: var(--surface); color: var(--ink); }
::placeholder { color: var(--ink-3); opacity: 1; }
textarea { resize: vertical; min-height: 64px; }
/* A browser's autofill paints its own pale background; keep the field the theme's. */
input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus,
textarea:-webkit-autofill, select:-webkit-autofill {
  -webkit-text-fill-color: var(--ink); caret-color: var(--ink);
  box-shadow: 0 0 0 1000px var(--surface) inset; transition: background-color 9999s ease-out 0s;
}
input:disabled, select:disabled, textarea:disabled, input[readonly] { background: var(--surface-2); color: var(--ink-3); }

.field { margin-bottom: 15px; }
.field .hint { font-size: 11.5px; color: var(--ink-3); margin-top: 4px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font: inherit; font-weight: 600; cursor: pointer;
  padding: 9px 16px; border-radius: var(--radius-sm); min-height: var(--control-h);
  border: 1px solid transparent; background: var(--accent); color: var(--accent-ink);
  /* A label never wraps. "Top up" broken over two lines made the button twice the height of
     the field beside it, which is how one row ended up with three different sizes in it. */
  white-space: nowrap;
}
.btn:hover { filter: brightness(1.08); text-decoration: none; }
.btn:active { filter: brightness(.95); }
.btn-block { width: 100%; }
.btn-ghost { background: transparent; color: var(--ink-2); border-color: var(--rule); }
.btn-ghost:hover { background: var(--surface-2); color: var(--ink); filter: none; }
.btn-link { background: none; border: none; color: var(--accent); padding: 0; font-weight: 500; }

/* ---------- flashes + alerts ---------- */

.flashes { display: grid; gap: 8px; margin-bottom: 18px; }
.alert {
  padding: 11px 14px; border-radius: var(--radius-sm);
  border-left: 3px solid var(--ink-3); background: var(--surface-2); font-size: 13.5px;
}
.alert-success { border-left-color: var(--ok);     background: var(--ok-soft); }
.alert-warning { border-left-color: var(--warn);   background: var(--warn-soft); }
.alert-error   { border-left-color: var(--danger); background: var(--danger-soft); }

/* ---------- login ---------- */

.auth {
  min-height: 100vh; display: grid; place-items: center; padding: 24px;
  background:
    radial-gradient(900px 420px at 50% -14%, var(--accent-soft), transparent 60%),
    radial-gradient(620px 320px at 88% 106%, var(--pink-soft), transparent 64%),
    var(--paper);
}
.auth-card { width: 100%; max-width: 384px; }
.auth-brand { text-align: center; margin-bottom: 26px; }
.auth-logo { display: block; margin: 0 auto; width: auto; height: auto; max-width: 260px; max-height: 110px; object-fit: contain; }
.auth-brand .sw { display: block; margin-top: 5px; font-size: 12.5px;
                  font-style: italic; color: var(--ink-3); }
.auth-foot { margin-top: 18px; text-align: center; font-size: 12px; color: var(--ink-3); }

/* ---------- responsive ---------- */

@media (max-width: 860px) {
  .shell { grid-template-columns: 1fr; }
  .sidebar { position: sticky; top: 0; z-index: 30; height: auto; border-right: 0; border-bottom: 1px solid var(--rule); }
  .brand { flex-direction: row; align-items: center; gap: 12px; padding: 10px 14px; }
  .brand .sub { display: none; }
  .brand-logo { height: 32px; }
  .nav-toggle {
    display: inline-flex; align-items: center; gap: 9px; margin-left: auto; cursor: pointer;
    font: inherit; font-size: 13px; font-weight: 600; color: var(--ink);
    background: var(--surface-2); border: 1px solid var(--rule); border-radius: var(--radius-sm); padding: 7px 12px;
  }
  .nav-toggle-bars { width: 15px; height: 2px; background: currentColor; box-shadow: 0 -5px currentColor, 0 5px currentColor; }
  .sidebar.is-open .nav-toggle { border-color: var(--nav-pink); }
  .nav { display: none; max-height: calc(100vh - 60px); padding: 6px 10px 14px; border-top: 1px solid var(--rule-soft); }
  .sidebar.is-open .nav { display: block; }
  .sidebar-foot { display: none; }
  .topbar { flex-wrap: wrap; height: auto; padding: 10px 14px; gap: 10px; }
  .content { padding: 18px 14px 48px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* Visible to screen readers only. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Language switcher. */
.locale-switch { display: inline-flex; gap: 10px; align-items: center; font-size: 12px; }
.locale-switch a { color: var(--ink-3); }
.locale-switch a:hover { color: var(--accent); }
.locale-switch [aria-current="true"] { color: var(--ink); font-weight: 600; }

/* ---------- forms (Asili form theme) ---------- */

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

.field-invalid input, .field-invalid select, .field-invalid textarea { border-color: var(--danger); }
.field-errors { list-style: none; margin: 5px 0 0; padding: 0; color: var(--danger); font-size: 12px; }

.field-check { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }

/* Stacking. Use these rather than an inline margin: a page's rhythm is one decision, and a
   decision written into a hundred and sixty templates is not one anybody can revisit. */
.gap-below { margin-bottom: var(--gap-below); }
.gap-above { margin-top: var(--gap-above); }
/* Only the top, because that is what the inline it replaced said. */
.gap-none  { margin-top: 0; }

/* A label only a screen reader reads. Where a box's own placeholder already says what it is to
   anybody looking at it, but a field with no label at all is a field a screen reader cannot
   announce. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
label.check { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; color: var(--ink); margin: 0; }
label.check input { width: auto; }

/* A number and the country it is dialled in, side by side: under each other they read as
   two questions and only the second gets answered. The country box is given room for a
   name plus its code, and stops growing so the number keeps the rest of the line. */
.phone-field { display: flex; gap: 8px; align-items: center; }
.phone-field select { flex: 0 1 14em; min-width: 0; }
.phone-field input { flex: 1 1 auto; min-width: 0; }

.choice-grid { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px; margin: 0;
  padding: 5px 11px; border: 1px solid var(--rule); border-radius: 20px;
  background: var(--surface); font-size: 12.5px; font-weight: 500;
  color: var(--ink-2); cursor: pointer;
}
.chip:hover { border-color: var(--accent); color: var(--ink); }
.chip input { width: auto; margin: 0; }
.chip:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
/* A chip chosen by script rather than by a checkbox — the report finder's sections. */
.chip.is-on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* A refusal said at the top of a form, rather than beside one field: the screen could not do
   what was asked and the reason belongs where the eye lands first. */
.notice {
  padding: 11px 14px; border: 1px solid var(--rule); border-left-width: 3px;
  border-radius: var(--radius); background: var(--surface); color: var(--ink-2);
  font-size: 13.5px; margin-bottom: 16px;
}
.notice.is-danger { border-left-color: var(--danger); background: var(--danger-soft); color: var(--ink); }
.notice.is-ok     { border-left-color: var(--ok);     background: var(--ok-soft);     color: var(--ink); }
.notice.is-warn   { border-left-color: var(--warn);   background: var(--warn-soft);   color: var(--ink); }

/* An African Script support visit, across the top of every screen (fix list M71). Warn rather
   than the brand accent: it is a state to notice and leave, not something to press. Full width
   above the topbar, because an operator who loses track of which hotel they are in is the whole
   risk the feature carries. */
.support-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 18px; background: var(--warn-soft); color: var(--ink);
  border-bottom: 1px solid var(--warn); font-size: 13.5px;
}
.support-banner-mark { display: inline-flex; color: var(--warn); }
.support-banner-text { flex: 1; min-width: 20ch; }
.support-banner-until { margin-left: 6px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* A client's support log: the hotel reads this, so an open visit has to stand out in it. */
.support-open { font-weight: 600; color: var(--warn); }

/* A row that belongs to the row above it rather than standing on its own — the hotels under a
   client on the platform screen. No rule between the two, and set back so the eye reads it as
   a continuation. */
.subrow > td { border-top: 0; padding-top: 0; background: var(--surface); }
.subrow .eyebrow { display: block; margin-bottom: 6px; }

/* A small standing label beside a name — "returning", "recipe set". Semantic colour, never the
   brand accent, so "this is good news" never reads like "press this". */
.pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border: 1px solid var(--rule); border-radius: 20px;
  background: var(--surface-2); color: var(--ink-3);
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.pill.is-ok     { border-color: var(--ok);     background: var(--ok-soft);     color: var(--ok); }
.pill.is-danger { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }

/* An action that destroys something. It has to look unlike the one beside it, or the two are
   told apart only by reading, which is not what happens at a counter with a queue. */
.btn-danger { background: var(--danger); color: var(--accent-ink); border-color: var(--danger); }
.btn-danger:hover { filter: brightness(1.06); }

/* One upload in the branding grid: the form stacks its own label, preview and button. */
.brand-upload { display: grid; gap: 8px; }

/* The code on an error page, for somebody reading it out over a telephone. */
.error-reference { font-family: var(--mono); font-size: 12px; }

/* The right-hand half of the till — the products, beside the bill. */
.pos-menu { display: flex; flex-direction: column; min-height: 0; }

/* What a line on the bill is: the dish, and anything said about it underneath. */
.pos-what { display: block; min-width: 0; }

/* The two print buttons, side by side rather than stacked full width: neither is the thing the
   waiter came to this screen to do. */
/* A dropdown you can type into. The real <select> is still there and still what the form
   sends; this is the box in front of it. */
.combo { position: relative; }
.combo-native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.combo-input { width: 100%; }
.combo-list {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 4px);
  margin: 0; padding: 4px; list-style: none; max-height: 260px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.combo-option { padding: 7px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: 13.5px; }
.combo-option:hover, .combo-option.is-on { background: var(--accent-soft); color: var(--accent); }
.combo-none { padding: 7px 10px; color: var(--ink-3); font-size: 13px; }

/* Finding one row in a list that has grown. Sits above the table it filters. */
.table-find { max-width: 360px; }

.pos-prints { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }

/* The moment the money arrived. Said once, plainly, above the things you do next. */
.pos-done {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px; border: 1px solid var(--ok); border-radius: var(--radius);
  background: var(--ok-soft); color: var(--ok); margin-bottom: 4px;
}
.pos-done strong { font-size: 15px; }
.pos-done span { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }

/* Sending the slip on: one row, the address and the button at the same height as everything
   else on the screen. */
.pos-send { display: flex; gap: 8px; align-items: center; }
.pos-send input { flex: 1 1 auto; min-width: 0; }

/* The slip as it will come out, beside the till rather than imagined. */
.pos-preview iframe { width: 100%; height: 60vh; border: 1px solid var(--rule); border-radius: var(--radius-sm); background: var(--paper); }

/* The actions sheet: everything a till might do, behind one button, so the column says one
   thing. A <dialog> rather than a hand-built menu — the browser gives the focus trap, Escape
   and the backdrop for nothing, and those are what hand-built menus get wrong. */
.sheet { border: none; padding: 0; background: transparent; max-width: min(560px, 94vw); width: 100%; }
.sheet::backdrop { background: rgba(0, 0, 0, .55); }
.sheet-card { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius);
              box-shadow: var(--shadow); overflow: hidden; }
.sheet-head { display: flex; align-items: center; justify-content: space-between;
              padding: 14px 16px; border-bottom: 1px solid var(--rule); }
.sheet-head h2 { margin: 0; font-size: 15px; }
.sheet-body { padding: 16px; display: grid; gap: 12px; }
.sheet-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.sheet-item { display: flex; align-items: center; justify-content: center; gap: 8px;
              padding: 18px 12px; border: 1px solid var(--rule); border-radius: var(--radius);
              background: var(--surface-2); color: var(--ink); font: inherit; font-size: 13.5px;
              font-weight: 500; text-align: center; cursor: pointer; text-decoration: none; }
.sheet-item:hover { border-color: var(--accent); color: var(--accent); }
.sheet-item.is-danger { color: var(--danger); }
.sheet-item.is-danger:hover { border-color: var(--danger); color: var(--danger); }

.form-actions { display: flex; gap: 10px; align-items: center; margin-top: 22px;
                padding-top: 18px; border-top: 1px solid var(--rule-soft); }

/* ---------- data tables ---------- */

.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; min-width: 640px; }
table.data th {
  text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); font-weight: 600; white-space: nowrap;
}
table.data td { padding: 11px 14px; border-bottom: 1px solid var(--rule-soft); vertical-align: middle; }
table.data tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--surface-2); }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }

.badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 20px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.badge-ok      { background: var(--ok-soft);     color: var(--ok); }
.badge-warn    { background: var(--warn-soft);   color: var(--warn); }
.badge-danger  { background: var(--danger-soft); color: var(--danger); }
.badge-accent  { background: var(--accent-soft); color: var(--accent); }
.badge-muted   { background: var(--surface-3);   color: var(--ink-3); }
.badge-pink    { background: var(--pink-soft);   color: var(--pink); }

/* ---- icons ---------------------------------------------------------------
   Drawn from the sheet in partials/_icons.html.twig, one definition per page.
   Everything here is sized in the text it sits beside and coloured by it, so
   neither theme needs a second set of rules. */

/* The sheet is definitions, not a picture: it must occupy nothing. Collapsed
   rather than display:none, which is the form that has never had trouble being
   referenced by <use>. */
.icon-sheet { position: absolute; width: 0; height: 0; overflow: hidden; }

.icon {
  width: 16px; height: 16px; flex: none;
  vertical-align: -0.15em;
  /* The stroke belongs here, not on the sheet. A <use> copy inherits from where it is used,
     never from where it was defined, so presentation attributes on the sheet's own <svg> do
     not reach it — and every icon renders with the default black fill and no stroke, which
     turns the ones drawn from rectangles into solid blocks. */
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Green in the sidebar, the same green that marks where you are. Quiet until the page is the
   one you are on. */
.nav-link > .icon { width: 17px; height: 17px; color: var(--nav-green); opacity: .8; }
.nav-link:hover > .icon,
.nav-link.is-active > .icon,
.nav-branch.is-active > summary.nav-link > .icon { opacity: 1; }

.btn > .icon { width: 15px; height: 15px; }
.badge > .icon { width: 12px; height: 12px; }

/* The one place an icon leads rather than follows: a screen with nothing on it. */
.empty > .icon { width: 30px; height: 30px; opacity: .4; margin-bottom: 8px; }

/* The bell, beside whoever is signed in (fix list M54).
 *
 * The count is the only thing on it that shouts, and it shouts in the semantic warning colour
 * rather than the brand accent: "something is waiting for you" is not "this is the primary
 * action" (AGENTS §6b). With nothing waiting there is no count and the bell is just an icon. */
.bell { position: relative; display: inline-flex; align-items: center; color: var(--ink-2); }
.bell:hover { color: var(--accent); }
.bell-count {
    position: absolute; top: -6px; right: -8px;
    min-width: 16px; padding: 0 4px;
    border-radius: 8px;
    background: var(--warn); color: var(--paper);
    font-size: 10px; line-height: 16px; text-align: center; font-variant-numeric: tabular-nums;
}
@media print { .bell { display: none; } }

/* A printout is read on paper, where a grey stroke is noise. */
@media print { .icon { display: none; } }

/* An app screen printed is a document, not a screenshot.
 *
 * A payslip is handed to somebody, and printing it used to carry the sidebar, the topbar and the
 * buttons onto the paper with it. The chrome goes, the content takes the whole page, and the
 * ground goes white — a dark theme printed is a solid black page and an empty cartridge.
 *
 * Nothing here is new styling: it is the same screen with everything that is not the record
 * taken off it. */
@media print {
    .sidebar,
    .topbar,
    .head-actions,
    .flashes { display: none; }

    .shell,
    .main,
    .content { display: block; padding: 0; margin: 0; max-width: none; }

    .card { border: 0; box-shadow: none; break-inside: avoid; }

    body { background: #fff; color: #000; }
}

/* What has gone wrong and is waiting for somebody — see NeedsAttention. Deliberately plain:
   it is read by being empty, and shouting at a hotel every morning trains everybody to ignore it. */
.attention { border-left: 3px solid var(--warn, #b45309); margin-bottom: 18px; }
.attention .card-head h2 { display: flex; align-items: center; gap: 8px; font-size: 15px; }
.attention-list { list-style: none; margin: 0; padding: 10px 18px 14px; display: grid; gap: 8px; }
.attention-list a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--rule-soft); padding-bottom: 6px; display: block; }
.attention-list li:last-child a { border-bottom: 0; padding-bottom: 0; }
.attention-list a:hover { color: var(--accent, inherit); }

.empty { padding: 40px 20px; text-align: center; color: var(--ink-3); }
.empty h3 { color: var(--ink); margin-bottom: 6px; }
.empty p { max-width: 46ch; margin: 0 auto 16px; }

.head-actions { margin-left: auto; display: flex; gap: 8px; }
.page-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.page-head > div:first-child { flex: 1 1 auto; }

.status-strip { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.status-strip .s {
  display: flex; align-items: baseline; gap: 7px; padding: 7px 12px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius-sm);
}
.status-strip .s b { font-size: 15px; font-variant-numeric: tabular-nums; }
.status-strip .s span { font-size: 12px; color: var(--ink-3); }

.inline-form { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; vertical-align: top; }
/* Inside one, a field is as wide as it needs to be rather than the whole row. */
.inline-form input, .inline-form select { width: auto; }
.status-select { font: inherit; font-size: 12px; padding: 3px 7px; width: auto; }

/* "or" divider on the login card. */
.or-divider { display: flex; align-items: center; gap: 12px; margin: 18px 0 14px;
              color: var(--ink-3); font-size: 11.5px; text-transform: uppercase;
              letter-spacing: .1em; font-family: var(--mono); }
.or-divider::before, .or-divider::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

/* Price grid cells — narrow, right-aligned, tabular. */
.grid-cell {
  width: 108px; text-align: right; padding: 6px 9px; font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.grid-cell:disabled { background: var(--surface-2); color: var(--ink-3); }

/* ---------- cancellation ladder ---------- */

/* Each rung is one row: notice, charge type, amount, and a way to drop it. The amount
   column keeps its width when hidden so the rows below do not jump as types change. */
.rungs { display: grid; gap: 10px; }
.rung {
  display: grid; gap: 12px; align-items: start;
  grid-template-columns: minmax(90px, 130px) minmax(140px, 1fr) minmax(120px, 180px) auto;
  padding: 12px; border: 1px solid var(--rule-soft);
  border-radius: var(--radius-sm); background: var(--surface-2);
}
.rung-field label { font-size: 11.5px; }
.rung-field .hint { font-size: 11.5px; color: var(--ink-3); margin-top: 4px; }
.rung > button { align-self: center; margin-top: 10px; }

@media (max-width: 640px) {
  .rung { grid-template-columns: 1fr 1fr; }
  .rung > button { grid-column: 2; justify-self: end; }
}

.btn-sm { padding: 5px 10px; font-size: 12.5px; }
.card-head > .btn-sm { margin-left: auto; }

/* ---------- detail lists and filter rows ---------- */

/* Label-above-value pairs. Used wherever a record is read rather than edited. */
.detail-grid { display: grid; gap: 14px 22px; margin: 0 0 14px;
               grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.detail-grid dt { font-size: 11.5px; font-weight: 600; color: var(--ink-3);
                  text-transform: uppercase; letter-spacing: .05em; margin-bottom: 3px; }
.detail-grid dd { margin: 0; font-size: 14px; }

.filter-row { display: flex; flex-wrap: wrap; gap: 0 14px; align-items: flex-end; }
.filter-row .field { margin-bottom: 0; }

.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pager-links { display: flex; gap: 8px; }

/* A line the register has since corrected. Struck rather than hidden — the book keeps
   every line, and an inspector is meant to see the correction. */
tr.superseded td { color: var(--ink-3); }
tr.superseded td:nth-child(2) strong { text-decoration: line-through; }

/* A wrapping row of small actions — agent shortcuts, filter chips. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* Forms that sit inside a table cell — the waitlist's book/offer/decline actions. */
.inline-form { display: inline-flex; align-items: center; gap: 6px; }
.inline-form select { width: auto; padding: 5px 8px; font-size: 12.5px; }
.row-actions { display: flex; gap: 12px; margin-top: 6px; font-size: 12.5px; }

/* ---------- booking chart ---------- */

/* One grid shared by every row: a label column, then one equal column per night. The
   nights are a custom property so the template sets it once and nothing hard-codes a
   width. min-width keeps a three-week view readable rather than squeezing columns to
   nothing; the wrapper scrolls instead. */
.chart-scroll { overflow-x: auto; }
.chart { --chart-label: 108px; --chart-col: 40px; min-width: 100%; }

.chart-row {
  display: grid;
  grid-template-columns: var(--chart-label) repeat(var(--chart-nights), minmax(var(--chart-col), 1fr));
  position: relative;
}

.chart-label {
  padding: 6px 10px; font-size: 12.5px; line-height: 1.25;
  border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule-soft);
  background: var(--surface); position: sticky; left: 0; z-index: 2;
  display: flex; align-items: center; gap: 6px;
}
.chart-label .subtle { font-size: 11px; }

.chart-cell {
  border-right: 1px solid var(--rule-soft); border-bottom: 1px solid var(--rule-soft);
  min-height: 30px; font-variant-numeric: tabular-nums;
}

.chart-head .chart-cell, .chart-head .chart-label { border-bottom: 1px solid var(--rule); }
.chart-date {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 5px 2px; font-size: 11px; line-height: 1.15;
}
.chart-date .dow { color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; font-size: 9.5px; }
.chart-date .dom { font-weight: 700; font-size: 13px; }
.chart-date .mon { color: var(--ink-3); font-size: 9.5px; }
.chart-date.is-weekend { background: var(--surface-2); }
/* The property's business date, not the browser's — marked in the brand's pink so it
   reads as "you are here" rather than as a warning. */
.chart-date.is-today { box-shadow: inset 0 -3px 0 var(--pink); }

/* A labelled break between the counts and the rooms. The two halves share one grid so the
   columns line up, so the break is a row of its own rather than a margin — which would take
   the label column out of step with the nights. */
.chart-section {
  position: sticky; left: 0; width: min-content; white-space: nowrap;
  display: flex; align-items: baseline; gap: 8px; padding: 12px 10px 6px;
}
.chart-section-title { font-size: 12px; font-weight: 700; letter-spacing: .02em; color: var(--ink); }
.chart-section-note { font-size: 11px; color: var(--ink-3); }
.chart-gap { height: 12px; border-bottom: 1px solid var(--rule); }

.chart-strip .chart-label { background: var(--surface-2); }
/* Read, not pressed: the counts are what is left, and the rooms below are where it is sold. */
.chart-strip .chart-cell { cursor: default; }
.chart-count {
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600; color: var(--ink-2); background: var(--surface-2);
}
.chart-count.is-full { background: var(--warn-soft); color: var(--warn); }
.chart-count.is-oversold { background: var(--danger-soft); color: var(--danger); }

.chart-room .chart-night { cursor: crosshair; }
.chart-room .chart-night.is-selected { background: var(--accent-soft); }
.chart-room.is-drop-target .chart-night { background: var(--accent-soft); }

/* Bars sit in the same grid as the night cells, one row up in the stacking order. */
.chart-bar {
  grid-row: 1; align-self: center; margin: 3px 2px; z-index: 1;
  display: flex; align-items: center; padding: 0 7px; min-height: 24px;
  border-radius: var(--radius-sm); font-size: 11.5px; font-weight: 600;
  color: var(--accent-ink); background: var(--accent);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  cursor: grab; touch-action: none; user-select: none;
}
.chart-bar:hover { text-decoration: none; filter: brightness(1.06); }
.chart-bar.is-dragging { opacity: .55; cursor: grabbing; }
/* A stay running past the window's edge is cut square there, so it reads as continuing
   rather than as ending on the last column. */
.chart-bar.clipped-start { border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: 0; }
.chart-bar.clipped-end { border-top-right-radius: 0; border-bottom-right-radius: 0; margin-right: 0; }
.chart-bar .bar-text { overflow: hidden; text-overflow: ellipsis; }

.chart-bar.state-option     { background: var(--warn);   color: var(--accent-ink); }
.chart-bar.state-confirmed  { background: var(--accent); color: var(--accent-ink); }
.chart-bar.state-in_house   { background: var(--pink);   color: var(--accent-ink); }
.chart-bar.state-checked_out{ background: var(--surface-3); color: var(--ink-2); }

.chart-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; font-size: 12.5px; }
.legend-item { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-2); }
.legend-item .swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.swatch.state-option     { background: var(--warn); }
.swatch.state-confirmed  { background: var(--accent); }
.swatch.state-in_house   { background: var(--pink); }
.swatch.state-checked_out{ background: var(--surface-3); }
.legend-hint { margin-left: auto; color: var(--ink-3); }
.legend-hint.is-error { color: var(--danger); }

/* A credit on a folio — a payment, a rebate, a reversal — reads as money coming back. */
td.is-credit { color: var(--ok); }
tr.is-reversal td { background: var(--surface-2); }

/* A till that does not balance. Shouted about wherever it appears — over is as much a
   problem as short, so both get the same treatment. */
.is-variance { color: var(--danger); }

/* A room's checklist, folded away on the board.
   Collapsed by default because a floor of forty rooms with eight lines each is three
   hundred lines of text, and a board nobody can scan is a board nobody reads. The dot on
   the summary is the only thing that has to be visible from across the room: it means a
   required line is still outstanding. */
.checklist { margin-top: 6px; }
.checklist > summary { cursor: pointer; font-size: 12px; color: var(--ink-3); }
.checklist > summary:hover { color: var(--ink-2); }
.checklist[open] > summary { margin-bottom: 6px; }

.check-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 12.5px; }
.check-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* The tick is the button. A checkbox plus a save is a form filled in at the end from
   memory by somebody holding a cloth in the other hand. */
.check-list .btn-link { text-align: left; font-size: 12.5px; }

/* The till. Two columns on a desk, stacked on the phone a waiter actually carries —
   and the bill goes first when stacked, because that is what a guest asks about. */
/* ---- the till ------------------------------------------------------------------------
   Two things side by side: what has been ordered, and what can be. The bill is the narrow
   column because it is read; the menu takes the rest because it is worked. On a phone the
   bill goes first — a waiter checks what is on the ticket before adding to it. */
.pos { display: grid; gap: 18px; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 1000px) { .pos { grid-template-columns: minmax(300px, 380px) 1fr; } }
@media (min-width: 1000px) { .pos-bill { position: sticky; top: 16px; } }

.pos-lines { list-style: none; margin: 0; padding: 0; }
.pos-line { display: grid; grid-template-columns: 2.2em 1fr auto auto; gap: 8px; align-items: start;
            padding: 8px 14px; border-bottom: 1px solid var(--rule-soft); font-size: 14px; }
.pos-line small { display: block; font-size: 11.5px; }
.pos-qty { color: var(--ink-2); }
.pos-money { font-variant-numeric: tabular-nums; }
.pos-line.is-void { opacity: .65; }

/* The ✕ opens its own reason box: a line taken off a bill says why, and the box is not
   worth the width until somebody wants it. */
.pos-line-void summary { cursor: pointer; color: var(--ink-3); list-style: none; padding: 0 3px; }
.pos-line-void summary::-webkit-details-marker { display: none; }
.pos-line-void[open] { grid-column: 1 / -1; }
.pos-line-void form { display: flex; gap: 6px; margin-top: 6px; }

.pos-totals { padding: 10px 14px; border-top: 1px solid var(--rule); font-size: 13.5px; }
.pos-totals > div { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; }
.pos-totals small { display: block; font-size: 11.5px; }
/* The figure the guest is told. Everything else on this panel is working out. */
.pos-total { font-size: 19px; font-weight: 700; padding: 8px 0 !important;
             border-top: 1px solid var(--rule); margin-top: 6px; }

.pos-actions { display: flex; flex-direction: column; gap: 10px; }
.btn-wide { width: 100%; justify-content: center; }
.pos-panel > summary { cursor: pointer; font-weight: 600; font-size: 13.5px; padding: 8px 0;
                       border-top: 1px solid var(--rule); }
.pos-panel[open] > summary { margin-bottom: 8px; }
.pos-panel form + form { margin-top: 12px; }

.pos-filters { display: flex; flex-direction: column; gap: 10px; }
.pos-search { width: 100%; }
.pos-filters .pill { cursor: pointer; border: 1px solid var(--rule); background: var(--surface-2); }
.pos-filters .pill.is-on { border-color: var(--accent); color: var(--accent); }

/* Cards, not rows: one tap is the gesture a waiter makes forty times a service, and a
   target the size of a thumb is the difference between that and forty misses. */
.pos-grid { display: grid; gap: 10px; padding: 0 14px 14px;
            grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.pos-card { margin: 0; }
.pos-card button { width: 100%; min-height: 76px; display: flex; flex-direction: column;
                   justify-content: space-between; gap: 6px; text-align: left; cursor: pointer;
                   padding: 10px 11px; border: 1px solid var(--rule); border-radius: 10px;
                   background: var(--surface-2); color: var(--ink); font: inherit; }
.pos-card button:hover { border-color: var(--accent); }
.pos-card button:active { transform: translateY(1px); }
.pos-card-name { font-size: 13.5px; line-height: 1.25; }
.pos-card-price { font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.pos-none { padding: 0 14px 14px; }

/* A voided line stays on the ticket, struck through: a guest reading the bill can see
   what came off, which is the difference between a correction and a disappearance. */
.struck { text-decoration: line-through; }

/* A whole tile that is a link. */
.tile-link { display: block; text-decoration: none; color: inherit; }
.tile-link:hover { border-color: var(--accent); }

/* ---- the public booking page ------------------------------------------------------
   Deliberately not the admin shell: no sidebar, no chrome that hints at what is behind
   the login. A stranger should see a hotel's booking page, not a corner of somebody's
   back office. The property's own colour arrives as --accent from the template. */
.public-page { background: var(--surface-2); }
.public-inner { max-width: 720px; margin: 0 auto; padding: 0 20px; }
.public-head { background: var(--surface); border-bottom: 1px solid var(--rule); padding: 18px 0; margin-bottom: 28px; }
.public-brand { font-size: 18px; font-weight: 700; text-decoration: none; color: var(--ink); }
.public-logo { display: block; width: auto; height: auto; max-height: 52px; max-width: 240px; object-fit: contain; }

/* ---------- branding ---------- */

.brand-uploads { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 16px; }
.brand-preview {
  display: grid; place-items: center; min-height: 104px; margin-bottom: 10px; padding: 14px;
  background: #FFFFFF; border: 1px solid var(--rule); border-radius: var(--radius);
}
.brand-preview img { max-width: 100%; max-height: 84px; object-fit: contain; }
.brand-preview-favicon img { width: 64px; height: 64px; }
.brand-actions { margin-top: 8px; }
.brand-remove { margin-top: 8px; }
.brand-section { margin-top: 28px; }
.brand-section > h2 { margin: 0 0 2px; font-size: 16px; }
.brand-section > p { margin: 0 0 12px; }

/* A logo drawn for white paper — African Script's black Africa among them — disappears on a dark page. */
@media (prefers-color-scheme: dark) {
  .brand-logo, .auth-logo, .public-logo { background: #FFFFFF; padding: 5px 9px; border-radius: var(--radius); }
}
.public-intro { color: var(--ink-2); max-width: 60ch; }
.public-search { background: var(--surface); border: 1px solid var(--rule); border-radius: 10px; padding: 20px; }

.public-options { display: grid; gap: 14px; }
.public-option { background: var(--surface); border: 1px solid var(--rule); border-radius: 10px;
                 padding: 18px; display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.public-option-body { flex: 1 1 260px; }
.public-option-body h2 { margin: 0 0 4px; font-size: 16px; }
.public-option-price { text-align: right; margin-left: auto; }
.public-total { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }

/* Shown only when stock is genuinely short. "3 left" on every row is the oldest trick on
   a booking site, and guests recognise it. */
.public-scarce { color: var(--warn); font-size: 12.5px; margin: 6px 0 0; }

.public-summary { background: var(--surface); border: 1px solid var(--rule); border-radius: 10px;
                  padding: 18px; display: flex; justify-content: space-between; gap: 18px;
                  align-items: center; flex-wrap: wrap; margin-bottom: 18px; }
.public-reference { font-size: 20px; font-family: var(--mono, monospace); }
.public-empty { background: var(--surface); border: 1px solid var(--rule); border-radius: 10px;
                padding: 32px; text-align: center; }
.public-foot { display: flex; gap: 14px; justify-content: space-between;
               padding-top: 28px; padding-bottom: 28px; font-size: 12.5px; }

/* The deposit on the booked page — set apart, because it is the one thing still to do. */
.public-deposit { margin: 18px 0; padding: 14px 16px; border: 1px solid var(--rule-soft); border-radius: 8px; }
.public-pay { display: grid; gap: 8px; max-width: 360px; margin-top: 10px; }
.public-pay input[type="tel"] { font-size: 1.05rem; }

/* ---------- error pages ---------- */

.error-page {
  min-height: 100vh; display: grid; place-content: center; gap: 14px; padding: 24px; text-align: center;
  background: radial-gradient(900px 420px at 50% -14%, var(--accent-soft), transparent 60%), var(--paper);
}
.error-card {
  display: grid; justify-items: center; gap: 12px; max-width: 460px; margin: 0 auto; padding: 32px 28px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 10px; box-shadow: var(--shadow);
}
.error-card h1 { font-size: 24px; text-wrap: balance; }
.error-card p { margin: 0; max-width: 42ch; }
.error-code { color: var(--pink); }
.error-foot { margin: 0; font-size: 12px; }

/* ---------- reports ---------- */

.report-sections { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); align-items: start; }
.report-list { list-style: none; margin: 0; padding: 6px 0; }
.report-list a { display: grid; gap: 2px; padding: 10px 18px; color: var(--ink); text-decoration: none;
                 border-left: 3px solid transparent; }
.report-list a:hover, .report-list a:focus-visible { background: var(--nav-hover); border-left-color: var(--nav-green);
                                                     text-decoration: none; }
.report-list .subtle { font-size: 12.5px; }
.report-head .eyebrow a { color: inherit; }
.report-filters { margin-bottom: 12px; }
.report-filters .card-body { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.report-filters .field { margin: 0; min-width: min(160px, 100%); }
.report-presets { display: flex; gap: 14px; flex-wrap: wrap; padding: 0 18px 14px; font-size: 12.5px; }
.report-exports { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.report-exports ~ .alert { margin-bottom: 12px; }
.report-tiles { margin-bottom: 18px; }
.report-tiles .v small { font-size: 12px; font-weight: 600; color: var(--ink-3); }
.report-table { margin-bottom: 16px; }
.report-truncated { padding: 10px 18px; margin: 0; }

/* ---- Finding a screen (fix list S17) ---------------------------------------------------------
   A search box above the menu. The results sit in the menu's own column rather than floating
   over the page, so a phone shows them where the menu already is. */
.nav-search { position: relative; padding: 0 2px 12px; }
.nav-search-input {
  width: 100%; padding: 7px 10px; font: inherit; font-size: 13px;
  color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--rule); border-radius: var(--radius-sm);
}
.nav-search-input::placeholder { color: var(--ink-3); }
.nav-search-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; background: var(--surface); }
.nav-search-results {
  list-style: none; margin: 6px 0 0; padding: 4px; display: grid; gap: 1px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.nav-search-results [role="option"] > a {
  display: flex; flex-direction: column; gap: 1px; padding: 6px 8px; border-radius: var(--radius-sm);
  color: var(--ink); font-size: 13px; text-decoration: none;
}
.nav-search-results [role="option"][aria-selected="true"] > a,
.nav-search-results [role="option"] > a:hover { background: var(--accent-soft); }
.nav-search-where { font-size: 11.5px; color: var(--ink-2); }
/* A display rule beats the hidden attribute; said again so an empty list takes no room. */
.nav-search-results[hidden] { display: none; }
.nav-search-none { padding: 6px 8px; font-size: 12.5px; color: var(--ink-2); }
