/* Nuvelo design system — tokens from the brand book (design_handoff_nuvelo_brand) */
:root {
  --brand: #E1613C;                       /* Clay */
  --brand-hover: #c74f2d;
  --brand-text: #b5453a;
  --brand-tint: rgba(225, 97, 60, .15);
  --accent: #EDA232;                      /* Honey */
  --accent-text: #9a6410;
  --accent-tint: rgba(237, 162, 50, .18);
  --fresh: #3E9B6B;                       /* Mint */
  --fresh-text: #2f7a52;
  --fresh-tint: rgba(62, 155, 107, .15);
  --ink: #241C17;                         /* Espresso */
  --ink-2: #6E6157;                       /* Cocoa */
  --danger: #b5453a;                      /* Clay ink — destructive actions on-brand */
  --muted: #9B8B7C;
  --line: #EADFCF;                        /* Oat */
  --cream: #FBF4EA;
  --paper: #FFFDF8;
  --bg: #EFE6D6;
  --radius-card: 18px;
  --radius-btn: 12px;
  --shadow-card: 0 16px 34px -26px rgba(90, 40, 20, .5);
  --shadow-section: 0 20px 50px -34px rgba(90, 40, 20, .35);
  --font-display: "Bricolage Grotesque", system-ui, sans-serif;
  --font-body: "Hanken Grotesk", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", monospace;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
::selection { background: var(--accent); color: var(--ink); }
/* Always reserve the scrollbar gutter so switching from a scrolling view (Settings)
   to a short one that fits the screen never changes the content width. Without this
   the vertical scrollbar toggles on every tab switch, and the ~15px width change
   shudders right-anchored fixed elements (the instance badge) and centred content
   sideways. Reserves space only; the scrollbar itself still shows only when needed. */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
}

h1, h2, h3 { font-family: var(--font-display); letter-spacing: -0.02em; }
a { color: var(--brand); }
a:hover { color: var(--brand-hover); }

.wrap { max-width: 860px; margin: 0 auto; padding: 24px 20px 60px; }
.wrap.narrow { max-width: 560px; }

/* ---- brand lockup ---- */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 0; margin-bottom: 18px;
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-weight: 800; font-size: 23px;
  letter-spacing: -0.03em; text-decoration: none; color: var(--ink);
}
.brand:hover { color: var(--ink); }
.brand .mark {
  width: 34px; height: 34px; flex: none;
  background: var(--brand); color: var(--paper); border-radius: 10px;
  display: grid; place-items: center; font-size: 20px; line-height: 1;
}
/* The icon glyph is drawn in CSS, not as a text node, so page text extraction reads the
   lockup as "nuvelo." ONCE — not "nnuvelo." A text "n" in the markup was exposed to
   crawlers/scrapers even with aria-hidden (which only affects the accessibility tree). */
.brand .mark::before { content: "n"; }
.brand .dot { color: var(--accent); }
.brand .brand-tag {
  font-family: var(--font-mono); font-weight: 500; font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted); margin-left: 2px;
}
.topbar a.minor { color: var(--ink-2); text-decoration: none; font-size: 15px; font-weight: 500; }
.topbar a.minor:hover { color: var(--brand); }

/* ---- landing ---- */
.hero { text-align: center; padding: 30px 0 38px; }
.hero h1 {
  font-size: clamp(38px, 7vw, 64px); font-weight: 800; letter-spacing: -0.03em;
  line-height: 1.05; margin: 0 0 14px;
}
.hero p { color: var(--ink-2); margin: 0 auto; max-width: 540px; font-size: 18px; }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 16px; }
.card {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius-card);
  padding: 22px; text-decoration: none; color: var(--ink); display: block;
  transition: box-shadow .15s, transform .15s;
}
a.card { color: var(--ink); }
a.card:hover { box-shadow: var(--shadow-card); transform: translateY(-2px); color: var(--ink); }
.card h3 { margin: 10px 0 6px; font-size: 22px; font-weight: 700; }
.card p { margin: 0; color: var(--ink-2); font-size: 15px; line-height: 1.5; }

/* mono eyebrow labels */
.badge {
  display: inline-block; font-family: var(--font-mono); font-weight: 500;
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  padding: 4px 12px; border-radius: 999px;
  background: var(--brand-tint); color: var(--brand-text);
}
.badge.softplay { background: var(--fresh-tint); color: var(--fresh-text); }
.badge.venue { background: var(--accent-tint); color: var(--accent-text); }

