/* Mobile-first. System fonts only — no webfont request on a 3G connection. */

:root {
  --accent: #0f766e;
  --accent-dark: #115e59;
  --ink: #14201f;
  --ink-soft: #5b6b69;
  --line: #e3e8e7;
  --bg: #ffffff;
  --bg-soft: #f6f8f8;
  --warn: #b42318;

  /* The amber notice pair — offline, and a booking queued for retry. Tokens,
     not literals, because these were hardcoded in two separate rules and the
     dark sweep reached neither: on a dark page a #fef3c7 slab measured 16.2:1
     against the background, making a passive status bar the brightest thing on
     screen. Every colour a component needs must come from here, or the next
     one repeats it. */
  --notice-bg: #fef3c7;
  --notice-ink: #78350f;

  --radius: 14px;
  --wrap: 720px;

  /* Vertical rhythm lives in variables so the safe-area rules can add to it
     without overwriting it. Two rules setting `padding` on the same selector
     is a file-ordering bug waiting to happen. */
  --hero-top: 34px;
  --hero-bottom: 30px;
  --edge-bottom: 28px;
}

* { box-sizing: border-box; }

/* An author rule setting `display` beats the user-agent rule behind the
   `hidden` attribute, so any element given a display value ignores `hidden`
   silently. That shipped a resume bar that never hid and, in landscape, an
   owner panel visible behind its own sign-in gate. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
}

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 20px; }

h1, h2, h3 { line-height: 1.2; margin: 0 0 .5em; }
/* 2.15rem against a 16px body is ~2.15x — inside the 2-3x a hero needs to be
   the one dominant element in a glance. At 1.85rem it was competing with the
   search card rather than leading it. Desktop already lifts this to 3rem.
   .admin-head h1 is scoped separately and stays 1.35rem: the owner screen is
   work, not an arrival. */
h1 { font-size: 2.15rem; letter-spacing: -.02em; }
h2 { font-size: 1.2rem; letter-spacing: -.01em; }
h3 { font-size: 1rem; }

/* --- Offline notice ------------------------------------------------------ */
.offline-bar {
  background: var(--notice-bg);
  color: var(--notice-ink);
  padding: 10px 20px;
  font-size: .85rem;
  text-align: center;
}

/* --- Setup notice --------------------------------------------------------
   Shown while the property's own staff are still filling in their details.
   Deliberately louder than the offline bar: offline is a temporary condition
   the guest can see for herself, whereas a placeholder price looks exactly
   like a real one. */
.setup-bar {
  background: #7f1d1d;
  color: #fff;
  padding: 12px 20px;
  font-size: .85rem;
  text-align: center;
  line-height: 1.45;
}
.setup-bar strong { display: block; font-size: .95rem; }
.setup-bar span { opacity: .9; }

.room-price .unpriced {
  display: block;
  font-size: .8rem;
  font-style: italic;
  opacity: .75;
  white-space: nowrap;
}

/* --- Hero ---------------------------------------------------------------- */
.hero {
  background: linear-gradient(160deg, var(--accent), var(--accent-dark));
  color: #fff;
  padding: calc(var(--hero-top) + env(safe-area-inset-top)) 0 var(--hero-bottom);
}
.eyebrow {
  margin: 0 0 6px;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  opacity: .85;
}
.lede { margin: 0; opacity: .93; font-size: .96rem; max-width: 46ch; }

.perks { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 7px; }
.perks li {
  position: relative;
  padding-left: 24px;
  font-size: .88rem;
  opacity: .95;
}
.perks li::before {
  content: "✓";
  position: absolute;
  left: 0;
  font-weight: 700;
}

/* --- Cards --------------------------------------------------------------- */
.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  margin: 22px 0;
  box-shadow: 0 1px 2px rgba(16, 32, 30, .04);
}
.search { margin-top: -22px; position: relative; background: var(--bg); }
.section-h { margin: 26px 0 12px; }

