/* ===========================================================================
   The console's look (butler.li issue #149): butler.li's 1.0 look, after shadcn/ui, in plain CSS.
   ---------------------------------------------------------------------------
   The same tokens as butler.li's brand.css, under shadcn's own names (--background, --foreground,
   --muted, --border, --ring, --primary ...), the same 8 px corners (12 px for cards), the same
   type: Inter for the text and Bricolage Grotesque for page titles, bundled in fonts/. Nothing is
   fetched from anywhere else, and nothing here needs a script: the console has none, and its
   Content-Security-Policy says so.

   Dark follows the operator's system. The console has no setting of its own for it: one operator,
   one computer, and the overview already followed the system before 1.0.

   The overview page that butler.li's hotel.sh writes loads this file too, inside the console, so
   the frame around it (sidebar, top bar, footer) looks the same as on every other page. The
   overview's own style comes after this one and wins where both say something.
   =========================================================================== */

@font-face { font-family: "Inter"; font-weight: 100 900; font-display: swap;
             src: url("/static/fonts/inter-latin.woff2") format("woff2");
             unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Inter"; font-weight: 100 900; font-display: swap;
             src: url("/static/fonts/inter-latin-ext.woff2") format("woff2");
             unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Bricolage Grotesque"; font-weight: 200 800; font-display: swap;
             src: url("/static/fonts/bricolage-grotesque-latin.woff2") format("woff2");
             unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Bricolage Grotesque"; font-weight: 200 800; font-display: swap;
             src: url("/static/fonts/bricolage-grotesque-latin-ext.woff2") format("woff2");
             unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

:root {
  color-scheme: light;
  --background: #ffffff; --foreground: #222222; --card: #ffffff; --muted: #f4f4f5;
  --muted-foreground: #5c5c66; --subtle: #fafafa; --border: #e4e4e7; --input: #8b8b94;
  --ring: #71717a; --primary: #222222; --primary-foreground: #ffffff; --secondary: #f4f4f5;
  --secondary-foreground: #222222; --hover: #f4f4f5; --link: #222222; --accent: #f4f4f5;
  --ok: #2e6b2a; --ok-bg: #eaf3e6; --info: #2b5c8a; --info-bg: #e8f0f8; --warn: #8a4b00;
  --warn-bg: #fceedc; --err: #a3231c; --err-bg: #fbe9e7; --destructive: #b42318;
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-display: "Bricolage Grotesque", "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --radius: 8px; --radius-lg: 12px; --radius-sm: 6px;
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .05);
  --shadow: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px -1px rgba(0, 0, 0, .06);
  --shadow-lg: 0 10px 38px -10px rgba(0, 0, 0, .25), 0 10px 20px -15px rgba(0, 0, 0, .15);
}
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --background: #161618; --foreground: #f4f4f5; --card: #1c1c1f; --muted: #27272a;
    --muted-foreground: #a1a1aa; --subtle: #1a1a1d; --border: #2e2e33; --input: #71717a;
    --ring: #a1a1aa; --primary: #f4f4f5; --primary-foreground: #161618; --secondary: #27272a;
    --secondary-foreground: #f4f4f5; --hover: #27272a; --link: #f4f4f5; --accent: #27272a;
    --ok: #8fcf87; --ok-bg: #1d2b1b; --info: #8db8e3; --info-bg: #18222d; --warn: #e7a861;
    --warn-bg: #2d2214; --err: #f0948c; --err-bg: #2e1a18; --destructive: #dc4c40;
    --shadow-xs: none; --shadow: none; --shadow-lg: 0 10px 38px -10px rgba(0, 0, 0, .7);
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--background); color: var(--foreground);
  font: 14px/1.55 var(--font-sans); -webkit-font-smoothing: antialiased;
  font-feature-settings: "cv11", "ss01";
}
h1, h2, h3 { font-family: var(--font-sans); font-weight: 600; color: var(--foreground); letter-spacing: -.005em; }
h1 { font-family: var(--font-display); font-size: 28px; line-height: 1.2; margin: 0 0 6px; letter-spacing: -.01em; }
h2 { font-size: 19px; line-height: 1.3; margin: 0 0 12px; }
h3 { font-size: 16px; line-height: 1.35; margin: 20px 0 6px; }
a { color: var(--link); text-decoration-color: var(--input); text-underline-offset: 3px; }
a:hover { text-decoration-color: currentColor; }
code { font-family: var(--mono); }
.vh { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
      clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
:where(a, button, .btn, summary, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--ring); outline-offset: 2px;
}
@media (forced-colors: active) {
  :where(a, button, .btn, summary, input, select, textarea, [tabindex]):focus-visible { outline: 3px solid Highlight; }
}
.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 100; padding: 8px 12px;
  background: var(--primary); color: var(--primary-foreground); border-radius: var(--radius);
}
.skip-link:focus { top: 8px; }