/* ---- panels ---- */
.panel {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius-card); padding: 26px;
  margin-bottom: 16px; box-shadow: var(--shadow-card);
}
.panel h2 { margin: 0 0 4px; font-size: 24px; font-weight: 700; }
.panel .sub { color: var(--ink-2); font-size: 15px; margin: 0 0 16px; line-height: 1.5; }

/* ---- forms ---- */
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 14px; font-weight: 600; margin-bottom: 6px; }

/* Inline field help: a tap-friendly (i) that reveals a plain-language explanation of a
   setting, so common jargon (slot interval, booking duration…) doesn't send people to
   the guide. `hlp()` in admin.html renders the button; one shared popover shows the copy. */
.fieldhelp {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-left: 4px; padding: 0; vertical-align: middle; flex: none;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
  color: var(--ink-2); font-family: var(--font-body); font-size: 11px; font-weight: 700;
  line-height: 1; cursor: pointer; -webkit-appearance: none; appearance: none;
}
.fieldhelp:hover, .fieldhelp:focus-visible { border-color: var(--brand); color: var(--brand-text); outline: none; }
.fieldhelp-pop {
  position: absolute; z-index: 60; max-width: 300px; width: max-content;
  background: var(--ink); color: var(--paper);
  font-family: var(--font-body); font-size: 13px; font-weight: 400; line-height: 1.45;
  padding: 10px 13px; border-radius: 10px; box-shadow: 0 8px 28px rgba(36, 28, 23, .22);
}
.field input, .field select, .field textarea {
  width: 100%; padding: 11px 13px; border: 1px solid var(--line); border-radius: 11px;
  font: inherit; font-size: 16px; background: var(--cream); color: var(--ink);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--brand); outline-offset: -1px;
}
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* Native file inputs render their own grey "Choose File" button that ignores the design
   system. Style the ::file-selector-button as a ghost pill so every upload control matches
   the .btn.ghost look, and align the whole control to sit on the button baseline of a row. */
input[type="file"] { font: inherit; font-size: 13px; color: var(--ink-2); max-width: 100%; }
input[type="file"]::file-selector-button {
  font: inherit; font-size: 14px; font-weight: 600; margin-right: 10px;
  padding: 9px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); color: var(--ink-2); cursor: pointer;
}
input[type="file"]::file-selector-button:hover { border-color: var(--ink-2); }

/* Standalone input/select/textarea that sits OUTSIDE a .field wrapper (compact toolbars,
   inline adjusters, search boxes). Same appearance as .field inputs — radius 11px, cream
   bg, brand focus — so every control on the site matches instead of hand-rolled 8/10px. */
.inp {
  padding: 11px 13px; border: 1px solid var(--line); border-radius: 11px;
  font: inherit; font-size: 16px; background: var(--cream); color: var(--ink);
}
.inp:focus { outline: 2px solid var(--brand); outline-offset: -1px; }

/* "powered by nuvelo." lockup — one definition for every guest page that shows it
   (was defined only inside widget.html, so order/bill rendered it unstyled). */
.powered { text-align: center; margin: 12px 0 6px; }
.powered a { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); text-decoration: none; }
.powered a b { color: var(--brand); } /* the wordmark keeps clay whatever the venue accent */