/* --- Forms --------------------------------------------------------------- */
.fields { display: grid; gap: 14px; grid-template-columns: 1fr 1fr; }
.fields label { display: flex; flex-direction: column; gap: 5px; font-size: .82rem; }
.fields label.full { grid-column: 1 / -1; }
.fields label span { font-weight: 600; color: var(--ink-soft); }
.fields label em { font-weight: 400; font-style: normal; opacity: .75; }

input, textarea {
  font: inherit;
  font-size: 1rem; /* 16px minimum stops iOS zooming on focus */
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-soft);
  color: var(--ink);
  width: 100%;
  min-height: 44px;
}
input:focus, textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  /* var(--bg), not #fff. A literal white here lit the focused date field up
     like a torch on a dark page — the brightest element on screen, on a
     control the guest is merely typing into. */
  background: var(--bg);
}
textarea { resize: vertical; }

#f-guests { grid-column: auto; }
.search .fields { grid-template-columns: 1fr 1fr; }
.search .fields label:last-child { grid-column: 1 / -1; }

.stay-summary { margin: 14px 0 0; font-size: .88rem; color: var(--ink-soft); }
.field-error { color: var(--warn); font-size: .85rem; margin: 10px 0 0; font-weight: 500; }

/* --- Rooms --------------------------------------------------------------- */
.rooms { display: grid; gap: 14px; }

.room {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  display: grid;
  gap: 10px;
}
.room.unavailable { opacity: .55; }
.room-top { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.room-name { font-weight: 650; font-size: 1.02rem; }
/* Matches "Rate not set yet" beside it, so the two unfilled fields read as one
   deliberate state rather than two separate glitches. */
.room-name-unset { font-weight: 500; font-style: italic; color: var(--ink-soft); }
.room-cap { font-size: .8rem; color: var(--ink-soft); }
.room-price { text-align: right; white-space: nowrap; }
.room-price b { font-size: 1.12rem; }
.room-price small { display: block; color: var(--ink-soft); font-size: .74rem; }

.amenities { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; }
.amenities li {
  font-size: .74rem;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  padding: 3px 9px;
  border-radius: 999px;
  color: var(--ink-soft);
}

.room-total { font-size: .85rem; color: var(--ink-soft); }
.room-total b { color: var(--ink); }
.room-note { font-size: .8rem; color: var(--warn); margin: 0; }

/* --- Buttons ------------------------------------------------------------- */
.btn-primary, .btn-ghost, .btn-room {
  font: inherit;
  font-weight: 600;
  border-radius: 10px;
  padding: 12px 18px;
  cursor: pointer;
  min-height: 46px;
  border: 1px solid transparent;
}
.btn-primary {
  background: var(--accent);
  color: #fff;
  width: 100%;
  font-size: 1rem;
  margin-top: 4px;
}
.btn-primary:disabled { opacity: .55; cursor: not-allowed; }
.btn-room { background: var(--accent); color: #fff; justify-self: start; padding: 10px 20px; }
.btn-room:disabled { background: var(--bg-soft); color: var(--ink-soft); cursor: not-allowed; }
.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--ink-soft);
  width: 100%;
  margin-top: 18px;
}

/* --- Booking totals ------------------------------------------------------ */
.chosen { font-size: .88rem; color: var(--ink-soft); margin: -4px 0 16px; }
.totals { margin: 18px 0 14px; border-top: 1px solid var(--line); padding-top: 14px; }
.totals .row { display: flex; justify-content: space-between; font-size: .9rem; padding: 4px 0; }
.totals .row.grand { font-weight: 700; font-size: 1.05rem; border-top: 1px solid var(--line);
                     margin-top: 8px; padding-top: 10px; }
.totals .row.due { color: var(--accent); font-weight: 650; }
.fineprint { font-size: .78rem; color: var(--ink-soft); margin: 12px 0 0; }

/* --- Confirmation -------------------------------------------------------- */
.confirm { text-align: center; }
.tick {
  width: 52px; height: 52px; margin: 0 auto 14px;
  border-radius: 50%; background: var(--accent); color: #fff;
  font-size: 1.6rem; line-height: 52px;
}
.ref-label { font-size: .78rem; color: var(--ink-soft); margin: 16px 0 2px;
             text-transform: uppercase; letter-spacing: .08em; }