/* --- the frame --------------------------------------------------------------
   The hotel app's frame (butler.li issue #144): the sidebar on the left with the console's menu
   and its sections, a top bar with where you are, the footer at the bottom. On a phone the sidebar
   hides behind the menu button, a <details> the stylesheet turns into a panel. */

/* The frame fills the window from its top edge. The overview of a hotel release before 1.0 puts
   16px of padding on its body, and its style wins over this file, so the frame started 16px down
   and its footer ended 32px below the window (Marcel, 2026-10-13). :has() outranks a plain body. */
body:has(> .app) { padding: 0; }
.app { display: grid; grid-template-columns: 248px minmax(0, 1fr); min-height: 100vh;
  background: linear-gradient(to right, var(--subtle) 247px, var(--border) 247px 248px, transparent 248px); }
.sidebar {
  background: var(--subtle); border-right: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 12px; padding: 12px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.app-main { min-width: 0; display: flex; flex-direction: column; min-height: 100vh; }

/* The console's menu, top left: butler.li's logo and "Admin console", opening onto who is signed
   in and signing out. */
.org-menu { position: relative; }
.org-menu > summary { list-style: none; }
.org-menu > summary::-webkit-details-marker { display: none; }
.org {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 6px 8px;
  border-radius: var(--radius); color: var(--foreground); text-decoration: none; cursor: pointer;
  user-select: none;
}
.org:hover, .org-menu[open] .org { background: var(--hover); }
.org-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.org-text .bl-logo { display: block; }
.org-sub { font-size: 12px; color: var(--muted-foreground); line-height: 1.2; }
.org-chev { color: var(--muted-foreground); flex: none; }
.org-who { margin: 0; padding: 6px 8px; font-size: 13px; overflow-wrap: anywhere; }
.dropdown-menu {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; min-width: 100%; padding: 4px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.dropdown-menu hr { border: 0; border-top: 1px solid var(--border); margin: 4px -4px; }
.dropdown-menu form { margin: 0; }
.dropdown-menu a, .dropdown-menu button {
  display: flex; width: 100%; align-items: center; gap: 8px; min-height: 32px; margin: 0; padding: 6px 8px;
  border: 0; border-radius: var(--radius-sm); background: none; box-shadow: none;
  color: var(--foreground); font-size: 14px; font-weight: 400; text-decoration: none; justify-content: flex-start;
}
.dropdown-menu a:hover, .dropdown-menu button:hover { background: var(--hover); }
.btn-icon {
  display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--radius);
  color: var(--foreground); cursor: pointer;
}
.btn-icon:hover { background: var(--hover); }

.sb-nav { display: flex; flex-direction: column; gap: 1px; }
.sb-group { margin: 10px 0 2px; padding: 0 8px; font-size: 12px; font-weight: 500; color: var(--muted-foreground); }
.sb-group:first-child { margin-top: 0; }
.sb-nav a {
  display: flex; align-items: center; gap: 10px; min-height: 34px; padding: 0 8px;
  border-radius: var(--radius); color: var(--foreground); font-weight: 500; font-size: 14px;
  text-decoration: none;
}
.sb-nav a svg { color: var(--muted-foreground); flex: none; }
.sb-nav a:hover { background: var(--hover); }
/* The weight is a second cue beside the background (1.4.1); aria-current says it to a screen
   reader. The frame takes --accent, not --muted: the overview that butler.li 0.61 writes loads
   its own style after this one and uses --muted for grey text, light grey in the dark, which
   turned the current entry into a pale block on the Hotels page only. */
.sb-nav a[aria-current] { background: var(--accent); font-weight: 600; }
.sb-nav a[aria-current] svg { color: var(--foreground); }

.topbar {
  position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 8px;
  min-height: 52px; padding: 0 20px 0 16px; background: var(--background);
  border-bottom: 1px solid var(--border);
}
.crumbs { display: flex; align-items: center; gap: 6px; min-width: 0; font-weight: 500; }
.crumbs a { color: var(--foreground); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.crumbs a:not([aria-current]) { color: var(--muted-foreground); }
.crumbs > span[aria-current] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.crumb-sep { color: var(--muted-foreground); }
.sb-toggle { display: none; }
.sb-toggle > summary { list-style: none; }
.sb-toggle > summary::-webkit-details-marker { display: none; }
.topbar-note { flex-basis: 100%; margin: 0 0 10px; }

main { width: 100%; max-width: 1240px; padding: 24px 32px 48px; flex: 1; }
.page-head { margin-bottom: 22px; }
.page-head p { color: var(--muted-foreground); margin: 0; max-width: 75ch; }
/* The forms are narrow, so a line stays readable; the activity log takes the width. */
main.narrow { max-width: 44rem; }

/* The footer: butler.li's logo, what this is, what it promises, and the version in a box. */
.ft {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; padding: 8px 20px;
  border-top: 1px solid var(--border); background: var(--subtle);
  color: var(--muted-foreground); font-size: 12px;
}
.ft-mark { color: var(--foreground); white-space: nowrap; }
.ft-mark .bl-logo { vertical-align: baseline; }
.ft-version {
  margin-left: auto; padding: 1px 6px; border-radius: 4px; background: var(--accent);
  border: 1px solid var(--border); font: 11px/1.5 var(--mono); color: var(--muted-foreground);
  white-space: nowrap; cursor: help;
}

@media (max-width: 900px) {
  .app { grid-template-columns: minmax(0, 1fr); background: none; }
  .sb-toggle { display: block; }
  .sidebar {
    position: fixed; top: 52px; left: 0; bottom: 0; z-index: 60; width: min(280px, 85vw);
    height: auto; transform: translateX(-105%); transition: transform .2s; box-shadow: var(--shadow-lg);
  }
  body:has(.sb-toggle[open]) .sidebar { transform: none; }
  .topbar { padding: 0 12px; }
  main { padding: 16px 16px 40px; }
}
/* A browser without :has() could never open the panel, so there the sidebar stays in the page,
   above it, and the button goes. */
@supports not selector(:has(*)) {
  @media (max-width: 900px) {
    .sidebar { position: static; transform: none; width: auto; box-shadow: none; border-right: 0;
               border-bottom: 1px solid var(--border); }
    .sb-toggle { display: none; }
  }
}

/* Signing in and the second step: no frame, the logo above one narrow card in the middle, as on a
   hotel's sign-in page. */
body.bare { background: var(--subtle); }
.bare-head { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 9vh 16px 0; }
.bare-head .bl-logo { color: var(--foreground); }
.bare-head .org-sub { font-size: 13px; }
body.bare main { max-width: 27rem; margin: 0 auto; padding: 22px 16px 48px; }
body.bare .ft { background: transparent; border-top: 0; justify-content: center; padding-bottom: 32px; }
body.bare .ft-version { margin-left: 0; }
body.bare .card h2 { text-align: center; }
body.bare .card button[type=submit] { width: 100%; }

/* --- cards, notes, forms ---------------------------------------------------- */

.card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 20px 22px; margin-bottom: 16px; box-shadow: var(--shadow); min-width: 0;
}
.card > :last-child { margin-bottom: 0; }
.note {
  border-radius: var(--radius-lg); padding: 12px 14px; font-size: 14px; margin: 12px 0;
  border: 1px solid transparent; background: var(--info-bg); color: var(--info);
}
.note.bad { background: var(--err-bg); color: var(--err); }
.note a { color: inherit; }
.muted { color: var(--muted-foreground); }
.back { display: inline-flex; align-items: center; gap: 6px; margin: 0 0 14px; font-size: 13px;
        color: var(--muted-foreground); text-decoration: none; }
.back:hover { color: var(--foreground); }

label { display: block; margin: 16px 0 6px; font-weight: 500; font-size: 14px; }
input:not([type=checkbox]):not([type=radio]), select {
  /* 16px: below that iOS Safari zooms the page on focus and does not zoom back out. */
  width: 100%; padding: 8px 12px; font: 16px/1.4 var(--font-sans); color: var(--foreground);
  background: var(--card); border: 1px solid var(--input); border-radius: var(--radius);
  box-shadow: var(--shadow-xs);
}
input:focus, select:focus { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 25%, transparent); }
input[type=checkbox] { accent-color: var(--primary); width: 16px; height: 16px; }
/* The contract's fields on "Neues Hotel" (butler.li #233): one group with its own heading. */
fieldset.contract { margin: 24px 0 0; padding: 0; border: 0; border-top: 1px solid var(--border); }
fieldset.contract legend { padding: 16px 0 4px; font-weight: 600; font-size: 15px; }
.hint { display: block; margin: 0 0 6px; color: var(--muted-foreground); font-size: 13px; }