/* ---- opening-hours rows (admin settings) ---- */
.hours-row {
  display: grid; grid-template-columns: 52px 108px 1fr; gap: 8px;
  align-items: center; margin-bottom: 8px;
}
.hours-row > label { font-weight: 600; font-size: 13px; text-transform: capitalize; }
.hours-row select {
  padding: 9px 10px; border: 1px solid var(--line); border-radius: 10px;
  font: inherit; font-size: 14px; background: var(--cream); color: var(--ink);
}
.hours-row select:focus { outline: 2px solid var(--brand); outline-offset: -1px; }
.hours-ranges { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

/* ---- date picker (guest-facing — native calendar popups can't be styled) ---- */
.ncal-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 11px 13px; border: 1px solid var(--line); border-radius: 11px;
  font: inherit; font-size: 16px; background: var(--cream); color: var(--ink);
  cursor: pointer; text-align: left;
}
.ncal-trigger:focus-visible { outline: 2px solid var(--brand); outline-offset: -1px; }
.ncal-chev { color: var(--muted); flex: none; transition: transform .15s; }
.ncal.open .ncal-chev { transform: rotate(180deg); }
.ncal-pop {
  margin-top: 8px; padding: 14px; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.ncal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.ncal-title { font-family: var(--font-display); font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.ncal-nav {
  border: 0; background: transparent; color: var(--ink-2); cursor: pointer;
  font: inherit; font-size: 20px; line-height: 1; padding: 5px 12px; border-radius: 9px;
}
.ncal-nav:hover:not(:disabled) { background: var(--cream); color: var(--ink); }
.ncal-nav:disabled { opacity: .3; cursor: default; }
.ncal-week, .ncal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.ncal-week span {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); text-align: center; padding: 4px 0 6px;
}
.ncal-day {
  border: 0; background: transparent; font: inherit; font-size: 14px; font-weight: 500;
  color: var(--ink); padding: 8px 0; border-radius: 9px; cursor: pointer;
  transition: background .1s;
}
.ncal-day:hover:not(:disabled):not(.selected) { background: var(--accent-tint); }
.ncal-day.today:not(.selected) { box-shadow: inset 0 0 0 1.5px var(--accent); }
.ncal-day.selected { background: var(--brand); color: var(--paper); font-weight: 700; }
.ncal-day:disabled { color: var(--muted); opacity: .35; cursor: default; }

/* ---- buttons ---- */
.btn {
  display: inline-block; border: 0; border-radius: var(--radius-btn); padding: 14px 26px;
  font: inherit; font-size: 16px; font-weight: 600; cursor: pointer;
  text-decoration: none; text-align: center;
  background: var(--brand); color: var(--paper);
  transition: background .15s;
}
.btn:hover { background: var(--brand-hover); color: var(--paper); }
.btn:disabled { opacity: .5; cursor: default; }
.btn.full { width: 100%; }
.btn.ghost {
  background: transparent; color: var(--ink);
  border: 1.5px solid var(--ink); padding: 12.5px 24.5px;
}
.btn.ghost:hover { background: var(--ink); color: var(--paper); }
.btn.danger { background: var(--brand-tint); color: var(--brand-text); }
.btn.danger:hover { background: var(--brand); color: var(--paper); }
/* Compact button — one shared size for toolbar/inline actions, so "small" buttons
   stop reinventing ~8 different paddings. Works with .ghost/.danger too. */
.btn.small { padding: 9px 16px; font-size: 14px; }

/* ---- guest action buttons: uniform equal-cell grid ---- */
.actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-top: 4px; }
.actions .btn { width: 100%; }
.gdpr { border-top: 1px solid var(--line); margin-top: 16px; padding-top: 14px; }
.gdpr-label { display: block; font-size: 12px; margin-bottom: 8px; }
.gdpr .actions .btn { padding: 9px 12px; font-size: 13px; }

/* ---- booking slots & sessions ---- */
.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; }
.slot {
  padding: 11px 4px; border: 1px solid var(--line); border-radius: 11px;
  background: var(--paper); font: inherit; font-size: 15px; font-weight: 600;
  cursor: pointer; text-align: center; color: var(--ink);
}
.slot:hover { border-color: var(--brand); color: var(--brand); }
.slot.selected { background: var(--brand); border-color: var(--brand); color: var(--paper); }
.slot:disabled { opacity: .35; cursor: default; text-decoration: line-through; }

.session-card {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  border: 1px solid var(--line); border-radius: var(--radius-card);
  padding: 16px 18px; margin-bottom: 10px;
  background: var(--paper); cursor: pointer; width: 100%; font: inherit; text-align: left;
  color: var(--ink);
}
.session-card:hover { border-color: var(--brand); }
.session-card.selected { border-color: var(--brand); outline: 2px solid var(--brand); outline-offset: -2px; }
.session-card .name { font-family: var(--font-display); font-weight: 700; font-size: 18px; }
.session-card .meta { color: var(--ink-2); font-size: 14px; }
.session-card:disabled { opacity: .45; cursor: default; }