.ref {
  font: 700 1.5rem/1.2 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .06em; margin: 0 0 20px;
}
.pay { background: var(--bg-soft); border-radius: var(--radius); padding: 18px; text-align: left; }
.pay-amount { font-size: 1.25rem; font-weight: 700; margin: 0 0 12px; color: var(--accent); }
.pay-methods { display: grid; gap: 8px; }
.pay-method { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 11px 13px; }
.pay-method b { display: block; font-size: .74rem; text-transform: uppercase;
                letter-spacing: .06em; color: var(--ink-soft); }
.pay-value { font-size: 1.02rem; font-weight: 600; display: block; word-break: break-word; }
a.pay-value { color: var(--accent); }
.pay-mnote { display: block; font-size: .8rem; font-weight: 400; color: var(--ink-soft); margin-top: 2px; }
.pay-intl {
  font-size: .84rem;
  line-height: 1.5;
  color: var(--ink-soft);
  background: rgba(15, 118, 110, .07);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  padding: 11px 13px;
  margin: 12px 0 0;
}
.pay-qr { max-width: 190px; margin: 12px auto 0; display: block; border-radius: 10px; }
.pay-note { font-size: .82rem; color: var(--ink-soft); margin: 14px 0 0; }

.queued {
  background: var(--notice-bg); color: var(--notice-ink); border-radius: 10px;
  padding: 13px; font-size: .85rem; margin-top: 16px; text-align: left;
}
.contact-block { margin-top: 20px; font-size: .88rem; color: var(--ink-soft); }
.contact-block a { color: var(--accent); font-weight: 600; }

/* --- Footer -------------------------------------------------------------- */
.foot { padding: 28px 20px 40px; color: var(--ink-soft); font-size: .82rem; text-align: center; }
.foot p { margin: 0 0 4px; }
.foot-direct { font-weight: 600; color: var(--accent); }

/* --- Two views, not many devices ----------------------------------------- */
/* There is portrait (taller than wide) and landscape (wider than tall), and
   they meet at the square. Switch on the shape of the viewport, with a width
   floor so a small phone held sideways doesn't get the desktop layout. */

/* Roomier portrait — a large phone or a narrow window. */
@media (min-width: 620px) {
  :root { --hero-top: 52px; --hero-bottom: 46px; }
  h1 { font-size: 2.3rem; }
  .perks { grid-template-columns: 1fr 1fr; gap: 8px 22px; }
  .search .fields { grid-template-columns: 1fr 1fr auto; }
  .search .fields label:last-child { grid-column: auto; }
  #f-guests { width: 96px; }
}

/* Landscape: wider than tall, and wide enough to mean it. */
@media (min-width: 900px) and (min-aspect-ratio: 1/1) {
  :root { --wrap: 1120px; --hero-top: 76px; --hero-bottom: 68px; }

  h1 { font-size: 3rem; }
  .lede { font-size: 1.05rem; max-width: 52ch; }
  .perks { max-width: 760px; margin-top: 26px; }

  /* Rooms lead; the search panel rides alongside and stays reachable, so
     changing dates never means scrolling back up past everything.

     SCOPED TO .guest ON PURPOSE. admin.html also uses <main class="wrap">, so
     an unscoped rule here put the owner screen into the guest's
     rooms-plus-330px-sidebar grid — trapping "Your details" in a column meant
     for a search box, and fighting the owner screen's own #panel layout below.
     Any rule in this block that is not about the guest page needs the same
     prefix. */
  .guest main.wrap {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 330px;
    gap: 0 36px;
    align-items: start;
  }
  .search {
    grid-column: 2;
    grid-row: 1;
    position: sticky;
    top: 28px;
    margin-top: 28px;
  }
  .search .fields { grid-template-columns: 1fr 1fr; }
  .search .fields label:last-child { grid-column: 1 / -1; }
  #f-guests { width: auto; }

  .rooms-section { grid-column: 1; grid-row: 1; }
  .section-h { margin-top: 34px; }

  /* One decision per card, laid along the eye's path: see it, price it, take it.
     .room-price is nested inside .room-top, so it is not a grid child — the
     header row stays flex and splits name from price itself. */
  .room {
    grid-template-columns: 210px minmax(0, 1fr);
    grid-template-areas:
      "photo head"
      "photo tags"
      "photo total"
      "photo act";
    align-items: start;
    gap: 10px 20px;
    padding: 18px;
  }
  /* Higher specificity on purpose: the base .photo rule is declared later in
     this file and would otherwise win the column back. */
  .room > .photo {
    grid-area: photo;
    grid-column: 1;
    aspect-ratio: auto;
    height: 100%;
    min-height: 176px;
  }
  .room-top { grid-area: head; }
  .amenities { grid-area: tags; }
  .room-total, .room-note { grid-area: total; align-self: end; }
  .btn-room { grid-area: act; justify-self: start; align-self: end; }

  /* The form and the receipt are single-focus moments — let them centre. */
  .booking, .confirm {
    grid-column: 1 / -1;
    max-width: 680px;
    margin-inline: auto;
  }
  .foot { grid-column: 1 / -1; }
}