/* Buttons are shadcn's Button. In the console every form has one action, so a plain button is the
   solid ink "default" variant; .secondary is the filled grey beside it, .danger the red one. */
button, a.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 36px; margin-top: 20px; padding: 7px 16px; border-radius: var(--radius);
  font: 500 14px/1.25 var(--font-sans); cursor: pointer; text-decoration: none;
  background: var(--primary); color: var(--primary-foreground); border: 1px solid var(--primary);
  box-shadow: var(--shadow-xs);
}
button:hover, a.button:hover { background: color-mix(in srgb, var(--primary) 88%, var(--background)); }
button.secondary { background: var(--secondary); color: var(--secondary-foreground); border-color: transparent; box-shadow: none; }
button.secondary:hover { background: var(--border); }
button.outline { background: var(--card); color: var(--foreground); border-color: var(--border); }
button.outline:hover { background: var(--hover); }
button.danger { background: var(--destructive); border-color: var(--destructive); color: #ffffff; }
button.danger:hover { background: color-mix(in srgb, var(--destructive) 88%, #000000); }
button.sm { min-height: 32px; padding: 5px 12px; font-size: 13px; margin-top: 0; }

/* A field's i: a <details> that opens its explanation below the label, with no script. */
.field-head { position: relative; margin-top: 16px; padding-right: 30px; }
.field-head label { margin: 0 0 6px; }
.info summary {
  position: absolute; top: -2px; right: 0; list-style: none; cursor: pointer; width: 26px; height: 26px;
  display: grid; place-items: center; border-radius: var(--radius-sm); color: var(--muted-foreground);
}
.info summary::-webkit-details-marker { display: none; }
.info summary:hover, .info[open] summary { background: var(--hover); color: var(--foreground); }
.info p {
  margin: 0 -30px 8px 0; padding: 10px 12px; background: var(--subtle); border: 1px solid var(--border);
  border-radius: var(--radius); font-size: 13.5px; color: var(--foreground);
}
.check { display: flex; gap: 10px; align-items: flex-start; font-weight: 400; margin: 4px 0 0; }
.check input { margin: 3px 0 0; flex: none; }

.qr { margin: 16px auto; max-width: 15rem; padding: 12px; background: #ffffff; border-radius: var(--radius); border: 1px solid var(--border); }
.qr svg { display: block; max-width: 100%; height: auto; }
.key code, .codes code { font: 14px/1.6 var(--mono); overflow-wrap: anywhere; }
.codes { columns: 2; padding-left: 20px; }
.steps { padding-left: 20px; }
details > summary { cursor: pointer; }
details pre {
  white-space: pre-wrap; overflow-wrap: anywhere; font: 12.5px/1.5 var(--mono);
  background: var(--muted); padding: 10px; border-radius: var(--radius);
}
.accounts dt { margin-top: 12px; font-weight: 600; }
.accounts dd { margin: 2px 0 0; }
.accounts code {
  font: 13.5px/1.6 var(--mono); overflow-wrap: anywhere; background: var(--muted);
  padding: 1px 5px; border-radius: 4px;
}

/* Deleting a hotel (issue #6): the one red button, and its card edged in red, so it is never
   mistaken for the other forms. */
.danger-card { border-color: color-mix(in srgb, var(--destructive) 45%, var(--border)); }
.danger-card h2 { color: var(--err); }
.goes li, .danger-card ul li { margin: 4px 0; }

/* The activity log (issue #9): one entry per line on a wide screen and stacked on a phone. */
.filter { display: inline-flex; flex-wrap: wrap; gap: 2px; margin: 4px 0 16px; padding: 3px;
          background: var(--muted); border-radius: var(--radius); }
.filter a { padding: 4px 12px; border-radius: var(--radius-sm); text-decoration: none;
            color: var(--muted-foreground); font-size: 13px; font-weight: 500; }
.filter a[aria-current] { background: var(--card); color: var(--foreground); box-shadow: var(--shadow-xs); }
.log { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
.log li { display: grid; grid-template-columns: 9.5rem minmax(0, 1fr) minmax(0, 12rem); gap: 2px 16px;
          padding: 10px 8px; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.log li.bad { box-shadow: inset 3px 0 0 var(--err); }
.log li.gone { background: var(--err-bg); }
.log-at { color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
.log-what, .log-who { overflow-wrap: anywhere; }
.log-hotel { display: block; color: var(--muted-foreground); }
.log-who { color: var(--muted-foreground); }
.pages { display: flex; gap: 16px; margin: 16px 0 0; }
.customers { display: grid; grid-template-columns: minmax(0, 12rem) minmax(0, 1fr); gap: 4px 16px; margin: 0 0 8px; }
.customers dt { font-weight: 600; overflow-wrap: anywhere; }
.customers dd { margin: 0; overflow-wrap: anywhere; }
.tag { font-weight: 500; font-size: 12px; padding: 0 6px; border-radius: var(--radius-sm);
       background: var(--err-bg); color: var(--err); }

/* The overview's "Refresh now", beside the time the page was written. */
.rf { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: 0 0 24px; }
.rf > p { margin: 0; }
.rf form { margin: 0; }
.rf-failed { flex-basis: 100%; color: var(--warn); }

@media (max-width: 640px) {
  .log li { grid-template-columns: minmax(0, 1fr); }
  .customers { grid-template-columns: minmax(0, 1fr); }
  .customers dd { margin-bottom: 8px; }
}

/* Who signs a hotel's contract, and who has (butler.li #238). */
/* Two forms in a row (butler.li #238: withdrawing a link and sending a new one): the lesser one
   on the left, the main one on the right, as everywhere; they wrap at phone width. */
.actions { display: flex; flex-wrap: wrap; gap: 0 12px; align-items: flex-end; }
.signers { list-style: none; margin: 8px 0 16px; padding: 0; }
.signers li { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid var(--border); }
.signers li:last-child { border-bottom: 0; }
.signers li > span:first-child { flex: none; margin-top: 2px; color: var(--muted-foreground); }
.signers li.done > span:first-child { color: var(--primary); }