/* ---- status pills (leading dot per brand book) ---- */
.pill {
  display: inline-block; padding: 8px 16px; border-radius: 999px;
  font-size: 14px; font-weight: 600; line-height: 1.2; white-space: nowrap;
}
.pill::before { content: "● "; font-size: 10px; vertical-align: 1px; }
.pill.confirmed, .pill.completed, .pill.seated { background: var(--fresh-tint); color: var(--fresh-text); }
.pill.pending_payment { background: var(--accent-tint); color: var(--accent-text); }
.pill.cancelled, .pill.no_show, .pill.expired { background: var(--brand-tint); color: var(--brand-text); }

/* ---- notices ---- */
/* Q&A blocks — used by /faq and the venue landing pages, so shared here rather than
   duplicated per page. Questions are h3 under an h2 section label. */
.faq-q { border-bottom: 1px solid var(--line); padding: 20px 0; }
.faq-q h3 { font-size: 19px; margin: 0 0 8px; }
.faq-q p { font-size: 16.5px; line-height: 1.6; color: var(--ink-2); margin: 0 0 10px; }
.faq-q p:last-child { margin: 0; }

/* Walkthrough clips — used by the guide and the FAQ, so it lives here rather than being
   duplicated in two page <style> blocks. Two up on a desktop, one up on a phone. The
   posters DO load on first paint (~335KB across the six); `preload="none"` defers only
   the MP4s, which is where the real weight is. */
.vid-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin: 14px 0 22px; }
.vid { margin: 0; border: 1px solid var(--line); border-radius: 14px; overflow: hidden; box-shadow: var(--shadow-card); background: var(--paper); }
/* aspect-ratio reserves the box before the poster loads — without it the player collapses
   to the UA default 300x150 and the page reflows as each clip settles. Clips are 1280x800. */
.vid video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; background: var(--cream); }
.vid figcaption { font-size: 13px; color: var(--ink-2); padding: 10px 14px; border-top: 1px solid var(--line); line-height: 1.45; }
/* "Beta" marker — these are early, rough-and-ready recordings and we say so rather than
   letting a venue assume the polish level is final. */
.beta-tag { display: inline-block; font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  background: var(--accent-tint); color: var(--accent-text); border: 1px solid var(--accent); border-radius: 999px; padding: 3px 10px; vertical-align: middle; margin-left: 10px; }

.notice { border-radius: 11px; padding: 12px 16px; font-size: 15px; margin: 12px 0; line-height: 1.5; }
.notice.ok { background: var(--fresh-tint); color: var(--fresh-text); }
.notice.err { background: var(--brand-tint); color: var(--brand-text); }
.notice.info { background: var(--accent-tint); color: var(--accent-text); }

/* ---- detail lists ---- */
.kv { display: grid; grid-template-columns: 130px 1fr; gap: 8px 14px; font-size: 16px; margin: 16px 0; }
.kv dt { color: var(--ink-2); }
.kv dd { margin: 0; font-weight: 600; }