/* Landscape on something short — a laptop, or a phone turned sideways.
   Keep the hero from eating the fold. */
@media (min-aspect-ratio: 1/1) and (max-height: 780px) {
  :root { --hero-top: 26px; --hero-bottom: 22px; }
  h1 { font-size: 2rem; }
  .lede { font-size: .96rem; }
  .perks { margin-top: 16px; }
}

/* Genuinely short — a phone turned sideways. Give the fold back entirely. */
@media (min-aspect-ratio: 1/1) and (max-height: 480px) {
  .perks { display: none; }
  .search { position: static; }
}

/* --- Dark mode ----------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e7edec;
    --ink-soft: #9aa9a7;
    --line: #2a3634;
    --bg: #101816;
    --bg-soft: #182220;

    /* Measured, not guessed. #b42318 on a #141d1b card is 2.62:1 — below the
       4.5:1 AA floor, and it was the colour on "That password did not work"
       and "This room is not open for online booking yet": the two sentences a
       reader most needs were the dimmest text on the page. #ff6b5e is 6.15:1
       on a card and 6.46:1 on the page ground.
       The notice pair inverts rather than lightens: deep amber ground, pale
       amber text, 10.8:1 between them, and only 1.34:1 against the page — so
       it reads as a band, not a floodlight. */
    --warn: #ff6b5e;
    --notice-bg: #3a2d10;
    --notice-ink: #fde68a;
  }
  /* A 1px lighter border, not a lighter fill. #141d1b against #101816 is four
     points of luminance — on a phone in daylight the cards simply vanished and
     the page read as one undifferentiated dark slab. */
  .card, .pay-method { background: #141d1b; border-color: #26332f; }
  .btn-room:disabled { background: #182220; }
  .tick { color: #fff; }

}

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

/* --- Owner screen -------------------------------------------------------- */

.admin { background: var(--bg-soft); }
.admin-head { background: linear-gradient(160deg, var(--accent), var(--accent-dark));
              color: #fff; padding: 22px 0 20px; }
.admin-head h1 { font-size: 1.35rem; margin: 0; }
.admin-sub { margin: 2px 0 0; font-size: .82rem; opacity: .85; }

.admin .card { margin: 16px 0; }
.hint { font-size: .84rem; color: var(--ink-soft); margin: -2px 0 14px; }

.stack { display: flex; flex-direction: column; gap: 5px; font-size: .82rem; margin-bottom: 14px; }
.stack span { font-weight: 600; color: var(--ink-soft); }

select {
  font: inherit; font-size: 1rem; padding: 11px 12px; min-height: 44px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-soft); color: var(--ink); width: 100%;
}

.pill {
  display: inline-block; min-width: 22px; padding: 1px 8px; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: .8rem; text-align: center;
  vertical-align: middle;
}

/* Calendar */
.cal-head { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 10px; }
.btn-nav {
  font: inherit; font-size: 1.3rem; line-height: 1; width: 44px; height: 44px;
  border: 1px solid var(--line); background: var(--bg); color: var(--ink);
  border-radius: 10px; cursor: pointer;
}
.cal-dow, .cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-dow { margin-bottom: 4px; }
.cal-dow span { text-align: center; font-size: .7rem; font-weight: 600; color: var(--ink-soft); }

.cal-day {
  font: inherit; font-size: .92rem; aspect-ratio: 1; min-height: 40px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--bg); color: var(--ink); cursor: pointer;
}
.cal-day[aria-pressed="true"], .cal-day.is-closed {
  background: #fde3e1; border-color: #f3b8b3; color: #8a1c14; font-weight: 650;
}
.cal-day.is-booked {
  background: var(--accent); border-color: var(--accent); color: #fff;
  font-weight: 650; cursor: not-allowed;
}
.cal-day.is-past { opacity: .4; }
.cal-blank { aspect-ratio: 1; }

.legend { list-style: none; display: flex; flex-wrap: wrap; gap: 14px; padding: 0;
          margin: 14px 0 0; font-size: .78rem; color: var(--ink-soft); }
.legend li { display: flex; align-items: center; gap: 6px; }
.legend i { width: 14px; height: 14px; border-radius: 4px; border: 1px solid var(--line); }
.sw-open { background: var(--bg); }
.sw-closed { background: #fde3e1; border-color: #f3b8b3; }
.sw-booked { background: var(--accent); border-color: var(--accent); }

/* Booking cards */
.bk { border: 1px solid var(--line); border-radius: 12px; padding: 14px; margin-bottom: 10px;
      background: var(--bg); }
.bk-top { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.bk-top strong { font-size: 1rem; }
.bk-meta { font-size: .8rem; color: var(--ink-soft); }
.bk-money { font-weight: 700; white-space: nowrap; }
.bk-when { font-size: .9rem; margin: 6px 0 4px; }
.bk-note { font-size: .84rem; color: var(--ink-soft); font-style: italic; margin-top: 6px; }
.bk-ref { font-size: .72rem; color: var(--ink-soft); margin-top: 8px;
          font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.bk-actions { display: flex; gap: 8px; margin-top: 12px; }
.btn-confirm, .btn-decline {
  font: inherit; font-weight: 600; flex: 1; min-height: 44px;
  border-radius: 10px; cursor: pointer; border: 1px solid transparent;
}
.btn-confirm { background: var(--accent); color: #fff; }
.btn-decline { background: transparent; border-color: var(--line); color: var(--ink-soft); }
.btn-confirm:disabled, .btn-decline:disabled { opacity: .5; cursor: wait; }

@media (prefers-color-scheme: dark) {
  .cal-day[aria-pressed="true"], .cal-day.is-closed,
  .sw-closed { background: #4a1512; border-color: #6d201b; color: #ffd9d5; }
}

/* Connected calendars */
.feed { display: flex; align-items: center; justify-content: space-between; gap: 12px;
        border: 1px solid var(--line); border-radius: 10px; padding: 11px 13px;
        margin-bottom: 8px; background: var(--bg); }
.feed strong { font-size: .95rem; }
.btn-small { flex: 0 0 auto; min-height: 38px; padding: 0 14px; font-size: .85rem; }
.feed-add { border-top: 1px solid var(--line); margin-top: 14px; padding-top: 16px; }

.cal-day.is-elsewhere {
  background: #e8ecf5; border-color: #c3cde3; color: #2f3f63;
  font-weight: 650; cursor: not-allowed;
}
.sw-elsewhere { background: #e8ecf5; border-color: #c3cde3; }

@media (prefers-color-scheme: dark) {
  .cal-day.is-elsewhere, .sw-elsewhere { background: #23304d; border-color: #33436b; color: #d3ddf3; }
}

/* Close-on-other-sites */
.pill-warn { background: var(--warn); }

/* --warn is deliberately lighter in dark so error TEXT clears 4.5:1 against a
   dark ground. That inverts this badge, where the same value is the ground:
   white on #ff6b5e is 2.79:1. Dark text on it is 5.98:1. A token swap is not
   finished until every direction it is used in has been measured. */
@media (prefers-color-scheme: dark) {
  .pill-warn { color: #14201f; }
}
.toggle { display: flex; gap: 10px; align-items: flex-start; font-size: .88rem;
          margin: 14px 0 4px; cursor: pointer; }
.toggle input { width: 20px; height: 20px; min-height: 20px; flex: 0 0 auto; margin-top: 1px; }
.btn-inline { width: auto; margin-top: 10px; padding: 9px 16px; min-height: 40px; font-size: .85rem; }

.ota { border: 1px solid #f3b8b3; background: #fef6f5; border-radius: 12px;
       padding: 14px; margin-bottom: 10px; }
.ota-what { font-weight: 650; font-size: .98rem; }
.ota-when { font-size: .9rem; margin: 4px 0 10px; }
.ota-who { font-size: .8rem; color: var(--ink-soft); }
.btn-done { font: inherit; font-weight: 600; width: 100%; min-height: 44px;
            border-radius: 10px; border: 1px solid transparent;
            background: var(--accent); color: #fff; cursor: pointer; }
.btn-done:disabled { opacity: .5; cursor: wait; }

.conflict { background: #fef6f5; border: 1px solid #f3b8b3; color: #8a1c14;
            border-radius: 10px; padding: 12px; font-size: .85rem; margin-top: 10px; }

@media (prefers-color-scheme: dark) {
  .ota, .conflict { background: #2a1614; border-color: #6d201b; }
  .conflict { color: #ffd9d5; }
}

/* --- Photos -------------------------------------------------------------- */
/* Aspect ratio is fixed so a slow-loading photo doesn't shove the page around
   while a guest is reading it. */
.photo {
  grid-column: 1 / -1;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 10px;
  display: block;
  background: var(--bg-soft);
}
.photo-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--tone-a), var(--tone-b));
  color: rgba(20, 32, 31, .34);
}

/* MUST stay immediately after the rule it overrides. The dark block near the
   top of this file loses to it on source order at equal specificity — the
   third time this file has been bitten by that, after the `padding` collision
   and the `[hidden]` bug. If you move either rule, move both.

   The light tints were the brightest thing on a dark page, which inverts the
   intended reading: a real photo should be the bright element and the stand-in
   should recede. */
@media (prefers-color-scheme: dark) {
  .photo-empty {
    background: linear-gradient(135deg, var(--tone-a-dark), var(--tone-b-dark));
    color: rgba(231, 237, 236, .30);
  }
  .photo { background: var(--bg-soft); }
}
/* The glyph was a fixed 46px, which read as a speck in a large tinted box and
   made the box look like a loading failure rather than a deliberate stand-in.
   Scale it with the card so the proportion holds at every size. */
.photo-empty svg {
  width: 26%;
  min-width: 44px;
  max-width: 96px;
  height: auto;
}
.hero.has-photo {
  background-size: cover;
  background-position: center;
}

/* Owner screen in landscape: two columns, because she is often at a desk with
   the OTA extranet open beside this. */
@media (min-width: 900px) and (min-aspect-ratio: 1/1) {
  .admin .wrap { max-width: 1120px; }

  /* The gate is the only thing on screen before sign-in, and pinned to the top
     of a 900px-tall empty page it read as unfinished rather than calm. Drop it
     toward the optical centre and hold it to a readable width. Signed in, the
     gate is [hidden], so none of this touches the working screen. */
  #gate {
    max-width: 420px;
    margin: clamp(40px, 18vh, 180px) auto 0;
  }
  #panel {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 24px;
    align-items: start;
  }
  #panel > .card { margin: 22px 0 0; }

  /* "Your details" is several times taller than any other card — left in a
     single column it pinned one side of the grid and left the other empty for
     over a thousand pixels of scroll. Span it, and lay the room blocks out
     across the width it gains, which also removes most of that scroll. */
  #details-card { grid-column: 1 / -1; }
  #details-card #d-rooms {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 0 20px;
    align-items: start;
  }
  #panel > button, #panel > .build { grid-column: 1 / -1; }
  .cal-day { min-height: 46px; }
}

/* --- Property details form ----------------------------------------------- */
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.sub { margin: 22px 0 10px; font-size: .95rem; }

.room-edit { border: 1px solid var(--line); border-radius: 12px; padding: 14px;
             margin-bottom: 10px; background: var(--bg); }
.room-edit h4 { margin: 0 0 10px; font-size: .9rem; color: var(--ink-soft); }

.owner-zone { border: 1px solid #f3b8b3; background: #fef6f5; border-radius: 12px;
              padding: 14px; margin: 22px 0 4px; }
.owner-warn { font-size: .84rem; color: #8a1c14; margin: 0 0 14px; line-height: 1.45; }
.saved { font-size: .85rem; color: var(--accent); font-weight: 600; margin: 10px 0 0; }

@media (prefers-color-scheme: dark) {
  .owner-zone { background: #2a1614; border-color: #6d201b; }
  .owner-warn { color: #ffd9d5; }
}

/* --- Build stamp --------------------------------------------------------- */
/* A non-technical owner can read this back over the phone, which is the only
   way "did my change go live?" ever gets a real answer. */
.build {
  font: 400 .68rem/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--ink-soft);
  opacity: .55;
  text-align: center;
  margin: 18px 0 0;
}

/* --- Tap shield ---------------------------------------------------------- */
/* Transparent, brief, self-removing. Absorbs the second half of a double-tap
   that would otherwise land on the screen that just arrived. */
.tap-shield {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: transparent;
}

/* --- Installed / standalone ---------------------------------------------- */
/* The browser tab hides this entire class of bug: with viewport-fit=cover the
   page runs under the notch and the home indicator once installed. These add
   to the spacing variables rather than replacing any padding, so this block
   can sit anywhere in the file without silently winning. */
body {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
.admin-head { padding-top: calc(22px + env(safe-area-inset-top)); }
.foot, #panel { padding-bottom: calc(var(--edge-bottom) + env(safe-area-inset-bottom)); }

/* --- Seam fixes ---------------------------------------------------------- */
/* Each of these answers a named continuity break found by walking the journey
   end to end as one person, rather than screen by screen. */

/* PROMISE, seam 1→2: a price must never change without saying why. */
.room-price .from {
  display: block;
  font: 400 .7rem/1 inherit;
  font-style: normal;
  color: var(--ink-soft);
  margin-bottom: 1px;
}
.room-price .season {
  display: block;
  color: var(--accent);
  font-weight: 650;
  margin-top: 1px;
}

/* STATE, seam 2→3: her tap has to leave a mark where she tapped. */
.room.is-chosen {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset;
}
.btn-room.is-chosen { background: var(--accent-dark); }

/* STATE + REGISTER, seam 4→5: say her plan back to her before the mechanics. */
.confirm-said {
  font-size: .95rem;
  color: var(--ink-soft);
  margin: -4px 0 18px;
  max-width: 42ch;
  margin-inline: auto;
}
.recap {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  text-align: left;
  display: grid;
  gap: 8px;
}
.recap-row { display: flex; justify-content: space-between; gap: 12px; font-size: .92rem; }
.recap-row strong { font-weight: 650; }
.recap-row span { color: var(--ink-soft); text-align: right; }
.confirm-note {
  font-size: .88rem;
  font-style: italic;
  color: var(--ink-soft);
  text-align: left;
  margin: 12px 2px 0;
}

/* EXIT, seam 4→5: a door back to the same person, in her channel. */
.btn-message {
  display: block;
  text-align: center;
  text-decoration: none;
  margin-top: 18px;
}

/* EXIT: leaving the page is not the same as losing the request. */
.resume-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--accent);
  color: #fff;
  padding: 10px 20px;
  font-size: .85rem;
}
.resume-bar button {
  font: inherit;
  font-weight: 650;
  background: rgba(255, 255, 255, .18);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: 8px;
  padding: 7px 14px;
  min-height: 38px;
  cursor: pointer;
  flex: 0 0 auto;
}