.muted { color: var(--muted); font-size: 14px; }
.spread { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ---- tables ---- */
table.list { width: 100%; border-collapse: collapse; font-size: 15px; }
table.list th {
  text-align: left; font-family: var(--font-mono); font-weight: 500;
  color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .1em;
  padding: 8px 10px; border-bottom: 1px solid var(--line);
}
table.list td { padding: 12px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
table.list select {
  padding: 6px 9px; border-radius: 9px; border: 1px solid var(--line);
  font: inherit; font-size: 14px; background: var(--cream); color: var(--ink);
}

/* ---- tabs ---- */
.tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.tabs button {
  padding: 10px 16px; border: 0; background: none; font: inherit; font-size: 16px; font-weight: 600;
  color: var(--ink-2); cursor: pointer; border-bottom: 2px solid transparent;
}
.tabs button.active { color: var(--brand); border-bottom-color: var(--brand); }

/* Grouped admin nav: a primary row (Bookings + the sections) and a second row for
   whichever section is open. The door tablet is a primary device, so both rows have
   to survive a narrow screen — they wrap, and the section row scrolls rather than
   pushing the page sideways. */
.tabnav { display: flex; align-items: flex-end; gap: 6px; flex-wrap: wrap; border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.tabnav .tabs { border-bottom: 0; margin-bottom: 0; }
.tabs-primary { flex: 0 0 auto; padding-bottom: 2px; display: flex; gap: 6px; align-items: center; }
.tab-groups { display: flex; gap: 6px; flex-wrap: wrap; padding-bottom: 2px; }
/* Bookings (the primary tab) and the section pills share ONE pill treatment so the whole
   row reads as a single nav and every item is obviously tappable — Bookings used to be an
   underlined text tab pushed apart from the pills, which read as a title, not a control.
   Kept as one rule (not two that approximate each other) so they can't drift. */
.tab-groups button, .tabs-primary button, .tabs-primary a {
  padding: 8px 14px; border: 1px solid var(--line); background: var(--paper); font: inherit;
  font-size: 14px; font-weight: 600; color: var(--ink-2); cursor: pointer; border-radius: 999px;
}
.tabs-primary a { text-decoration: none; }
.tab-groups button:hover, .tabs-primary button:hover, .tabs-primary a:hover { border-color: var(--ink-2); }
/* Service mode leaves the admin for the tablet floor screen, so it gets a distinct
   solid mint fill — clearly an action, and a different hue from the clay active-tab
   state so the two never read the same. */
.tabs-primary a[data-service-link] { background: var(--fresh); border-color: var(--fresh); color: var(--paper); }
.tabs-primary a[data-service-link]:hover { background: var(--fresh-text); border-color: var(--fresh-text); }
.tab-groups button.active, .tabs-primary button.active { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-text); }
/* A down-caret marks the four section pills as expandable (each reveals a sub-row of tabs);
   Bookings deliberately has none — it's a direct tab, not a menu. The caret flips up while
   its section is open. */
.tab-groups button::after {
  content: ""; display: inline-block; width: 0; height: 0; margin-left: 7px; vertical-align: 2px;
  border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid currentColor;
  opacity: .5; transition: transform .15s ease;
}
.tab-groups button.active::after { transform: rotate(180deg); opacity: .8; }
@media (prefers-reduced-motion: reduce) { .tab-groups button::after { transition: none; } }
.tab-group-row { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tab-group-row button { white-space: nowrap; }
@media (max-width: 700px) {
  .tab-groups { width: 100%; }
  .tab-groups button { flex: 1 1 auto; }
}

footer.site {
  text-align: center; color: var(--muted); font-family: var(--font-mono);
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase; margin-top: 44px;
}

/* ---- code snippets (embed instructions) ---- */
.code-snippet {
  background: var(--ink); color: var(--cream); border-radius: 12px;
  padding: 14px 16px; font-family: var(--font-mono); font-size: 12.5px;
  line-height: 1.7; overflow-x: auto; white-space: pre; margin: 0;
}

/* ---- floor plan (designer + picker widget) ---- */
/* Floor zoom/pan (floorzoom.js): a fixed-size viewport clips the .fp-canvas stage, which is
   scaled/translated by a transform. The canvas keeps its own size, room shape and placement
   maths — the viewport is purely a clip + a home for the zoom buttons. */
.fp-viewport { position: relative; width: 100%; overflow: hidden; border-radius: var(--radius-card); touch-action: none; }
.fp-zoom { position: absolute; right: 8px; bottom: 8px; display: flex; gap: 4px; z-index: 4; }
.fp-zoom button {
  width: 34px; height: 34px; padding: 0; border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink); font-size: 17px; font-weight: 700; line-height: 1;
  cursor: pointer; display: grid; place-items: center; box-shadow: 0 1px 4px rgba(0, 0, 0, .10);
}
.fp-zoom button:hover { border-color: var(--brand); color: var(--brand-text); }

/* Touch targets: on the door/floor TABLET (a coarse pointer) small glyph controls get a
   ≥44px hit area, without changing how they look under a mouse. The field-help (i) keeps
   its 16px badge but grows an invisible tap zone; the calendar nav and floor-zoom buttons
   grow their own box. */
@media (pointer: coarse) {
  .fieldhelp::after { content: ''; position: absolute; inset: -14px; }
  .ncal-nav { min-width: 44px; min-height: 44px; }
  .fp-zoom button { width: 44px; height: 44px; }
}
.fp-viewport.fp-zoomed .fp-canvas { cursor: grab; }
.fp-viewport.fp-zoomed .fp-canvas:active { cursor: grabbing; }
.fp-canvas {
  position: relative; width: 100%; aspect-ratio: 3 / 2;
  background: var(--cream); border: 1px solid var(--line); border-radius: var(--radius-card);
  overflow: hidden; touch-action: none; transform-origin: 0 0; will-change: transform;
}
/* Floor DESIGNER canvas only (this id is unique to the admin editor — the widget uses
   #w-floorbox, service #svc-canvas). A faint 5% grid so the snap-to-grid drag has something
   visible to line up against; the --cream fill shows through the cells. */
#fp-canvas {
  background-color: var(--cream);
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 5% 5%;
}
.fp-table {
  position: absolute; display: grid; place-items: center; text-align: center;
  background: var(--paper); border: 1.5px solid var(--ink-2); border-radius: 8px;
  font-size: 12px; font-weight: 600; line-height: 1.15; user-select: none;
  aspect-ratio: 1.5; color: var(--ink); padding: 2px;
}
.fp-table.round { border-radius: 999px; aspect-ratio: 1; }
.fp-table small { display: block; color: var(--muted); font-weight: 500; font-size: 10px; }
.fp-table.draggable { cursor: grab; }
.fp-table.draggable:active { cursor: grabbing; }
.fp-table.available { border-color: var(--fresh); background: var(--fresh-tint); cursor: pointer; }
.fp-table.available:hover { box-shadow: 0 0 0 2px var(--fresh); }
.fp-table.unavailable { opacity: .35; }
/* Guest floor-plan tables are <button>s so they are keyboard-reachable and have a
   role. That means undoing the browser's button defaults, and — the point of the
   exercise — giving focus somewhere clearly visible to land. */
button.fp-table { font-family: inherit; font-size: 12px; margin: 0; appearance: none; -webkit-appearance: none; }
button.fp-table:disabled { cursor: not-allowed; }
.fp-table:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; z-index: 5; }
.fp-table.selected { border-color: var(--brand); background: var(--brand); color: var(--paper); }
.fp-table.selected small { color: rgba(255, 253, 248, .85); }

/* draggable polygon corner handles (custom room shapes) */
.fp-vertex {
  position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border-radius: 999px; background: var(--brand); border: 2px solid var(--paper);
  box-shadow: 0 1px 4px rgba(90, 40, 20, .4); cursor: grab; z-index: 3; touch-action: none;
}
.fp-vertex:active { cursor: grabbing; }
.fp-vertex .vx {
  position: absolute; top: -9px; right: -9px; width: 16px; height: 16px; border-radius: 999px;
  background: var(--ink); color: var(--paper); font-size: 11px; line-height: 16px; text-align: center;
  cursor: pointer; opacity: 0; transition: opacity .1s;
}
.fp-vertex:hover .vx { opacity: 1; }

.fp-legend { display: flex; gap: 16px; margin-top: 10px; font-size: 13px; color: var(--ink-2); flex-wrap: wrap; }
.fp-legend .dot { display: inline-block; width: 10px; height: 10px; border-radius: 999px; margin-right: 5px; }

/* wall features: entrance / doors / windows */
.fp-feature {
  position: absolute; display: flex; flex-direction: column; align-items: center; gap: 2px;
  user-select: none; z-index: 2; pointer-events: none;
}
.fp-feature i { display: block; border-radius: 4px; }
.fp-feature span {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap;
}
.fp-feature.window i { width: 64px; height: 8px; background: var(--accent-tint); border: 1.5px solid var(--accent); }
.fp-feature.door i { width: 36px; height: 8px; background: var(--ink-2); }
.fp-feature.entrance i { width: 48px; height: 8px; background: var(--brand); }
/* A play zone is an AREA, not a wall fixture — a soft mint block (matching the soft-play
   badge) marking where the play equipment sits. */
.fp-feature.play i { width: 62px; height: 44px; background: var(--fresh-tint); border: 1.5px dashed var(--fresh); border-radius: 8px; }
.fp-feature.play span:not(.fx) { color: var(--fresh-text); }
.fp-feature.vert { flex-direction: row; }
.fp-feature.vert.window i { width: 8px; height: 64px; }
.fp-feature.vert.door i { width: 8px; height: 36px; }
.fp-feature.vert.entrance i { width: 8px; height: 48px; }
.fp-feature.vert.play i { width: 44px; height: 62px; }
.fp-feature.draggable { pointer-events: auto; cursor: grab; }
.fp-feature .fx {
  position: absolute; top: -9px; right: -9px; width: 18px; height: 18px;
  border-radius: 999px; background: var(--brand-tint); color: var(--brand-text);
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; cursor: pointer;
}
/* remove control on a table in the floor designer (matches the wall-feature ×) */
.fp-table .fx {
  position: absolute; top: -9px; right: -9px; width: 18px; height: 18px;
  border-radius: 999px; background: var(--brand); color: var(--paper);
  font-size: 12px; font-weight: 700; line-height: 18px; text-align: center;
  box-shadow: 0 1px 4px rgba(90, 40, 20, .35); z-index: 4;
  /* red-X cursor so it's obvious you're over the delete spot (falls back to pointer) */
  cursor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZyBzdHJva2UtbGluZWNhcD0icm91bmQiPjxsaW5lIHgxPSI2IiB5MT0iNiIgeDI9IjE4IiB5Mj0iMTgiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSI2Ii8+PGxpbmUgeDE9IjE4IiB5MT0iNiIgeDI9IjYiIHkyPSIxOCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjYiLz48bGluZSB4MT0iNiIgeTE9IjYiIHgyPSIxOCIgeTI9IjE4IiBzdHJva2U9IiNkODFlMmMiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjE4IiB5MT0iNiIgeDI9IjYiIHkyPSIxOCIgc3Ryb2tlPSIjZDgxZTJjIiBzdHJva2Utd2lkdGg9IjMuNSIvPjwvZz48L3N2Zz4=') 12 12, pointer;
}

/* The table's remove control is a real <button> now (it was a span, so keyboard users
   could not delete a table at all) — strip the browser defaults it brings with it. */
button.fx { border: 0; padding: 0; font-family: inherit; appearance: none; -webkit-appearance: none; }
.fp-table:focus-visible, button.fx:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; z-index: 6; }

/* Inline code in prose (e.g. data-size in Settings). There was no rule for this, so a
   bare <code> fell back to the browser's default monospace and looked foreign. */
code { font-family: var(--font-mono); font-size: 0.92em; background: var(--cream);
  border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px; }

/* room/floor switcher pills */
.room-pills { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
.room-pill {
  padding: 8px 16px; border-radius: 999px; border: 1.5px solid var(--line);
  background: var(--paper); font: inherit; font-size: 14px; font-weight: 600;
  color: var(--ink-2); cursor: pointer;
}
.room-pill:hover { border-color: var(--brand); color: var(--brand); }
.room-pill.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.room-pill.ghostly { border-style: dashed; }

/* ---- instance badge (demo/testing ribbons) ---- */
.instance-badge {
  position: fixed; top: 14px; right: 14px; z-index: 50;
  font-family: var(--font-mono); font-weight: 500; font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase;
  padding: 6px 14px; border-radius: 999px;
  background: var(--accent); color: var(--ink);
  box-shadow: var(--shadow-card);
}


/* ---- icon tiles: render brand line-SVGs, colour matched to the tint rotation ---- */
.ico { color: var(--brand-text); }
.ico svg { width: 22px; height: 22px; display: block; stroke: currentColor; stroke-width: 1.85; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.feat:nth-child(3n+2) .ico { color: var(--accent-text); }
.feat:nth-child(3n) .ico { color: var(--fresh-text); }

/* ---- shared marketing header/footer (injected by renderPage from public/_nav.html
   and _footer.html). These used to live inline in index.html, which is why every other
   page had a different-looking nav. */
.mk-nav { position: sticky; top: 0; z-index: 40; background: rgba(239,230,214,.82); backdrop-filter: blur(12px); border-bottom: 1px solid rgba(234,223,207,.9); }
.mk-nav-in { position: relative; max-width: 1160px; margin: 0 auto; padding: 15px 20px; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.mk-nav nav { display: flex; align-items: center; gap: 20px; }
.mk-nav nav a.minor { color: var(--ink-2); font-size: 15px; font-weight: 500; text-decoration: none; white-space: nowrap; }
.mk-nav nav a.minor:hover { color: var(--brand); }
.mk-nav nav a[aria-current="page"] { color: var(--brand); font-weight: 600; }

/* Desktop: <details> behaves as a plain row — the summary is hidden and the links show
   whether or not it is "open". */
.mk-menu > summary { display: none; }
.mk-menu-items { display: flex; align-items: center; gap: 20px; }
/* The right-hand group holds the menu plus the always-visible Sign in. On desktop the
   persistent Sign in is hidden (the inline `.mk-signin-inline` in the row covers it); it
   only appears once the row collapses into the hamburger below. */
.mk-nav-end { display: flex; align-items: center; gap: 20px; }
.mk-signin-persist { display: none; }
/* Modern Chromium/Edge collapse a CLOSED <details>'s content via content-visibility on the
   ::details-content slot, which zero-sizes the desktop nav even though .mk-menu-items is
   display:flex — so on a fresh desktop load the whole header showed nothing (summary is
   hidden here, content collapsed). Re-reveal the content above the mobile breakpoint; older
   engines without ::details-content ignore the rule and their display:flex override already
   shows the row. Scoped to desktop so the mobile hamburger still collapses normally. */
@media (min-width: 901px) {
  .mk-menu::details-content { content-visibility: visible; }
}

/* Phone: a row of seven links plus two buttons is ~180px wider than the screen, which is
   what used to zoom the whole page out. Collapse into a real disclosure instead of hiding
   the site — every page must still reach pricing and the demo in one tap. */
@media (max-width: 900px) {
  .mk-nav-in { padding: 12px 16px; }
  /* Below the collapse, the persistent Sign in sits beside the hamburger as a matching
     pill; the inline copy inside the menu is hidden so it never shows twice. */
  .mk-nav-end { gap: 10px; }
  .mk-signin-inline { display: none; }
  /* A plain, compact text link (not a bordered pill) so [Sign in] [hamburger] still fits at
     320px — the pill overflowed the narrowest phones. Brand colour + weight keep it obvious;
     vertical padding gives a touch target. */
  .mk-signin-persist {
    display: inline-flex; align-items: center; white-space: nowrap;
    font-size: 15px; font-weight: 600; color: var(--brand); text-decoration: none;
    padding: 8px 2px;
  }
  .mk-signin-persist:hover { text-decoration: underline; }
  .mk-signin-persist:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; border-radius: 6px; }
  .mk-menu > summary {
    display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
    font-size: 15px; font-weight: 600; color: var(--ink); padding: 8px 12px;
    border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
  }
  .mk-menu > summary::-webkit-details-marker { display: none; }
  .mk-menu > summary:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
  .mk-burger { width: 15px; height: 2px; background: var(--ink); position: relative; display: inline-block; }
  .mk-burger::before, .mk-burger::after { content: ""; position: absolute; left: 0; width: 15px; height: 2px; background: var(--ink); }
  .mk-burger::before { top: -5px; } .mk-burger::after { top: 5px; }
  .mk-menu[open] > summary { border-color: var(--brand); color: var(--brand); }
  .mk-menu[open] > summary .mk-burger,
  .mk-menu[open] > summary .mk-burger::before,
  .mk-menu[open] > summary .mk-burger::after { background: var(--brand); }
  /* The UA hides a closed <details>'s children with `display:none`; setting display on
     .mk-menu-items outranks that, so without this the "closed" menu was never closed. */
  .mk-nav .mk-menu:not([open]) > .mk-menu-items { display: none; }
  .mk-nav .mk-menu-items {
    position: absolute; right: 16px; left: 16px; margin-top: 10px;
    flex-direction: column; align-items: stretch; gap: 2px;
    background: var(--paper); border: 1px solid var(--line); border-radius: 14px;
    padding: 10px; box-shadow: 0 14px 34px rgba(36,28,23,.16); z-index: 50;
  }
  .mk-nav .mk-menu-items a.minor { padding: 11px 12px; border-radius: 9px; font-size: 16px; }
  .mk-nav .mk-menu-items a.minor:hover { background: var(--cream); }
  .mk-nav .mk-menu-items .btn { margin-top: 6px; text-align: center; }
}

.site-footer { border-top: 1px solid var(--line); margin-top: 56px; padding: 36px 0 28px; }
.sf-in { display: grid; grid-template-columns: repeat(4, 1fr); gap: 28px; }
.sf-group h2 { font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin: 0 0 10px; font-weight: 500; }
.sf-group a { display: block; margin-bottom: 7px; font-size: 14.5px; color: var(--ink-2); text-decoration: none; }
.sf-group a:hover { color: var(--brand); }
.sf-base { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 30px; padding-top: 18px; border-top: 1px solid var(--line); font-size: 13px; color: var(--muted); }
.sf-base a { color: var(--muted); }
@media (max-width: 760px) { .sf-in { grid-template-columns: 1fr 1fr; } }
@media (max-width: 420px) { .sf-in { grid-template-columns: 1fr; } }
