/* =============================================================================
   travee+ Quotation Studio — design system
   Brand: white + cyan · Font: Poppins
   White-label agents can override --brand / --brand-2 at runtime.

   The palette moved from CareMyTrip orange to travee+ cyan. Only the six brand
   and neutral tokens below changed: every rule in this file, and every page,
   reads them by name, so the whole app followed. Anything still hard-coding an
   orange hex is a bug — grep for F5821F before adding one.
   ========================================================================== */

:root {
  /* Brand (overridable per white-label agent) */
  --brand:      #25A8CB;   /* travee+ cyan */
  --brand-2:    #56C3DE;   /* light cyan, for the button gradient */
  --brand-ink:  #14738F;   /* deep cyan for text on light */
  --accent:     #0B1015;   /* ink (cover bar in the PDF) */

  /* Neutrals */
  --bg:         #F7FBFC;   /* cool off-white page */
  --surface:    #FFFFFF;
  --line:       #E3EAEE;
  --ink:        #0F141A;
  --muted:      #6C7880;
  --muted-2:    #9AA5AC;

  --ok:         #1E9E64;
  --warn:       #E0A100;
  --danger:     #D9483B;

  --radius:     16px;
  --radius-sm:  10px;
  --radius-lg:  26px;
  --shadow:     0 1px 2px rgba(11,16,21,.05), 0 8px 24px rgba(20,115,143,.07);
  --shadow-lg:  0 24px 60px -18px rgba(20,115,143,.26);
  --ring:       0 0 0 4px rgba(37,168,203,.16);

  --maxw: 1180px;
  --font: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

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

html { scroll-behavior: smooth; }

body {
  font-family: var(--font);
  color: var(--ink);
  background:
    radial-gradient(1100px 520px at 88% -8%, rgba(253,185,19,.16), transparent 60%),
    radial-gradient(900px 480px at -10% 4%, rgba(37,168,203,.10), transparent 55%),
    var(--bg);
  background-attachment: fixed;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

h1, h2, h3, h4 { line-height: 1.15; font-weight: 600; letter-spacing: -.02em; }
a { color: var(--brand-ink); text-decoration: none; }
img { max-width: 100%; display: block; }

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 22px; }
.muted { color: var(--muted); }
.small { font-size: .82rem; }
.center { text-align: center; }
.hidden { display: none !important; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.row { display: flex; gap: 12px; align-items: center; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; }
.stack { display: grid; gap: 14px; }

/* ---------------------------------------------------------------- brand ---- */
.brandmark { display: inline-flex; align-items: center; gap: 11px; font-weight: 700; letter-spacing: -.03em; color: var(--ink); }
/* Logos keep their own aspect ratio — square OR rectangular, never squished. */
.brandmark img, .brandmark svg { height: 40px; width: auto; max-width: 190px; object-fit: contain; display: block; }
.brandmark .dotcom { color: var(--brand); }
.brandmark b { font-weight: 700; }

/* --------------------------------------------------------------- buttons --- */
.btn {
  --_bg: var(--brand);
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font: inherit; font-weight: 600; font-size: .95rem;
  padding: 12px 22px; border-radius: 999px; border: 0; cursor: pointer;
  color: #fff; background: linear-gradient(180deg, var(--brand-2), var(--brand));
  box-shadow: 0 8px 20px -8px rgba(20,115,143,.6); transition: transform .16s, box-shadow .16s, filter .16s;
  text-align: center; white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 14px 26px -10px rgba(20,115,143,.7); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; box-shadow: none; }
.btn.ghost { background: var(--surface); color: var(--brand-ink); box-shadow: inset 0 0 0 1.5px var(--line); }
.btn.ghost:hover { box-shadow: inset 0 0 0 1.5px var(--brand); }
.btn.dark { background: linear-gradient(180deg, #3a3e46, var(--accent)); box-shadow: 0 8px 20px -10px rgba(0,0,0,.5); }
.btn.sm { padding: 8px 15px; font-size: .84rem; }

/* ---- touch ergonomics -------------------------------------------------- --
   Gated on `pointer: coarse`, NOT on width: a narrow desktop window is still a
   mouse, and growing every control there would just waste space. On a real
   touch screen the public pages were asking for 33-37px targets — a package
   card alone had three of them side by side — against the ~44px both Apple and
   Google publish as the comfortable minimum. The header stays a little tighter
   at 40px, because three rows of nav at 44px pushes the content off the fold. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn.sm { min-height: 44px; padding-top: 10px; padding-bottom: 10px; }
  .navlink { min-height: 40px; display: inline-flex; align-items: center; }
  .topbar .btn.sm { min-height: 40px; }
  /* The tile's three actions were 87 / 121 / 129 wide — a ragged row that read
     as three unrelated controls. Sharing the row makes them one control group. */
  .pkg-tile .row.wrap > .btn { flex: 1 1 auto; }
  /* Footer contact lines are the one place a phone number is meant to be TAPPED,
     and they were 22px of inline text. Block them out so the whole line is the
     target, without disturbing the surrounding copy. */
  footer a[href^="mailto:"], footer a[href^="tel:"], footer a[href*="wa.me"] {
    display: inline-flex; align-items: center; min-height: 40px;
  }
}

/* One hero decision, one button width. The two calls to action measured 245 and
   213, which on a phone reads as a mistake rather than a hierarchy. */
@media (max-width: 560px) {
  .hero .row.wrap > .btn { width: 100%; }
}
.btn.lg { padding: 15px 30px; font-size: 1.02rem; }
.btn.block { width: 100%; }
.btn-link { background: none; border: 0; color: var(--brand-ink); font: inherit; font-weight: 600; cursor: pointer; padding: 6px; }

/* ---------------------------------------------------------------- cards ---- */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 22px;
}
.card.pad-lg { padding: 30px; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: .74rem; font-weight: 600;
  padding: 5px 12px; border-radius: 999px; background: #E8F6FA; color: var(--brand-ink);
  border: 1px solid #BFE4F0; letter-spacing: .01em;
}
.chip.slate { background: #EEF0F3; color: var(--accent); border-color: #E1E4E9; }
.chip.ok { background: #E6F6EE; color: var(--ok); border-color: #CDEBDC; }
/* Amber chip: something is waiting on someone. */
.chip.warn { background: #FFF8E6; color: #7A5A12; border-color: #F2DCA7; }

.badge-status { text-transform: capitalize; font-weight: 600; font-size: .74rem; padding: 4px 11px; border-radius: 999px; }
.badge-status.draft { background: #F1F0EE; color: #6b6b6b; }
.badge-status.sent { background: #E8F6FA; color: var(--brand-ink); }
.badge-status.pending { background: #FFF3E0; color: #B4690E; }
.badge-status.confirmed { background: #E6F6EE; color: var(--ok); }
.badge-status.converted { background: #E6F6EE; color: #127a4a; }
.badge-status.cancelled { background: #FBE7E4; color: var(--danger); }
/* inline status dropdown in tables */
select.statusSel { width: auto; padding: 6px 10px; font-size: .82rem; font-weight: 600; border-radius: 999px; }

/* --------------------------------------------------------------- inputs ---- */
label.field { display: block; }
.field > span { display: block; font-size: .82rem; font-weight: 600; color: var(--ink); margin-bottom: 6px; }
.field > span .req { color: var(--brand); }
/* Checkbox and radio are EXCLUDED, and that exclusion is load-bearing.
   width:100% is meant for a text box; a checkbox obeyed it too, so every one of
   them rendered as wide as its own form. On /welcome that made the terms
   checkbox a 626px-wide control with its label crushed into the ~80px left over
   beside it — which read as a broken page, not as a wide checkbox. The 12px
   padding did the same to its height. Sized just below instead, once, rather
   than overridden at each of the two dozen places a checkbox appears.
   The :not()s are wrapped in :where() so this base rule stays at element
   specificity. Bare, it scored (0,2,1) and beat every `.thing input` override
   in this file — a 44px stepper box kept the 14px side padding and clipped the
   digit inside it to a sliver. */
input:where(:not([type="checkbox"]):not([type="radio"])), select, textarea {
  width: 100%; font: inherit; font-size: .95rem; color: var(--ink);
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 14px; transition: border-color .15s, box-shadow .15s;
}

/* A select sharing a flex row sizes to its content; 100% would wrap its
   siblings. Must stay below the rule above. Add a class if a new row wraps. */
:where(.row, .fx-row, .spread, .addbar, .photo-upload) > select:not(:only-child) { width: auto; }

/* A real 17px target, brand-coloured when checked. Not transform:scale() — that
   grows the picture and leaves the clickable area at the old size, so the edge
   of what you can see is not a place you can click. */
input[type="checkbox"], input[type="radio"] {
  width: 17px; height: 17px; flex: none; margin: 0; padding: 0;
  accent-color: var(--brand); cursor: pointer;
}
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--brand); box-shadow: var(--ring); }
input[readonly] { background: #F8F9FB; color: var(--muted); cursor: default; }
textarea { resize: vertical; min-height: 92px; }

/* The browser default placeholder is far too faint on the warm page — hints
   like "Uttarakhand" or "Pick or type your own" were effectively invisible.
   Dark enough to read, still clearly lighter than a real value. */
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }

/* A <input list="..."> is a dropdown, but it renders as a plain text box, so on
   a form that also has real <select>s only the selects looked openable. Give it
   the same chevron, and space on the right so the text never runs under it.
   Clicking it opens the list (ui.js) rather than only typing into it. */
input[list] {
  padding-right: 38px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%237A7A82' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
input[list].mini { padding-right: 30px; background-position: right 10px center; }
input[list]::-webkit-calendar-picker-indicator { opacity: 0; }   /* ours replaces it */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
/* Grid items are min-width:auto by default, so a wide child (a data table, a
   long select) stretches its column past the screen instead of scrolling inside
   its own wrapper. Every column here is meant to fit the grid, not the reverse. */
.grid-2 > *, .grid-3 > *, .grid-4 > * { min-width: 0; }
@media (max-width: 900px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }
/* Header rows (title + actions) and button rows must wrap on phones — unwrapped
   they stretch the page and everything to the right falls off the screen. */
@media (max-width: 720px) { .spread, .row { flex-wrap: wrap; gap: 8px; } }

/* ----------------------------------------------------- package live editor - */
.pkg-live-panel {
  background: #F7FBFC;
  border-color: #BFE4F0;
  padding: 14px 18px;
  margin-bottom: 14px;
  /* The editor breaks out of the 1180px reading column and uses the whole
     window. The DOCUMENT below it must not — it is A4 and stays A4 — but the
     editor is a workbench: on a wide screen the route, the rate chart and the
     bill all fit beside the controls instead of being three scrolls apart. */
  width: calc(100vw - 32px);
  max-width: 1680px;
  margin-left: 50%;
  transform: translateX(-50%);
}
@media (max-width: 1180px) {
  /* Below the reading column there is nothing to break out of. */
  .pkg-live-panel { width: auto; margin-left: 0; transform: none; }
}
/* Inside the app frame there is a sidebar to the left, so a 100vw breakout runs
   underneath it and the editor's first column is cut off. The main area is
   already the full width that is available — use it. */
.app-main .pkg-live-panel { width: auto; max-width: none; margin-left: 0; transform: none; }
.app-main .doc-toolbar,
.app-main .pkg-live-panel { --panel-in-app: 1; }
.pkg-live-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: start;
  margin-bottom: 12px;
}
.pkg-live-head b { display: block; color: var(--ink); }
.pkg-live-head span { display: block; color: var(--muted); font-size: .82rem; margin-top: 2px; }
.pkg-live-stats {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  min-width: 210px;
}
.pkg-live-stats span,
.pkg-live-stats b {
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 999px;
  padding: 6px 10px;
  font-size: .82rem;
  white-space: nowrap;
}
.pkg-live-stats b { color: var(--brand-ink); }
.pkg-control-grid {
  /* auto-fit rather than a fixed six-column track: the editor grew children,
     vehicle, tier and GST controls, and a hard-coded track list silently
     stacked every extra one into a 1px-wide column. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));
  gap: 10px;
  align-items: end;
}
/* Markup: each box says what it is (% of cost, or flat rupees) instead of two
   bare numbers sharing one label. */
.pkg-markup { display: flex; gap: 8px; }
.pkg-affix {
  display: inline-flex; align-items: center; gap: 4px; flex: 1; min-width: 0;
  border: 1px solid var(--line, #E6E8EC); border-radius: 10px; background: #fff; padding: 0 8px;
}
.pkg-affix input { border: 0 !important; padding: 9px 0 !important; background: transparent; min-width: 2.5em; width: 100%; }
@media (max-width: 460px) { .pkg-markup { flex-direction: column; } }
.pkg-affix input:focus { outline: none; box-shadow: none; }
.pkg-affix i { font-style: normal; font-size: .78rem; color: var(--muted); white-space: nowrap; }
.pkg-control-grid .field > span,
.pkg-route-row label > span {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
}
.pkg-control-grid input,
.pkg-control-grid select { padding: 9px 10px; font-size: .9rem; }
.pkg-actions-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 12px;
}
.pkg-route-editor {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed #BFE4F0;
}
.pkg-route-summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* "Route & nights" broke across two lines the moment the vehicle name beside it
     grew; below this width they stack instead of squeezing each other. */
}
@media (max-width: 520px) {
  .pkg-route-summary { grid-template-columns: minmax(0, 1fr); }
}
.pkg-route-summary-x {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 10px;
}
.pkg-route-summary > div {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.pkg-route-summary b { color: var(--ink); }
.pkg-route-summary span {
  color: var(--muted);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 9px;
  font-size: .78rem;
}
.pkg-route-list { display: grid; gap: 8px; }
.pkg-route-row {
  display: grid;
  grid-template-columns: 30px minmax(170px, 1fr) 132px auto;
  gap: 8px;
  align-items: end;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px;
}
.pkg-route-index {
  width: 26px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  background: #E8F6FA;
  color: var(--brand-ink);
  font-weight: 700;
}
.pkg-route-row input { padding: 8px 9px; font-size: .88rem; }
.pkg-stepper {
  display: grid;
  grid-template-columns: 34px 58px 34px;
  gap: 4px;
}
.pkg-stepper button {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  color: var(--brand-ink);
  cursor: pointer;
}
.pkg-stepper input { text-align: center; }
.pkg-route-tools {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 10px;
}
.btn.danger,
.btn.ghost.danger { color: var(--danger); }
/* Editable rate chart (package live editor) — trim which group-size rows show */
.pkg-rate-editor { margin-top: 14px; padding-top: 12px; border-top: 1px dashed #BFE4F0; }
/* The package page runs ~8 screens. This bar sticks under the site nav so the
   price, the way back and the download buttons never scroll out of reach. */
.doc-toolbar {
  position: sticky; top: 67px; z-index: 30;
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-bottom: 14px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
/* Wrap to its own line rather than ellipsis into nothing. `min-width: 0` let
   the title shrink to "11N/1…" while the price and five buttons kept their full
   width — unreadable from 760px (where the mobile rule starts) up to ~1100px.
   A real basis makes the bar break instead of crushing the one part that says
   which package this is. */
.doc-toolbar-title {
  flex: 1 1 15rem; min-width: 10rem; font-weight: 600; font-size: .92rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.doc-toolbar-price {
  font-weight: 700; color: var(--brand-ink); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* The agent's own actions, kept as one block so they wrap together and stay
   against the right edge instead of stringing out across the bar. */
.doc-toolbar-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-left: auto; }
.doc-toolbar-acts .btn { white-space: nowrap; }
@media (max-width: 760px) {
  .doc-toolbar { top: 0; }
  .doc-toolbar-title { flex-basis: 100%; flex-grow: 0; }
  /* Full width on its own line, or five buttons squeeze the price off the bar. */
  .doc-toolbar-acts { flex-basis: 100%; margin-left: 0; }
}

/* Says WHY the rate chart and the hotel table are not on the page for a visitor
   who has not registered. The API withholds them; without this the document just
   comes up shorter and the visitor is given no reason to sign up. */
.doc-gate {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  margin-bottom: 14px; padding: 14px 16px;
  background: var(--brand-soft, #E7F5F9); border: 1px solid var(--brand, #25A8CB);
  border-radius: var(--radius);
}
.doc-gate > div { flex: 1; min-width: 220px; }
/* The HEADING only — a direct child. Unscoped, this caught any <b> inside the
   note's paragraph too, so an emphasised word broke its own line. */
.doc-gate > div > b { display: block; font-size: .95rem; }
.doc-gate p { margin: 4px 0 0; font-size: .88rem; color: var(--muted, #7B888F); }

/* Storefront trip planner — the visitor's own controls, above the document. */
.pkg-plan {
  margin-bottom: 14px; padding: 14px 16px;
  background: #fff; border: 1px solid var(--line, #E3EAEF);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.pkg-plan-head { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; margin-bottom: 12px; }
.pkg-plan-head b { font-size: .98rem; }
.pkg-plan-head b i { color: var(--brand, #25A8CB); margin-right: 6px; }
.pkg-plan-head span { color: var(--muted, #7B888F); font-size: .82rem; }
.pkg-plan-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr));
  gap: 10px; align-items: end;
}
.pkg-plan-grid .field { margin: 0; }
.pkg-plan-grid .field > span {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted, #7B888F); font-weight: 600;
}
.pkg-plan-grid input, .pkg-plan-grid select { padding: 9px 10px; font-size: .9rem; }
/* One arrangement at this size: a value, not a dropdown with nothing to choose. */
.pkg-plan-fixed { display: block; padding: 9px 2px; font-size: .9rem; }
.pkg-plan-out {
  display: flex; gap: 18px; align-items: center; flex-wrap: wrap;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line, #E3EAEF);
}
.pkg-plan-fig span { display: block; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted, #7B888F); }
.pkg-plan-fig b { font-size: 1.22rem; color: var(--brand-ink); font-variant-numeric: tabular-nums; }
.pkg-plan-note { margin: 10px 0 0; }
@media (max-width: 560px) {
  .pkg-plan-out { gap: 12px; }
  .pkg-plan-out .btn { flex: 1 0 100%; justify-content: center; }
}

/* Summary of the folded rate chart — a whole 20-row table's worth of scroll. */
.pkg-rate-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; flex-wrap: wrap; margin-bottom: 8px;
}
/* Which version of an agent's own document is on screen, and the way back. */
.pkg-mine-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 auto 12px; max-width: 900px;
  padding: 10px 14px; border-radius: var(--radius);
  background: #F7FBFC; border: 1px solid #BFE4F0;
  font-size: .88rem; color: var(--brand-ink);
}
.pkg-mine-bar span { flex: 1; min-width: 220px; }

.pkg-rate-tools {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 0; border-bottom: 1px dashed var(--line); margin-bottom: 10px;
}
/* The group-size range. Two bare 92px selects sat between muted words, so which
   box was "from" and where to click both had to be guessed. Now it is one grouped
   control with clickable labels and a hit area big enough for a thumb. */
.pkg-range {
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 3px 8px 3px 4px; border: 1px solid var(--line); border-radius: 10px;
  background: #fff;
}
.pkg-range-lbl { font-size: .8rem; font-weight: 600; color: var(--ink, #23262b); cursor: pointer; padding: 0 2px; }
.pkg-range-lbl:hover { color: var(--brand); }
.pkg-rate-tools select {
  width: auto; min-width: 104px; min-height: 38px; cursor: pointer;
  padding: 6px 30px 6px 10px; font-size: .86rem; font-weight: 600;
  border: 1px solid var(--line); border-radius: 8px; background-color: #fff;
  /* Native carets vary and some platforms draw none at these sizes, so the arrow
     is drawn here — a select that looks like a text box does not invite a click. */
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center;
}
.pkg-rate-tools select:hover { border-color: var(--brand); }
.pkg-rate-tools select:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* On a phone the range keeps its own line rather than being split across a wrap. */
@media (max-width: 620px) {
  .pkg-range { width: 100%; justify-content: space-between; }
  .pkg-rate-tools select { flex: 1; min-width: 0; }
  .pkg-rate-sep { display: none; }
}
.pkg-rate-sep { width: 1px; height: 20px; background: var(--line); }
/* Group sizes as chips: point at the size you do or do not want. */
.pkg-size-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.pkg-size-chip {
  min-width: 30px; padding: 4px 7px; font-size: .78rem; cursor: pointer;
  border: 1px solid var(--brand, #25A8CB); border-radius: 999px;
  background: #E8F6FA; color: var(--brand-ink, #14738F); font-variant-numeric: tabular-nums;
}
.pkg-size-chip:hover { background: #D6EEF6; }
.pkg-size-chip.is-off {
  border-color: var(--line, #E6E8EC); background: var(--surface, #fff);
  color: var(--muted); text-decoration: line-through;
}
.pkg-tier-chip {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: .82rem; padding: 4px 9px; border: 1px solid var(--line);
  border-radius: 20px; background: var(--surface);
}
.pkg-tier-chip input { width: auto; margin: 0; }
.pkg-tier-chip.is-off { opacity: .55; text-decoration: line-through; }
.pkg-tier-chip b { font-weight: 500; }
/* The tier the headline price is quoted at — one of the ticked ones. */
.pkg-tier-chip.is-quoted { border-color: var(--brand, #25A8CB); background: #E8F6FA; }
.pkg-tier-chip.is-quoted b { font-weight: 700; color: var(--brand-ink, #14738F); }
.pkg-tier-field { grid-column: 1 / -1; }
/* The bill: what the client pays, line by line, with the child rates editable
   where their effect is visible. */
.pkg-bill { margin-top: 10px; border-top: 1px dashed #BFE4F0; padding-top: 8px; }
.pkg-bill-row {
  display: flex; justify-content: space-between; gap: 12px; align-items: center;
  padding: 5px 0; font-size: .86rem; border-bottom: 1px solid var(--line);
}
.pkg-bill-row b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.pkg-bill-row.is-sub { border-top: 1px solid var(--line); }
.pkg-bill-row.is-total { border-bottom: 0; font-size: .98rem; color: var(--brand-ink, #14738F); }
.pkg-bill-row.is-total b { font-size: 1.06rem; }
.pkg-bill-rate input {
  width: 92px; padding: 3px 6px; font-size: .82rem; text-align: right;
  border: 1px solid var(--line); border-radius: 6px; font-variant-numeric: tabular-nums;
}
.pkg-bill-rate input.is-edited { border-color: var(--brand, #25A8CB); background: #EFF9FC; }
/* The rate card above the bill: what one person costs in each kind of bed. */
.pkg-bill-card { border: 1px solid var(--line); border-radius: 10px; background: #fff; padding: 4px 10px 6px; margin-bottom: 10px; }
.pkg-bill-card .pkg-bill-row:last-child { border-bottom: 0; }
/* Numbered steps. The editor was one flat wall of twelve controls: everything was
   visible and nothing said what to do first. */
.pkg-side-group > h4 { display: flex; align-items: center; gap: 8px; }
.pkg-step-no {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--brand, #25A8CB); color: #fff; font-size: .78rem; font-weight: 700;
}
.pkg-step-hint {
  margin: 4px 0 10px; font-size: .82rem; line-height: 1.45; color: var(--muted);
  max-width: 62ch;
}
/* Rooms: a chosen arrangement plus the plan it produces, not a warning. */
/* Order controls beside each stop: the route IS the day program's order, so
   moving a stop has to be one click, not a delete and a re-add. */
.pkg-route-order { display: inline-flex; flex-direction: column; align-items: center; gap: 1px; }
.pkg-route-order button {
  border: 0; background: none; cursor: pointer; color: var(--muted);
  line-height: 1; padding: 1px 3px; font-size: .7rem; border-radius: 4px;
}
.pkg-route-order button:hover:not(:disabled) { color: var(--brand, #25A8CB); background: #E8F6FA; }
.pkg-route-order button:disabled { opacity: .25; cursor: default; }
/* Where a stop's rate came from — and what to do when the answer is "nothing".
   An agent could not see that a night was costed off a nationwide default, which
   is precisely the case where the quote is wrong. */
.pkg-stop-status { font-size: .78rem; line-height: 1.4; min-width: 190px; }
.pkg-stop-ok { color: #1B7F4B; }
.pkg-stop-warn { color: #A33; display: inline-block; }
/* The room arrangement does not hold. Nothing is corrected for the agent — the
   choice stands and this says what is wrong with it, loudly enough to be read. */
.pkg-room-alert {
  display: flex; gap: 7px; align-items: flex-start; margin-top: 7px;
  padding: 8px 10px; border-radius: 9px; font-size: .79rem; line-height: 1.45;
  background: #FEF3F2; border: 1px solid #FDA29B; color: #B42318;
}
.pkg-room-alert b { color: inherit; }
.pkg-sleeping { display: block; margin-top: 3px; color: var(--muted); }
.pkg-stop-warn a { color: #A33; text-decoration: underline; }
.pkg-stop-banner {
  margin: 0 0 8px; padding: 9px 12px; border-radius: 10px; font-size: .84rem; line-height: 1.5;
  background: #FDF0EE; border: 1px solid #F3C9C2; color: #8C2F22;
}
.pkg-stop-banner .btn { margin-left: 6px; vertical-align: baseline; }
/* Pick the hotels for a stop instead of retyping their names. The cell is a
   button; the choosing happens in a sheet, because an inline menu inside a
   horizontally-scrolling table opened clipped and shoved the columns around. */
.pkg-hotel-cell {
  display: flex; align-items: center; gap: 6px; width: 100%; min-width: 150px;
  text-align: left; cursor: pointer; font: inherit; font-size: .8rem; line-height: 1.35;
  padding: 6px 8px; border: 1px solid var(--line, #E6E8EC); border-radius: 8px; background: #fff;
}
.pkg-hotel-cell:hover { border-color: var(--brand, #25A8CB); background: #F7FBFC; }
.pkg-hotel-cell > span {
  flex: 1; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.pkg-hotel-cell.is-empty > span { color: var(--muted); }
.pkg-hotel-cell > i { flex: none; font-size: .72rem; color: var(--muted); }
.pkg-hotel-count { display: block; font-size: .68rem; color: var(--muted); padding: 2px 2px 0; }

/* The sheet itself. */
.pkg-hm-list { display: grid; gap: 2px; max-height: 46vh; overflow: auto; }
.pkg-hm-opt {
  display: flex; align-items: flex-start; gap: 9px; padding: 8px 10px; border-radius: 8px;
  cursor: pointer; font-size: .9rem; line-height: 1.4;
}
.pkg-hm-opt:hover { background: #EFF9FC; }
.pkg-hm-opt input { width: auto; margin: 3px 0 0; flex: none; }
.pkg-hm-name { flex: 1; min-width: 0; }
.pkg-need-list { margin: 0; padding-left: 20px; font-size: .86rem; line-height: 1.55; }
.pkg-need-list li { margin-bottom: 4px; }
.pkg-hm-rate {
  margin: 10px 0 0; padding: 8px 10px; border-radius: 8px; background: #F7FBFC;
  border: 1px solid #BFE4F0; font-size: .84rem; line-height: 1.45;
}
.pkg-hm-edit { flex: none; color: var(--muted); font-size: .78rem; }
.pkg-hm-edit:hover { color: var(--brand, #25A8CB); }

/* Folding a step. The heading stays, everything under it goes. */
.pkg-side-group > h4 {
  display: flex; align-items: center; gap: 8px;
  user-select: none;
}
.side-group-toggle {
  margin-left: auto; border: 0; background: none; cursor: pointer; color: var(--muted);
  padding: 4px 6px; border-radius: 6px; font-size: .8rem; line-height: 1;
  transition: transform .15s ease;
}
.side-group-toggle:hover { color: var(--brand, #25A8CB); background: #E8F6FA; }
.pkg-side-group.is-collapsed > *:not(h4) { display: none; }
/* A folded step is a row, not a card — the padding that frames its contents is
   just empty space once they are hidden. */
.pkg-side-group.is-collapsed { padding: 6px 12px; margin-bottom: 6px; }
.pkg-side-group.is-collapsed > h4 { margin: 0; }
.pkg-side-group > h4 { margin: 0 0 4px; }
.pkg-side-group.is-collapsed .side-group-toggle { transform: rotate(-90deg); }
.pkg-side-group.is-collapsed { padding-bottom: 4px; }

/* Build the rooms, don't pick them from a list: a room type, a count, and loose
   extra beds. Five side-by-side counters squeezed each stepper to about 60px and
   the minus, the number and the plus fought over it — a stepper needs ~120px, so
   two of them and a dropdown is what fits the sidebar.
   `span 2` rather than `1 / -1` on the type: in the 320px sidebar only two tracks
   fit, so it still takes the whole row and the counters wrap under it, while in
   the wizard's full-width card the three controls line up on one row instead of
   a full-width dropdown above two 120px counters marooned at the left. */
.pkg-mix { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px 10px; padding-top: 2px; }
.pkg-mix-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.pkg-mix-cell.is-type { grid-column: span 2; }
.pkg-mix-cell label {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .03em; color: var(--muted);
  display: flex; flex-direction: column; line-height: 1.25;
}
.pkg-mix-cell label small { text-transform: none; letter-spacing: 0; opacity: .75; }
.pkg-mix-cell select {
  width: 100%; min-width: 0; padding: 6px 8px; font-size: .88rem;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; color: inherit;
}
/* Capped: given a full-width wizard card the cell is ~250px, and a stepper
   stretched that far puts the minus and the plus a hand-width apart from the
   number they change. */
.pkg-mix-step { display: grid; grid-template-columns: 34px minmax(0, 1fr) 34px; gap: 4px; max-width: 160px; }
.pkg-mix-step input { width: 100%; min-width: 0; text-align: center; padding: 5px 2px; font-size: .86rem; }
.pkg-mix-step button { padding: 4px 0; }
/* A room arrangement the party does not fit in wears it. The control that made
   the choice goes red, and the line under it says why. */
.pkg-mix.is-bad select, .pkg-mix.is-bad input { border-color: #D92D20; }
.pkg-mix.is-bad select:focus, .pkg-mix.is-bad input:focus { outline: 2px solid #FDA29B; outline-offset: 1px; }
/* A page's own actions, in the sidebar rather than stacked over the document. */
.side-actions:empty { display: none; }
.side-actions { padding: 6px 10px 2px; border-top: 1px solid var(--line, #E6E8EC); margin-top: 6px; }
.side-acts-list { display: grid; gap: 6px; }
.side-acts-list .btn { width: 100%; justify-content: flex-start; }
:root.nav-rail .side-actions .side-label,
:root.nav-rail .side-acts-list .btn span { display: none; }
.pkg-rooms { display: flex; flex-direction: column; gap: 4px; }
.pkg-rooms small { color: var(--muted); font-size: .76rem; }
/* The drive from a departure city the package was not written for. */
.pkg-leg { grid-column: 1 / -1; border-left: 3px solid #BFE4F0; padding: 2px 0 2px 10px; margin-top: 8px; }
.pkg-leg-row { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.pkg-leg-row > span { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); min-width: 74px; }
.pkg-leg-row input { flex: 1; min-width: 0; padding: 7px 9px; font-size: .86rem; }
.pkg-bill-cap {
  display: block; font-size: .7rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); padding: 6px 0 2px;
}
.pkg-tier-picks { display: flex; flex-wrap: wrap; gap: 6px; padding-top: 2px; }
.pkg-rate-cell input {
  width: 100%; min-width: 92px; border: 1px solid transparent; background: transparent;
  padding: 4px 6px; border-radius: 6px; font-size: .85rem; text-align: right;
  font-variant-numeric: tabular-nums;
}
.pkg-rate-cell input:hover { border-color: var(--line); }
.pkg-rate-cell input:focus { border-color: var(--brand); background: #fff; outline: none; }
.pkg-rate-cell.is-edited input { border-color: var(--brand); background: #EFF9FC; font-weight: 600; }
details.pkg-rate-editor > summary.pkg-rate-head { cursor: pointer; list-style: revert; }
details.pkg-rate-editor > summary.pkg-rate-head::-webkit-details-marker { display: revert; }
.pkg-rate-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; }
.pkg-rate-table { width: 100%; border-collapse: collapse; font-size: .85rem; background: #fff; }
.pkg-rate-table th,
.pkg-rate-table td { padding: 7px 10px; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; }
.pkg-rate-table th {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); background: #F2F9FC;
}
.pkg-rate-table tr:last-child td { border-bottom: 0; }
.pkg-rate-del { width: 40px; }
.pkg-rate-del button {
  border: 1px solid var(--line); background: #fff; color: var(--danger);
  border-radius: 7px; width: 28px; height: 28px; cursor: pointer; line-height: 1;
}
.pkg-rate-del button:hover { background: #FFF1F0; }
/* Trimmed-row styling — shared by the package editor (.pkg-rate-table) and the
   Cost Calculator chart (.data table). */
tr.row-off { opacity: .45; }
tr.row-off .pkg-rate-del button { color: var(--brand-ink); }
tr.row-off td:not(.pkg-rate-del) { text-decoration: line-through; }
@media (max-width: 920px) {
  .pkg-live-head,
  .pkg-route-summary { grid-template-columns: 1fr; }
  .pkg-live-stats { justify-content: flex-start; }
  .pkg-control-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pkg-route-row { grid-template-columns: 30px minmax(0, 1fr); }
  .pkg-route-row .pkg-nights-field { grid-column: 2; }
  .pkg-route-row > button { grid-column: 2; justify-self: start; }
}
@media (max-width: 640px) {
  .pkg-control-grid { grid-template-columns: 1fr; }
  .pkg-route-row { grid-template-columns: 1fr; }
  .pkg-route-index { width: 100%; }
  .pkg-route-row .pkg-nights-field,
  .pkg-route-row > button { grid-column: auto; }
}

/* ------------------------------------------------------------- top nav ----- */
.topbar {
  position: sticky; top: 0; z-index: 40; backdrop-filter: blur(10px);
  background: rgba(255,255,255,.82); border-bottom: 1px solid var(--line);
}
.topbar .inner { display: flex; align-items: center; justify-content: space-between; height: 66px; }
.topbar nav { display: flex; align-items: center; gap: 6px; }
.navlink { padding: 8px 14px; border-radius: 999px; font-weight: 600; font-size: .9rem; color: var(--muted); }
.navlink:hover { color: var(--ink); background: #EFF9FC; }
.navlink.active { color: var(--brand-ink); background: #E8F6FA; }
.avatar { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; font-weight: 700;
  color: #fff; background: linear-gradient(180deg, var(--brand-2), var(--brand)); }
@media (max-width: 640px) {
  .topbar .inner { height: auto; min-height: 64px; align-items: flex-start; flex-wrap: wrap; gap: 8px; padding-top: 10px; padding-bottom: 10px; }
  .topbar .inner > .row { width: 100%; flex-wrap: wrap; gap: 7px; }
  .topbar #stepChip { display: none; }
  .topbar .brandmark { font-size: .92rem; gap: 8px; }
  .topbar .brandmark img, .topbar .brandmark svg { height: 32px; max-width: 145px; }
  .topbar .btn.sm { padding: 7px 10px; font-size: .76rem; }
}
/* The nav links outgrow the bar well before phone width (every admin page adds
   one), so wrap them early — an unwrapped bar stretches the page and gives every
   screen a sideways scroll. */
@media (max-width: 900px) {
  .topbar .inner { flex-wrap: wrap; }
  /* flex-start, not flex-end: once these wrap onto two or three rows, aligning
     each row to the right leaves a ragged staircase. Left-aligned they read as
     one tidy block, and unwrapped rows look identical either way because
     `.inner` is space-between and pushes the nav right regardless. */
  .topbar nav { flex-wrap: wrap; justify-content: flex-start; gap: 4px; row-gap: 6px; max-width: 100%; flex: 1 1 auto; }
  .navlink { padding: 7px 10px; font-size: .8rem; }
}

/* ------------------------------------------------------------ toast/loader- */
.toast-wrap { position: fixed; top: 18px; right: 18px; z-index: 400; display: grid; gap: 10px; }
.toast {
  background: var(--accent); color: #fff; padding: 13px 18px; border-radius: 12px; font-weight: 500;
  box-shadow: var(--shadow-lg); animation: slideIn .3s ease; max-width: 340px; font-size: .9rem;
}
.toast.ok { background: #12805a; } .toast.err { background: #c23b2f; }
@keyframes slideIn { from { transform: translateX(30px); opacity: 0; } to { transform: none; opacity: 1; } }

.overlay {
  position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  background: radial-gradient(700px 500px at 50% 30%, rgba(240,250,253,.96), rgba(232,246,250,.99));
  backdrop-filter: blur(4px);
}
.loader-mark { width: 84px; height: 84px; animation: spin 1.5s cubic-bezier(.6,.1,.3,.9) infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.loader-text { margin-top: 20px; font-weight: 600; color: var(--brand-ink); letter-spacing: .02em; }
.loader-sub { color: var(--muted); font-size: .86rem; margin-top: 4px; }
.dots::after { content: ''; animation: dots 1.4s steps(4,end) infinite; }
@keyframes dots { 0%{content:''} 25%{content:'.'} 50%{content:'..'} 75%{content:'...'} }

/* fade-in-up utility for staggered reveals */
.rise { animation: rise .5s both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* =============================================================================
   LANDING + AUTH
   ========================================================================== */
.hero { position: relative; overflow: hidden; padding: 60px 0 40px; }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 40px; align-items: center; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }
.hero h1 { font-size: clamp(2.2rem, 5vw, 3.6rem); letter-spacing: -.03em; }
.hero h1 .accent { color: var(--brand); }
.hero p.lede { font-size: 1.1rem; color: var(--muted); max-width: 30ch; margin: 18px 0 26px; }
.eyebrow { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: .8rem;
  color: var(--brand-ink); background: #E8F6FA; border: 1px solid #BFE4F0; padding: 6px 14px; border-radius: 999px; }

.feature-row { display: flex; gap: 22px; flex-wrap: wrap; margin-top: 30px; }
.feature { display: flex; gap: 11px; align-items: flex-start; max-width: 220px; }
.feature .ic { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
  background: #E8F6FA; color: var(--brand-ink); font-size: 1rem; }
.feature b { display: block; font-size: .9rem; } .feature span { font-size: .8rem; color: var(--muted); }

/* auth card */
.auth-card { max-width: 430px; width: 100%; }
.auth-card .tabs { display: flex; background: #EFF9FC; border-radius: 999px; padding: 5px; margin-bottom: 22px; }
.auth-card .tabs button { flex: 1; border: 0; background: none; font: inherit; font-weight: 600; color: var(--muted);
  padding: 9px; border-radius: 999px; cursor: pointer; transition: .18s; }
.auth-card .tabs button.active { background: #fff; color: var(--brand-ink); box-shadow: var(--shadow); }

/* Himalayan silhouette footer flourish */
.range { height: 120px; margin-top: 40px; background:
  linear-gradient(180deg, transparent, rgba(37,168,203,.05)),
  conic-gradient(from 210deg at 20% 100%, transparent 0 40deg, rgba(46,49,56,.08) 40deg 60deg, transparent 60deg);
  position: relative; }

/* =============================================================================
   WIZARD
   ========================================================================== */
.wizard { display: grid; grid-template-columns: 260px 1fr; gap: 26px; align-items: start; padding: 26px 0 60px; }
@media (max-width: 860px) { .wizard { grid-template-columns: 1fr; } .rail { position: static !important; } }
.wizard.quick-wizard { grid-template-columns: 1fr; max-width: 1180px; }
.quick-wizard .rail { display: none; }
.quick-wizard > section { width: 100%; }

.rail { position: sticky; top: 84px; }
.rail ol { list-style: none; display: grid; gap: 4px; }
.rail li { display: flex; gap: 13px; align-items: center; padding: 11px 12px; border-radius: 12px; color: var(--muted);
  font-weight: 600; font-size: .9rem; cursor: default; transition: .2s; }
.rail li .num { flex: none; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  font-size: .8rem; background: #E7EEF1; color: var(--muted-2); transition: .2s; }
.rail li.done { color: var(--ink); }
.rail li.done .num { background: var(--ok); color: #fff; }
.rail li.current { color: var(--brand-ink); background: #EFF9FC; }
.rail li.current .num { background: linear-gradient(180deg,var(--brand-2),var(--brand)); color: #fff; box-shadow: var(--ring); }
.rail li.locked { cursor: not-allowed !important; opacity: .62; }

.draft-bg { position: fixed; inset: 0; z-index: 70; background: rgba(35,38,43,.34); backdrop-filter: blur(3px); }
.draft-modal {
  position: fixed; z-index: 71; top: 92px; left: 50%; transform: translateX(-50%);
  width: min(460px, calc(100vw - 28px)); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 20px;
}
.draft-modal h2 { font-size: 1.18rem; }

.step { min-height: 60vh; }
.step-head { margin-bottom: 20px; }
.step-head .kicker { color: var(--brand); font-weight: 600; font-size: .82rem; letter-spacing: .08em; text-transform: uppercase; }
.step-head h2 { font-size: 1.7rem; margin-top: 4px; }
.step-head p { color: var(--muted); margin-top: 6px; max-width: 60ch; }

.wizard-actions { display: flex; justify-content: space-between; gap: 12px; margin-top: 30px;
  padding-top: 22px; border-top: 1px solid var(--line); }

.quick-head h2 { font-size: 1.9rem; }
.quick-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 18px; align-items: start; }
/* minmax(0,1fr), not the implicit auto track: an auto column is sized by its
   widest child, so one wide editor row stretched every card in the column past
   the viewport and the whole page scrolled sideways. */
.quick-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; min-width: 0; }
.quick-section { border-radius: 14px; }
.quick-section-title { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; color: var(--brand-ink); }
.quick-section-title i { color: var(--brand); }
.quick-section-locked {
  background: linear-gradient(180deg,#fff,#F8FAFC);
  border-style: dashed;
  opacity: .82;
}
/* A button now, not a label: it names the empty field and jumps to it. */
.locked-note {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 14px 16px;
  border: 1px solid transparent;
  border-radius: 12px;
  background: #F1F5F9;
  color: var(--muted);
  font-size: .92rem;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}
.locked-note[onclick]:hover,
.locked-note[onclick]:focus-visible { border-color: var(--brand); color: var(--text); }
.locked-note:not([onclick]) { cursor: default; }
.locked-note span { flex: 1; }
.locked-note i { color: #94A3B8; }
.locked-note[onclick]:hover i, .locked-note[onclick]:focus-visible i { color: var(--brand); }

/* Country -> State -> Trip type narrowing row above the package dropdown. */
.pkg-filter { padding: 12px; border: 1px dashed var(--line); border-radius: 12px; background: var(--bg); }
.pkg-filter .field span { font-size: 12px; }
.meal-picker { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.checkline {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--line); background: #fff; border-radius: 999px;
  padding: 8px 12px; font-size: .88rem; font-weight: 600; cursor: pointer;
}
.checkline input { width: auto; accent-color: var(--brand); }
.meal-summary, .meal-status { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.meal-chip {
  display: inline-flex; align-items: center; padding: 4px 8px; border-radius: 999px;
  font-size: .72rem; font-weight: 700; border: 1px solid transparent; white-space: nowrap;
}
.meal-chip.included { color: #13734B; background: #E6F6EE; border-color: #CDEBDC; }
.meal-chip.excluded { color: #8A4A00; background: #FFF4E0; border-color: #F2D1AA; }
.slim-table { box-shadow: none; border-radius: 10px; }
.slim-table table.data th { font-size: .68rem; padding: 10px; }
.slim-table table.data td { font-size: .84rem; padding: 11px 10px; vertical-align: top; }
.hotel-stays-table th:nth-child(1), .hotel-stays-table td:nth-child(1) { min-width: 190px; }
.hotel-stays-table th:nth-child(6), .hotel-stays-table td:nth-child(6) { min-width: 190px; }
.itinerary-table th:nth-child(3), .itinerary-table td:nth-child(3) { min-width: 260px; }
.rate-sheet {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.rate-sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 10px;
}
.rate-sheet-head b { display: block; color: var(--ink); }
.rate-sheet-head span { display: block; color: var(--muted); font-size: .78rem; margin-top: 2px; }
.rate-sheet-head strong { color: var(--brand-ink); white-space: nowrap; }
.rate-inputs input { padding: 9px 10px; font-size: .88rem; }
.rate-sheet-list {
  display: grid;
  gap: 7px;
  margin-top: 10px;
}
.rate-sheet-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 34px;
  gap: 10px;
  align-items: center;
  border: 1px solid #E5E7EB;
  background: #fff;
  border-radius: 8px;
  padding: 8px 9px;
}
.rate-sheet-row span {
  display: block;
  color: var(--muted);
  font-size: .76rem;
  margin-top: 1px;
}
.rate-sheet-row strong { color: var(--ink); white-space: nowrap; }
.rate-sheet-row.is-hidden {
  background: #F8FAFC;
  opacity: .72;
}
.rate-sheet-row.is-hidden b,
.rate-sheet-row.is-hidden strong { color: var(--muted); }
@media (max-width: 680px) {
  .rate-sheet-head { display: grid; }
  .rate-sheet-row { grid-template-columns: minmax(0, 1fr) auto 34px; gap: 8px; }
}
.day-viewer {
  margin-top: 12px; padding: 12px; border: 1px solid var(--line);
  border-radius: 12px; background: #F8FAFC;
}
.day-detail {
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line);
  font-size: .9rem;
}
.day-detail p { margin-top: 4px; color: var(--muted); }
.route-ok, .route-errors {
  border-radius: 12px; padding: 11px 13px; font-size: .86rem; margin-bottom: 12px;
}
.route-ok { background: #E6F6EE; border: 1px solid #CDEBDC; color: #13734B; }
.route-errors { background: #FFF4E0; border: 1px solid #F2D1AA; color: #8A4A00; }
.route-errors ul { margin: 6px 0 0 18px; }
/* Amber is a note; this one blocks the save, so it is red. */
.room-errors { background: #FEF3F2; border-color: #FDA29B; color: #B42318; }
.quick-summary { position: sticky; top: 84px; }
.quick-summary-card { background: linear-gradient(160deg,var(--accent),#42474f); color: #fff; border-radius: 14px; padding: 20px; box-shadow: var(--shadow); }
.quick-total { font-size: 2.25rem; font-weight: 800; margin: 4px 0; }
.quick-price-line { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid rgba(255,255,255,.14); font-size: .9rem; }
.quick-price-line span { opacity: .78; }
.quick-price-line b { text-align: right; }
/* Net/sell/margin in the light pricing card; .quick-price-line above is
   dressed for the dark summary card and reads as invisible here. */
.net-sell { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.net-sell .quick-price-line { border-bottom: 1px solid var(--line); font-size: .88rem; }
.net-sell .quick-price-line:last-of-type { border-bottom: 0; }
.net-sell .quick-price-line span { opacity: 1; color: var(--muted); }
.net-sell .quick-price-line b { color: var(--ink); font-variant-numeric: tabular-nums; }
.net-sell .is-margin b { color: #067647; }
.net-sell .is-loss b { color: #B42318; }

/* Bill-in currency + the agent's rate, above the net/sell block. */
.sell-cur { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.sell-cur .field { margin: 0; }

/* Quiet money problems, said out loud: a zero add-on rate, a mistyped tax. */
.money-warn { margin-top: 10px; padding: 10px 12px; border-radius: 10px; font-size: .84rem;
  line-height: 1.5; background: #FFF4ED; border: 1px solid #F5CDB0; color: #8A4B18; }
.money-warn p { margin: 0; }
.money-warn p + p { margin-top: 8px; }

/* Rate-request strip: waiting is information, an answered net is an action. */
.rate-req { margin-top: 10px; padding: 10px 12px; border-radius: 10px; font-size: .85rem; line-height: 1.45; }
.rate-req.is-pending { background: #FFF8E6; border: 1px solid #F2DCA7; color: #7A5A12; display: flex; gap: 8px; align-items: flex-start; }
.rate-req.is-answered { background: #ECFDF3; border: 1px solid #ABEFC6; color: #067647;
  display: flex; gap: 10px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.rate-req.is-answered b { color: #054F31; }

.quick-hotel-list { padding: 4px 2px 0; }
.quick-stay-row { display: grid; grid-template-columns: 1.1fr .7fr 1.2fr 1fr; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); font-size: .9rem; align-items: start; }
.quick-stay-row span { color: var(--muted); }
.quick-stay-edit-list, .quick-day-edit-list { display: grid; gap: 10px; }
.quick-stay-edit-row, .quick-day-edit-row {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  padding: 12px;
}
.quick-day-edit-row.is-auto { background: #F7FBFC; border-style: dashed; }
/* The day the route error is about, marked where the agent is typing. */
.quick-day-edit-row.is-offroute { border-color: var(--danger); background: #FFF7F6; }
.quick-day-edit-row.is-offroute input[data-f="stay"] { border-color: var(--danger); }
.quick-edit-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.quick-edit-head .idx {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  flex: none;
  border-radius: 8px;
  background: #E8F6FA;
  color: var(--brand-ink);
  font-weight: 700;
  font-size: .82rem;
}
.quick-edit-head b { min-width: 0; overflow-wrap: anywhere; }
/* auto-fit, not fixed tracks: the old five- and four-track grids had a combined
   minimum of 600–810px, which no longer fits once the summary rail takes 320px
   beside them — the rows overflowed the card and pushed the page sideways.
   The fields now reflow to as many per row as the column can hold. */
.quick-stay-edit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  align-items: end;
}
.quick-stay-edit-grid .meal { grid-column: 1 / -1; }
.quick-day-edit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  align-items: end;
}
.quick-day-edit-grid .desc { grid-column: 1 / -1; }
.quick-day-edit-grid .desc textarea { min-height: 62px; }
.quick-itinerary-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.quick-table-label {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 14px 0 8px;
  color: var(--muted);
  font-size: .82rem;
  font-weight: 600;
}
@media (max-width: 980px) {
  .quick-layout { grid-template-columns: 1fr; }
  .quick-summary { position: static; }
}
@media (max-width: 720px) {
  .quick-stay-row { grid-template-columns: 1fr; gap: 3px; }
  .quick-total { font-size: 1.9rem; }
  .quick-edit-head { flex-wrap: wrap; }
}

/* selectable option cards */
.opt-grid { display: grid; gap: 14px; }
.opt-grid.cols-2 { grid-template-columns: 1fr 1fr; }
.opt-grid.cols-3 { grid-template-columns: repeat(3,1fr); }
.opt-grid.cols-4 { grid-template-columns: repeat(4,1fr); }
@media (max-width: 760px) { .opt-grid.cols-2, .opt-grid.cols-3, .opt-grid.cols-4 { grid-template-columns: 1fr; } }

.opt {
  position: relative; text-align: left; background: var(--surface); border: 2px solid var(--line);
  border-radius: var(--radius); padding: 18px; cursor: pointer; transition: .18s; font: inherit; color: inherit;
}
.opt:hover { border-color: #9FD6E8; transform: translateY(-2px); box-shadow: var(--shadow); }
.opt.selected { border-color: var(--brand); background: #FFFaf4; box-shadow: var(--ring); }
.opt.selected::after { content: '\f00c'; font-family: 'Font Awesome 6 Free'; font-weight: 900; position: absolute; top: 12px; right: 12px; width: 24px; height: 24px;
  border-radius: 50%; background: var(--brand); color: #fff; display: grid; place-items: center; font-size: .8rem; }
.opt h4 { font-size: 1.05rem; }
.opt .meta { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* package card */
.pkg-card .thumb { height: 132px; border-radius: 12px; margin: -18px -18px 14px; position: relative; overflow: hidden;
  background: linear-gradient(135deg, var(--accent), #4b5059); }
.pkg-card .thumb .glow { position: absolute; inset: 0; background:
  radial-gradient(120px 90px at 78% 20%, rgba(253,185,19,.6), transparent 70%),
  radial-gradient(160px 120px at 20% 90%, rgba(37,168,203,.45), transparent 70%); }
.pkg-card .thumb .dur { position: absolute; bottom: 10px; left: 12px; color: #fff; font-weight: 700; font-size: .82rem;
  background: rgba(0,0,0,.28); padding: 4px 10px; border-radius: 999px; backdrop-filter: blur(4px); }
.pkg-card .price { font-weight: 700; color: var(--brand-ink); }

/* category cards (hotel tiers) */
.tier { display: grid; gap: 6px; }
.tier .stars { color: var(--brand-2); letter-spacing: 2px; }

/* hotel plan list in wizard summary */
.hotel-line { display: grid; grid-template-columns: 54px 1fr auto; gap: 12px; align-items: center;
  padding: 12px 0; border-bottom: 1px dashed var(--line); }
.hotel-line:last-child { border-bottom: 0; }
.night-pill { background: #E8F6FA; color: var(--brand-ink); font-weight: 700; font-size: .78rem; padding: 6px; border-radius: 8px; text-align: center; }
.thumb-mini { width: 100%; height: 100%; border-radius: 10px; background: linear-gradient(135deg,#DCEAF0,#F2F9FC); display:grid; place-items:center; color: var(--brand-ink); font-weight:700; }

/* live preview panel */
.preview { position: sticky; top: 84px; }
.preview .doc { border-radius: 14px; overflow: hidden; border: 1px solid var(--line); box-shadow: var(--shadow); background: #fff; }
.preview .doc .cover { padding: 20px; color: #fff; background: linear-gradient(135deg, var(--accent), #444952); position: relative; }
.preview .doc .cover .swirl { position:absolute; inset:0; background: radial-gradient(150px 120px at 85% 10%, rgba(253,185,19,.5), transparent 65%); }
.preview .doc .body { padding: 18px; }

/* =============================================================================
   DASHBOARD / TABLES
   ========================================================================== */
/* Vertical only. `.page` is always used together with `.container`, and the
   shorthand `padding: 30px 0 60px` here — later in the file, same specificity —
   was quietly cancelling that container's `0 22px`. Every screen's text then sat
   flush against both edges of a phone, headings clipped at x=0. */
.page { padding-top: 30px; padding-bottom: 60px; }
/* 22px of each side is a lot of a 360px screen; give the content room to breathe. */
@media (max-width: 560px) { .container { padding-left: 16px; padding-right: 16px; } }
/* minmax(0,1fr), not 1fr: a bare 1fr floors at the content's min-content width,
   so a card with a long label refused to shrink and pushed the row past the
   viewport — which scrolls the whole page sideways and clips everything else. */
.stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 900px){ .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 420px){ .stat-grid { grid-template-columns: minmax(0, 1fr); } }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; box-shadow: var(--shadow); }
.stat .n { font-size: 2rem; font-weight: 700; color: var(--brand-ink); letter-spacing: -.03em; }
.stat .l { color: var(--muted); font-size: .85rem; font-weight: 500; }
/* Tiles that answer "who do I ring first" are links into the quotations desk
   with that view already applied — they were buttons filtering a table on the
   dashboard, and that table lives on its own page now. Styled for both. */
.stat-action { display: block; text-align: left; font: inherit; cursor: pointer; width: 100%;
               text-decoration: none; color: inherit; }
.stat-action:hover, .stat-action:focus-visible { border-color: var(--brand); }
.stat-action.is-on { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand) inset; }
.stat-action.is-urgent .n { color: var(--danger); }

/* A Trip ID is a handle people read out and file by, so it is set apart from
   the quote ref under it rather than being one more link in a row of them. */
.tripid { text-decoration: none; color: var(--brand-ink); letter-spacing: .02em; }
.tripid:hover { text-decoration: underline; }

/* Skeleton row. A table that keeps its height while it reloads does not throw
   the pager and everything below it down the page on every keystroke — which is
   the actual complaint behind "the filter feels janky". */
.skel {
  display: inline-block; height: 11px; border-radius: 6px; vertical-align: middle;
  background: linear-gradient(90deg, var(--line) 25%, #EFF4F6 37%, var(--line) 63%);
  background-size: 400% 100%; animation: skel 1.3s ease-in-out infinite;
}
@keyframes skel { 0% { background-position: 100% 50% } 100% { background-position: 0 50% } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none } }

/* Phones: a data table stops pretending to be a table.
   `.table-wrap` scrolls sideways, which works but means half the row is off
   screen and nobody scrolls it. Below 640px each row stacks into a card and
   every cell carries its own column name from data-label — set it on the <td>
   where a column is not self-explanatory, and the header row disappears. */
@media (max-width: 640px) {
  .table-wrap { border-radius: var(--radius); overflow: visible; box-shadow: none; border: 0; background: transparent; }
  table.data, table.data tbody, table.data tr, table.data td { display: block; width: 100%; }
  table.data thead { display: none; }
  table.data tr {
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: var(--shadow); margin-bottom: 12px; padding: 6px 4px;
  }
  table.data tr:hover td { background: transparent; }
  table.data td {
    border-bottom: 1px solid var(--line); padding: 10px 12px;
    display: flex; gap: 12px; align-items: baseline; justify-content: space-between;
    text-align: right !important;
  }
  table.data td:last-child { border-bottom: 0; }
  table.data td::before {
    content: attr(data-label); flex: none; text-align: left;
    font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--muted); font-weight: 700;
  }
  /* A cell with no label is the row's title or its actions — full width. */
  table.data td:not([data-label]) { justify-content: flex-start; text-align: left !important; }
}

table.data { width: 100%; border-collapse: collapse; }
table.data th { text-align: left; font-size: .76rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
  padding: 12px 14px; border-bottom: 2px solid var(--line); }
table.data td { padding: 14px; border-bottom: 1px solid var(--line); font-size: .92rem; vertical-align: middle; }
table.data tr:hover td { background: #FFFaf4; }
.table-wrap { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--line); background: var(--surface); box-shadow: var(--shadow); }
/* A control in a table cell sizes to itself. The base rule gives every input and
   select width:100%, which is right in a form and wrong here: the Leads status
   dropdown became as wide as its column and clipped "Contacted" down to the
   chevron, so the column read as an empty orange box. `select.statusSel` already
   said width:auto — but only for the two callers that remembered the class, and
   leads.js was not one of them. Said once, where every table gets it. */
table.data td select,
table.data td input:where(:not([type="checkbox"]):not([type="radio"])) { width: auto; max-width: 100%; }

/* ------------------------------------------------------------- pager ------ */
/* One bar under every long list. See pagerHtml() in ui.js — the markup is
   built there so the four screens that page cannot drift apart. */
.pager { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 16px; }
.pager .pager-of { margin-left: auto; }
.pager button[disabled] { opacity: .45; cursor: default; }
@media (max-width: 560px) { .pager .pager-of { margin-left: 0; width: 100%; } }

.empty { text-align: center; padding: 60px 20px; color: var(--muted); }
.empty .big { font-size: 2.4rem; margin-bottom: 8px; }

/* Edit surface (branding / hotels / vehicles / …): a centred modal. The class is
   still .drawer because every page builds one, but it opens in the middle of the
   screen rather than sliding in from the edge. The inline max-width each caller
   sets (480–900px) still controls how wide its modal is. */
.drawer-bg { position: fixed; inset: 0; background: rgba(30,22,14,.5); z-index: 260; animation: slideIn .2s;
  backdrop-filter: blur(2px); }
/* Centred with inset+margin:auto rather than a translate, so the open animation
   never has to hand `transform` back — animating it left the box stuck off-centre. */
.drawer { position: fixed; inset: 0; margin: auto;
  /* width from the viewport, capped by max-width — so a caller setting
     style="max-width:900px" (the calculator's rate grids) gets a wider modal. */
  width: 94vw; max-width: 560px; height: max-content; max-height: 88vh;
  background: var(--surface); border-radius: var(--radius);
  z-index: 261; box-shadow: 0 30px 80px -20px rgba(0,0,0,.45); padding: 26px; overflow-y: auto;
  animation: modalIn .18s ease-out; }
@keyframes modalIn { from { opacity: 0 } to { opacity: 1 } }
/* The title + Close stay put while the body scrolls. */
.drawer > .spread:first-of-type { position: sticky; top: -26px; z-index: 3; background: var(--surface);
  margin: -26px -26px 0; padding: 20px 26px 14px; border-bottom: 1px solid var(--line); }
/* Phones: the modal goes full-screen — a centred box with margins wastes the
   little space there is, and long forms need every pixel. */
@media (max-width: 720px) {
  /* Pin to all four edges rather than sizing by percentage — a fixed element's
     percentage resolves against the initial containing block, which overflows on
     zoomed mobile viewports and gives the whole page a sideways scroll. */
  .drawer { inset: 0; margin: 0; width: auto; max-width: none !important;
    height: 100dvh; max-height: none; border-radius: 0; padding: 0 14px 22px; }
  .drawer > .spread:first-of-type { top: 0; margin: 0 -14px; padding: 14px; }
  .drawer > .spread:first-of-type h2 { font-size: 1.05rem; }
  /* Controls sized by their content (long option labels, inline width:auto)
     must never push the page wider than the screen — that sideways scroll is
     what pushed half the drawer off-screen on phones. */
  input, select, textarea, .btn { max-width: 100%; }
}

/* tabs (admin) */
.tabbar { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 22px; border-bottom: 1px solid var(--line); }
.tabbar button { border: 0; background: none; font: inherit; font-weight: 600; color: var(--muted); padding: 11px 16px;
  cursor: pointer; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.tabbar button.active { color: var(--brand-ink); border-bottom-color: var(--brand); }
.swatch { width: 22px; height: 22px; border-radius: 6px; border: 1px solid rgba(0,0,0,.1); display:inline-block; vertical-align:middle; }

/* =============================================================================
   INLINE EDITORS (wizard: editable stays / itinerary / vehicles / pricing)
   ========================================================================== */
.edit-row { background: var(--surface); border: 1.5px solid var(--line); border-radius: 14px; padding: 14px; margin-bottom: 12px; }
.edit-row .rowtop { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.edit-row .rowtop .idx { width: 26px; height: 26px; border-radius: 8px; background: #E8F6FA; color: var(--brand-ink); font-weight: 700; display: grid; place-items: center; font-size: .8rem; flex: none; }
.edit-row .rowtop .grow { font-weight: 600; }
.icon-btn { background: var(--surface); border: 1.5px solid var(--line); color: var(--muted); width: 32px; height: 32px; border-radius: 9px; cursor: pointer; font-size: .85rem; transition: .15s; }
.icon-btn:hover { border-color: var(--brand); color: var(--brand-ink); }
.icon-btn.danger:hover { border-color: var(--danger); color: var(--danger); }
input.mini, select.mini, textarea.mini { padding: 8px 10px; font-size: .88rem; border-radius: 8px; }
.field-mini > span { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: 4px; display: block; }
.grid-nights { display: grid; grid-template-columns: 2fr 90px 2fr 1.4fr; gap: 10px; }
.grid-day { display: grid; grid-template-columns: 90px 1fr 130px; gap: 10px; }
@media (max-width: 760px){ .grid-nights, .grid-day { grid-template-columns: 1fr; } }
.addbar { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin: 10px 0 6px; }
.stay-rate { margin-top: 10px; padding: 8px 10px; border-radius: 9px; background: #F8FAFC; color: var(--muted); font-size: .78rem; }
.stay-rate i { color: var(--brand-ink); margin-right: 6px; }

/* pricing breakdown */
.breakdown { display: grid; gap: 8px; }
.breakdown .li { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px dashed var(--line); }
.breakdown .li.tot { border-bottom: 0; border-top: 2px solid var(--line); font-weight: 700; font-size: 1.15rem; padding-top: 12px; }
.margin-note { background: #E6F6EE; border: 1px solid #CDEBDC; color: #12805a; border-radius: 10px; padding: 10px 14px; font-size: .84rem; margin-top: 12px; }
.veh-cap { font-size: .78rem; color: var(--muted); }
.hotel-price-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: start; padding: 8px 0; border-bottom: 1px dashed var(--line); font-size: .85rem; }
.hotel-price-row:last-child { border-bottom: 0; }
@media (max-width: 680px){ .hotel-price-row { grid-template-columns: 1fr; } .hotel-price-row > div:last-child { text-align: left !important; } }

/* upload button */
.uploader { display: inline-flex; align-items: center; gap: 8px; }
.thumb-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.thumb-row .t { position: relative; width: 72px; height: 56px; border-radius: 8px; overflow: hidden; border: 1px solid var(--line); background: #F2F9FC; }
.thumb-row .t img { width: 100%; height: 100%; object-fit: cover; }
.thumb-row .t button { position: absolute; top: 2px; right: 2px; background: rgba(0,0,0,.55); color: #fff; border: 0; border-radius: 6px; width: 20px; height: 20px; cursor: pointer; font-size: .7rem; }

/* Photos grouped by what they show. The tile grows inside a group because it
   carries its own category select underneath — 72x56 with a dropdown under it
   is a dropdown squeezed to nothing. Outside a group the small tile stays as
   it was, so the package and quote pages are untouched. */
.photo-upload { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; }
.photo-upload select, .photo-upload input { padding: 6px 8px; font-size: .82rem; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; color: var(--ink); }
.photo-upload input { min-width: 150px; }
.photo-group { margin-top: 12px; }
.photo-group .ph-head { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: .82rem;
  color: var(--brand-ink); text-transform: uppercase; letter-spacing: .04em;
  border-bottom: 1px solid var(--line); padding-bottom: 4px; margin-bottom: 8px; }
.photo-group .ph-head .muted { font-weight: 400; text-transform: none; letter-spacing: 0; }
.photo-group .thumb-row .t { width: 118px; height: auto; border-radius: 10px; overflow: visible; border: 0; background: none; }
.photo-group .thumb-row .t img { width: 118px; height: 84px; border-radius: 10px; border: 1px solid var(--line); }
.photo-group .thumb-row .t select.ph-tag { width: 118px; margin-top: 4px; padding: 3px 4px; font-size: .7rem;
  border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink); }
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px,1fr)); gap: 14px; }
.media-card { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; background: var(--surface); }
.media-card .ph { height: 110px; background: #F2F9FC; display: grid; place-items: center; color: var(--brand-ink); }
.media-card .ph img { width: 100%; height: 100%; object-fit: cover; }
.media-card .mc-body { padding: 8px 10px; }

/* =============================================================================
   B2C STOREFRONT (public, customer-facing)
   ========================================================================== */
.b2c-hero { position: relative; overflow: hidden; border-radius: 0 0 28px 28px;
  background: linear-gradient(135deg, var(--accent), #454b54); color: #fff; padding: 54px 0 60px; }
.b2c-hero::after { content: ''; position: absolute; inset: 0; background:
  radial-gradient(420px 260px at 85% 0%, rgba(253,185,19,.35), transparent 60%),
  radial-gradient(460px 300px at 8% 100%, rgba(37,168,203,.30), transparent 60%); }
.b2c-hero .inner { position: relative; z-index: 1; }
.b2c-hero h1 { font-size: clamp(2rem, 5vw, 3.3rem); letter-spacing: -.03em; max-width: 18ch; }
.b2c-hero p { color: rgba(255,255,255,.85); max-width: 46ch; margin-top: 12px; font-size: 1.05rem; }

.pkg-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
@media (max-width: 900px){ .pkg-grid { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 620px){ .pkg-grid { grid-template-columns: 1fr; } }
.pkg-tile { background: var(--surface); border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
  box-shadow: var(--shadow); transition: transform .18s, box-shadow .18s; display: flex; flex-direction: column; }
.pkg-tile:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
/* Three lines and an ellipsis. Unclamped, summaries ran 61px to 163px and gave
   the grid a 123px height spread — the longest is 318 characters. The tile links
   to the package, so the card is the teaser and View is the "read more". */
.pkg-tile .bd p {
  display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3;
  -webkit-box-orient: vertical; overflow: hidden;
}
.pkg-tile .ph { height: 190px; position: relative; background: linear-gradient(135deg,var(--accent),#4b5059); }
.pkg-tile .ph img { width: 100%; height: 100%; object-fit: cover; }
.pkg-tile .ph .cat { position: absolute; top: 12px; left: 12px; background: rgba(255,255,255,.92); color: var(--brand-ink);
  font-weight: 700; font-size: .72rem; padding: 5px 11px; border-radius: 999px; }
.pkg-tile .ph .dur { position: absolute; bottom: 12px; right: 12px; background: rgba(0,0,0,.35); color: #fff;
  font-weight: 600; font-size: .76rem; padding: 4px 10px; border-radius: 999px; backdrop-filter: blur(4px); }
.pkg-tile .bd { padding: 18px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.pkg-tile h3 { font-size: 1.18rem; }
.pkg-tile .pp { margin-top: auto; }
.pkg-tile .pp b { color: var(--brand-ink); font-size: 1.25rem; }
.pkg-tile .pp span { color: var(--muted); font-size: .82rem; }

.b2c-detail-hero { border-radius: 22px; overflow: hidden; position: relative; min-height: 360px;
  background: linear-gradient(135deg,var(--accent),#454b54); color: #fff; display: flex; align-items: flex-end; padding: 30px; }
.b2c-detail-hero img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .55; }
.b2c-detail-hero .scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(0,0,0,.65), transparent 60%); }
.b2c-detail-hero .in { position: relative; z-index: 1; }
.b2c-price-card { background: var(--surface); border: 1px solid var(--line); border-radius: 18px; padding: 22px;
  box-shadow: var(--shadow); position: sticky; top: 84px; }
.b2c-price-card .big { font-size: 2.1rem; font-weight: 800; color: var(--brand-ink); letter-spacing: -.02em; }
.wa { background: #25D366 !important; }
.b2c-foot { background: var(--accent); color: #fff; padding: 34px 0; margin-top: 50px; }
.b2c-foot a { color: #fff; opacity: .85; }
.b2c-partners { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.b2c-partners span { font-size: .78rem; opacity: .7; }
@media (max-width: 820px){ .b2c-cols { grid-template-columns: 1fr !important; } .b2c-price-card { position: static !important; } }
.edit-row.blank-row { border-style: dashed; background: #F7FBFC; }
.edit-row.blank-row .idx { background: #BFE4F0; color: var(--brand-ink); }

/* ---------------------------------------------------- admin enquiry inbox -- */
/* Three panes like a mail client: accounts, list, reading pane. Collapses to a
   single column on narrow screens so the list stays usable on a phone. */
.inbox-wrap { display: grid; grid-template-columns: 190px minmax(280px, 360px) 1fr; gap: 14px; align-items: start; }
.inbox-list { max-height: 70vh; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.inbox-row {
  text-align: left; width: 100%; background: #fff; border: 1px solid var(--line);
  border-radius: 12px; padding: 10px 12px; cursor: pointer; font: inherit;
  border-left: 3px solid transparent;
}
.inbox-row:hover { border-color: var(--brand); }
.inbox-row.unread { border-left-color: var(--brand); background: #FFFBF6; }
.inbox-row.unread .who, .inbox-row.unread .subj { font-weight: 700; }
.inbox-row.on { border-color: var(--brand); box-shadow: 0 0 0 2px rgba(37,168,203,.14); }
.inbox-row .subj { margin-top: 2px; }
.inbox-row .prev { margin-top: 3px; }
.inbox-read { padding: 18px; min-height: 240px; }
.inbox-body {
  white-space: pre-wrap; word-break: break-word; font: inherit; font-size: .92rem;
  line-height: 1.6; background: #FAFAFB; border: 1px solid var(--line);
  border-radius: 10px; padding: 14px; margin: 0; max-height: 52vh; overflow-y: auto;
}
@media (max-width: 900px) {
  .inbox-wrap { grid-template-columns: 1fr; }
  .inbox-list { max-height: none; }
}

/* The lead's conversation: their mail and ours, one column, newest first. Sides
   are told apart by the tint and the edge, not by left/right alignment — a
   chat-bubble layout wastes half the width of a drawer on a mail thread. */
.mail-thread { display: flex; flex-direction: column; gap: 10px; max-height: 46vh; overflow-y: auto; }
.mail-msg {
  border: 1px solid var(--line); border-left: 3px solid var(--line);
  border-radius: 10px; padding: 10px 12px; background: #fff;
}
.mail-msg.them { border-left-color: #F59E0B; background: #FFFCF5; }
.mail-msg.us   { border-left-color: var(--brand); background: #F6FCFD; }
.mail-msg.draft { border-style: dashed; background: #FAFAFB; }
.mail-msg .subj { margin-top: 3px; }
.mail-msg .prev { margin-top: 3px; line-height: 1.5; }

/* ===================================================== brochure document ===
   The photo-led client document (brochureQuoteDoc in brochure.js). Lives in the
   shared stylesheet because pkgLocalStyles() inlines this file into the printed
   PDF and Word build — screen and paper stay one design. Tables and blocks
   only: Word ignores flex, so nothing here depends on it. */
.bd-doc { position: relative; color: #1a1a1a; font-size: 10.5pt; line-height: 1.55; }
.bd-doc p { margin: 0 0 9px; }

/* Diagonal trip-ref watermark, behind everything, never on the cover. */
.bd-water {
  position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  transform: rotate(-28deg) scale(1.6); transform-origin: center;
  font-size: 15pt; font-weight: 700; color: rgba(120,120,120,.10);
  word-spacing: 14px; line-height: 2.6; letter-spacing: 1px;
}
.bd-doc > section, .bd-doc > .bd-foot { position: relative; z-index: 1; }

/* ---- cover ---- */
.bd-cover { position: relative; overflow: hidden; page-break-after: always; background: #2b2b2b; }
.bd-cover-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .95; }
.bd-cover-inner { position: relative; text-align: center; padding: 26px 20px 0; }
.bd-cover-logo { height: 44px; margin: 0 auto 16px; display: block; }
.bd-cover-brand { color: #fff; font-size: 20pt; font-weight: 800; margin-bottom: 16px; text-shadow: 0 2px 10px rgba(0,0,0,.5); }
.bd-strip { background: #fff; padding: 6px; border-radius: 4px; display: table; margin: 0 auto; }
.bd-strip-img { width: 92px; height: 200px; object-fit: cover; display: inline-block; margin: 0 2px; vertical-align: top; }
.bd-cover-title {
  margin-top: -18px; font-size: 46pt; font-weight: 900; letter-spacing: -1px;
  text-transform: uppercase; color: var(--brand, #25A8CB);
  text-shadow: 0 2px 14px rgba(0,0,0,.35);
}
.bd-cover-sub { color: #fff; font-weight: 700; letter-spacing: 3px; font-size: 10pt; text-shadow: 0 1px 6px rgba(0,0,0,.6); }
.bd-cover-bar { position: relative; margin: 22px 0 0; background: #3a3a3a; color: #fff; display: table; width: 100%; }
.bd-cover-cell { display: table-cell; padding: 14px 18px; vertical-align: top; font-size: 9.5pt; }
.bd-cover-cell + .bd-cover-cell { border-left: 1px solid rgba(255,255,255,.18); width: 38%; }
.bd-trip b { color: var(--brand, #25A8CB); }
.bd-who { margin-top: 2px; }
.bd-dates { margin-top: 10px; border-top: 1px dotted rgba(255,255,255,.35); padding-top: 8px; }
.bd-dates span + span { margin-left: 18px; }
.bd-consult-l { color: #d8d8d8; }
.bd-consult-n { font-weight: 700; margin: 3px 0 1px; }

/* ---- section heading: pink bar, crimson stripe ---- */
.bd-sec {
  position: relative; background: #FBE3EF; color: #B0286A; text-align: center;
  font-size: 13pt; font-weight: 700; margin: 0 0 16px; padding: 11px 14px; border-radius: 4px;
}
.bd-sec-bar { position: absolute; left: -4px; top: 4px; bottom: 4px; width: 6px; background: #C2185B; border-radius: 2px; }
.bd-page { page-break-before: always; padding-top: 4px; }
.bd-h3 { color: #B0286A; font-size: 11pt; margin: 14px 0 6px; }

/* ---- greeting meta row ---- */
.bd-meta { display: table; width: 100%; margin: 18px 0 22px; border-spacing: 0; }
.bd-meta > div { display: table-cell; padding: 0 14px 10px 0; vertical-align: top; }
.bd-meta-k { font-size: 8pt; letter-spacing: .08em; text-transform: uppercase; color: #7a7a7a; font-weight: 700; }
.bd-meta-v { font-size: 12pt; font-weight: 700; margin-top: 2px; }
.bd-total { border: 1px solid #e3e3e3; border-radius: 6px; overflow: hidden; }
.bd-total-h { background: #fafafa; border-bottom: 1px solid #e9e9e9; padding: 9px 14px; font-weight: 700; }
.bd-total-b { padding: 14px; }
.bd-total-n { font-size: 22pt; font-weight: 800; }
.bd-total-note { color: #6b6b6b; font-size: 9pt; margin-top: 2px; }

/* ---- hotel cards ---- */
.bd-card {
  border: 1px solid #e6e6e6; border-radius: 8px; padding: 14px 16px; margin-bottom: 14px;
  display: table; width: 100%; page-break-inside: avoid; background: #fff;
}
.bd-card-l { display: table-cell; vertical-align: top; }
.bd-card-r { display: table-cell; vertical-align: top; width: 250px; padding-left: 14px; }
.bd-shot { width: 118px; height: 78px; object-fit: cover; border-radius: 3px; margin: 0 2px 4px 0; }
.bd-nb {
  display: inline-block; background: #FBE3EF; color: #B0286A; font-weight: 700;
  border-radius: 5px; padding: 2px 8px; margin-right: 5px; font-size: 10pt;
}
.bd-nb-t { font-size: 11pt; }
.bd-nb-t b { font-size: 13pt; }
.bd-hotel { color: #C2185B; font-size: 13pt; font-weight: 700; margin: 8px 0 2px; }
.bd-hotel-alt { font-weight: 700; }
.bd-sm { color: #6b6b6b; font-size: 9pt; }
.bd-kv { display: table; width: 100%; margin-top: 10px; }
.bd-kv > div { display: table-cell; padding-right: 18px; vertical-align: top; }
.bd-kv-k { font-size: 8pt; letter-spacing: .08em; text-transform: uppercase; color: #7a7a7a; font-weight: 700; }
.bd-kv-v { font-weight: 700; }
.bd-sim { color: #C2185B; font-weight: 700; margin-top: 10px; }

/* ---- day blocks ---- */
.bd-day { display: table; width: 100%; margin-bottom: 22px; page-break-inside: avoid; }
.bd-day-badge {
  display: table-cell; width: 74px; vertical-align: top;
  border: 1px solid #F2C6DC; border-radius: 8px; text-align: center; padding: 10px 4px; background: #fff;
}
.bd-day-n { display: block; font-size: 17pt; font-weight: 800; color: #C2185B; }
.bd-day-l { display: block; font-size: 8.5pt; color: #7a7a7a; }
.bd-day-body { display: table-cell; vertical-align: top; padding-left: 16px; }
.bd-day-date { font-weight: 700; font-size: 9.5pt; }
.bd-day-title { color: #C2185B; font-size: 13pt; font-weight: 700; margin: 2px 0 3px; }
.bd-day-img { width: 100%; max-height: 300px; object-fit: cover; border-radius: 4px; margin: 10px 0 12px; }

/* ---- tables + lists ---- */
.bd-tbl { width: 100%; border-collapse: collapse; font-size: 10pt; }
.bd-tbl caption.bd-cap { text-align: left; font-weight: 700; padding: 0 0 8px; }
.bd-tbl th, .bd-tbl td { border: 1px solid #e6e6e6; padding: 9px 12px; text-align: left; vertical-align: top; }
.bd-tbl th { background: #fafafa; font-weight: 700; }
.bd-td-day { width: 130px; }
.bd-ul { margin: 0; padding-left: 18px; }
.bd-ul li { margin-bottom: 4px; }
.bd-two { display: table; width: 100%; }
.bd-two > div { display: table-cell; width: 50%; vertical-align: top; padding-right: 16px; }

/* ---- footer ---- */
.bd-foot { margin-top: 26px; border-top: 2px solid var(--brand, #25A8CB); padding-top: 10px; text-align: center; font-size: 9pt; }
.bd-foot-a { color: #6b6b6b; margin-top: 3px; }

@media print { .bd-cover { min-height: 96vh; } }

/* An agent's saved document renders in an iframe so its own stylesheet — which
   includes the print rules — cannot leak into this page's chrome. */
.pkg-saved-doc { width: 100%; border: 0; display: block; min-height: 70vh; }

/* ================================================== final A4 preview step ==
   Full-screen last look before printing: the document at true A4 width, still
   editable. The sheet is exactly 210mm so the page guides drawn inside the
   frame line up with real paper. */
#pkgA4 { position: fixed; inset: 0; z-index: 200; background: #EFF1F3; display: flex; flex-direction: column; }
#pkgA4 .a4-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; background: var(--surface); border-bottom: 1px solid var(--line);
}
#pkgA4 .a4-title { flex: 1; min-width: 160px; font-weight: 700; }
#pkgA4 .a4-state { display: block; font-weight: 400; font-size: .78rem; color: var(--muted); }
#pkgA4 .a4-pages { font-size: .82rem; color: var(--muted); white-space: nowrap; }
#pkgA4 .a4-hint { background: #F7FBFC; border-bottom: 1px solid #BFE4F0; padding: 8px 14px; font-size: .85rem; color: var(--brand-ink); }
#pkgA4 .a4-scroll { flex: 1; overflow: auto; padding: 20px 12px 60px; }
#pkgA4 .a4-sheet {
  width: 210mm; margin: 0 auto; background: #fff;
  box-shadow: 0 6px 30px rgba(16,24,40,.18);
}
#pkgA4 .a4-sheet iframe { width: 100%; border: 0; display: block; min-height: 297mm; }
/* No media-query zoom here: pkgA4ApplyZoom() sizes the sheet from the space
   actually available, and a CSS zoom underneath it made the first tap of a zoom
   button cancel the auto-fit and push the page off the side. */
#pkgA4 .a4-zoom { font-size: .78rem; color: var(--muted); min-width: 44px; text-align: center; }
@media print { #pkgA4 { position: static; background: #fff; } #pkgA4 .a4-bar, #pkgA4 .a4-hint { display: none; } }

/* Page-boundary marks for the A4 step. Drawn in THIS document over the preview
   frame — inside it they sat behind the document's own table backgrounds. */
#pkgA4 .a4-sheet { position: relative; }
#pkgA4 .a4-cut {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 2px dashed #C2185B; pointer-events: none; z-index: 5;
}
#pkgA4 .a4-cut::after {
  content: attr(data-label); position: absolute; right: 0; top: 2px;
  background: #C2185B; color: #fff; font: 600 10px/1.7 sans-serif;
  padding: 1px 8px; border-radius: 0 0 6px 6px; white-space: nowrap;
}
#pkgA4 .a4-cut[data-forced] { border-top-color: #0F5F5A; }
#pkgA4 .a4-cut[data-forced]::after { background: #0F5F5A; content: attr(data-label); }
@media print { #pkgA4 .a4-cut { display: none !important; } }

/* ---- seasonal rate sheet (calculator drawer + hotels page) --------------
   Shared because both screens edit the same thing and a supplier's sheet has
   one shape; two copies would drift. */
/* The seasonal rate sheet, laid out the way a supplier writes one: room types
   down the side, each season across the top, EP/CP/MAP under every season.
   A real table because the season headings genuinely span their plan columns —
   colspan does that honestly and a CSS grid would have to fake it. */
.season-sheet-scroll { overflow-x:auto; }
.season-sheet { border-collapse:collapse; font-size:.78rem; }
.season-sheet th, .season-sheet td { border:1px solid var(--line); padding:3px 4px; text-align:center; }
.season-sheet thead th.seas { background:#2f6fb3; color:#fff; min-width:210px; }
.season-sheet thead tr.plans th { background:#e8eef5; font-weight:700; width:62px; }
.season-sheet th.rt { background:#f3f4f6; text-align:left; white-space:nowrap; font-weight:600; position:sticky; left:0; z-index:1; }
.season-sheet thead th.seas input { width:100%; padding:3px 5px; font-size:.74rem; margin-bottom:2px; }
.season-sheet thead th.seas .dates { display:flex; gap:3px; align-items:center; margin-bottom:2px; }
.season-sheet thead th.seas .dates input { flex:1; min-width:0; }
.season-sheet tbody input { width:100%; padding:4px 3px; font-size:.78rem; text-align:center; border-color:transparent; background:transparent; }
.season-sheet tbody input:focus { border-color:var(--brand); background:#fff; }
.season-sheet tbody input[type=number] { -moz-appearance:textfield; appearance:textfield; }
.season-sheet tbody input[type=number]::-webkit-outer-spin-button,
.season-sheet tbody input[type=number]::-webkit-inner-spin-button { -webkit-appearance:none; margin:0; }
/* The season actually being applied to the travel date. */
.season-sheet td.season-active { background:#eaf7ee; }
/* The All year column: the hotel's own rates, distinct from a dated season. */
.season-sheet thead th.seas.allyear { background: #4b5563; min-width: 120px; vertical-align: top; }
.season-sheet thead th.seas.allyear .sub { display: block; font-weight: 400; font-size: .62rem; opacity: .8; margin-top: 2px; }
.season-sheet td.allyear { background: #fafafa; }
/* The probe's answer: the same sheet, read-only, so the shape matches the editor. */
.season-sheet.is-result td { padding: 6px 12px; text-align: right; font-size: .9rem; }
.season-sheet.is-result thead th.seas { min-width: 150px; }

/* The rate probe over a range: one calendar block per month. A rate card is read
   as "what do I pay the week we are there", and a wall of dates answers that in
   one look where a list of bands does not — so it gets both. */
.probe-cals { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 12px; }
.probe-cal { flex: 1 1 300px; max-width: 420px; border: 1px solid var(--line); border-radius: 12px;
  overflow: hidden; background: #fff; }
.probe-cal .mh { background: var(--brand-ink); color: #fff; font-weight: 600; font-size: .85rem;
  padding: 6px 10px; text-align: center; }
.probe-cal .dow, .probe-cal .days { display: grid; grid-template-columns: repeat(7, 1fr); }
.probe-cal .dow span { text-align: center; font-size: .62rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); padding: 4px 0; background: #EFF9FC; }
.probe-cal .d { min-height: 50px; border-top: 1px solid var(--line); border-right: 1px solid var(--line);
  padding: 2px 3px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 1px; }
.probe-cal .d:nth-child(7n) { border-right: 0; }
.probe-cal .d .n { font-size: .6rem; color: var(--muted); align-self: flex-start; line-height: 1; }
.probe-cal .d b { font-size: .68rem; font-weight: 700; line-height: 1.1; text-align: center; word-break: break-word; }
.probe-cal .d i { font-size: .55rem; font-style: normal; color: var(--muted); text-align: center;
  line-height: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.probe-cal .d.pad, .probe-cal .d.out { background: #F2F7F9; }
.probe-cal .d.out .n { opacity: .45; }
.probe-cal .d.seas { background: #eaf7ee; }
.probe-cal .d.seas b { color: #10643f; }
.probe-cal .d.allyear { background: #fff; }
.season-sheet.is-result th.rt .sub { display: block; font-weight: 400; font-size: .68rem; color: var(--muted); }
/* A rule between the export actions and the send actions in the A4 bar. */
#pkgA4 .a4-sep { width: 1px; align-self: stretch; margin: 0 2px; background: var(--line); }
/* Per-season plan controls: drop a plan column, or add one that is not shown. */
.season-sheet thead tr.plans th .planx { border: 0; background: none; color: #94a3b8; cursor: pointer; font-size: .8rem; line-height: 1; padding: 0 0 0 3px; }
.season-sheet thead tr.plans th .planx:hover { color: #b91c1c; }
.season-sheet th.planadd, .season-sheet td.planadd { background: #f8fafc; width: 74px; }
.season-sheet th.planadd select { width: 100%; padding: 2px; font-size: .68rem; border-color: var(--line); }
/* The add-a-season column sits at the far right of the header. */
.season-sheet thead th.seas.addcol { background: #334155; min-width: 62px; padding: 4px; }
.season-sheet thead th.seas.addcol button { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 100%; }
.season-sheet thead th.seas.addcol span { font-size: .6rem; }
.season-sheet td.addcol { background: #fafafa; }
/* Room categories: same sheet styling, but a data grid rather than a rate matrix. */
.season-sheet.hx-rooms th.rt { min-width: 190px; }
.season-sheet.hx-rooms td { padding: 5px 6px; }
.season-sheet.hx-rooms input, .season-sheet.hx-rooms select { width: 100%; padding: 5px 6px; font-size: .82rem; text-align: left; border-color: var(--line); background: #fff; }
.season-sheet.hx-rooms td:nth-child(n+3) input { text-align: right; }
.season-sheet.hx-rooms td.acts { white-space: nowrap; text-align: right; }
.season-sheet.hx-rooms td.acts .btn { padding: 4px 10px; font-size: .78rem; }
/* The first row is the hotel's own rates — everything downstream reads it. */
.season-sheet.hx-rooms tr.is-primary td { background: #fffaf3; }
.season-sheet.hx-rooms tr.is-primary .chip { font-size: .55rem; margin-left: 4px; vertical-align: middle; }
/* The row being added: part of the table, not a separate strip, but visibly not
   saved yet. */
.season-sheet.hx-rooms tr.is-new td { background: #f2f8ff; }
.season-sheet.hx-rooms tr.is-new input, .season-sheet.hx-rooms tr.is-new select { border-color: var(--brand, #12805a); }

/* Hotel list filter chips: how many hotels can actually quote a price. */
.hx-chips { display:flex; gap:6px; flex-wrap:wrap; }
.hx-chips .chip { cursor:pointer; border:1px solid var(--line); background:#fff; color:var(--muted);
                  padding:4px 9px; border-radius:999px; font-size:.72rem; line-height:1.4; }
.hx-chips .chip b { color:var(--ink, #1f2937); }
.hx-chips .chip.on { border-color:var(--brand,#12805a); color:var(--brand,#12805a); background:rgba(18,128,90,.06); }
.hx-chips .chip.warn b { color:var(--danger); }

/* The note a supplier's own rate card carries under the sheet. */
/* The one control that turns a refusal into a decision. Deliberately inside the
   red block and not beside the Save button: it should read as answering the
   error above it, never as a setting somebody flicks on once and forgets. */
.room-approve { display: flex; gap: 8px; align-items: flex-start; margin-top: 10px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; background: #fff; cursor: pointer; }
.room-approve input { margin-top: 2px; flex: none; }
.room-approve span { font-size: .82rem; line-height: 1.4; }
.room-approve b { display: block; font-weight: 500; font-size: .74rem; margin-top: 2px; }

.sheet-note { margin: 8px 0 0; padding: 7px 10px; border: 1px solid var(--line);
              border-radius: 6px; background: #FFFBEB; color: #7c5e10;
              font-size: .74rem; text-align: center; }
/* On its own page the editor is the whole column, not a panel beside a list. */
main[data-hx-page="edit"] .hx-editor, main[data-hx-page="edit"] .hx-split { display: block; }

/* A hotel in the list is a link to its own page, so it can be middle-clicked
   and opened in a tab. It was a <button>, which cannot be. */
a.hx-item { display: block; text-decoration: none; color: inherit; }

/* The rate sheet as a spreadsheet: every cell typed, the category name editable
   in the first column, and the all-year fallback kept beside the seasons.

   The season and add-season headings were styled as `th.seas.addcol` — BOTH
   classes — and this grid's add column is `th.addcol` alone, so it fell back to
   a white cell with a white button on it. The + Season control was invisible,
   which read as an empty column at the end of the table. These rules key off
   .rate-grid so they cannot miss again, and they use the brand palette: the
   sheet was slate and blue in an otherwise orange app. */
.season-sheet.rate-grid thead th.seas { background: var(--brand-ink); color: #fff; }
.season-sheet.rate-grid thead th.addcol { background: var(--ink); color: #fff; min-width: 74px; padding: 4px; }
.season-sheet.rate-grid thead th.addcol button { display: flex; flex-direction: column; align-items: center;
  gap: 2px; width: 100%; color: #fff; }
.season-sheet.rate-grid thead th.addcol span { font-size: .6rem; }
.season-sheet.rate-grid td.addcol { background: #F7FBFC; }
.season-sheet.rate-grid thead tr.plans th { background: #EFF9FC; color: var(--brand-ink); }
/* Remove-season: pale pink on a coloured heading was barely there. */
.season-sheet.rate-grid thead th.seas .dates button { color: #fff; opacity: .75; padding: 0 2px; }
.season-sheet.rate-grid thead th.seas .dates button:hover { opacity: 1; color: #FFD9D4; }

.season-sheet.rate-grid th.rt { min-width: 260px; text-align: left; }
.season-sheet.rate-grid th.rt input { width: 100%; font-weight: 600; }
.season-sheet.rate-grid th.allyear, .season-sheet.rate-grid td.allyear { background: #FFFBEB; min-width: 92px; }
.season-sheet.rate-grid td { padding: 3px 4px; }
.season-sheet.rate-grid td input { width: 100%; padding: 5px 6px; font-size: .82rem;
  border: 1px solid var(--line); border-radius: 4px; background: #fff; text-align: right; }
.season-sheet.rate-grid th.rt input { width: 100%; padding: 5px 6px; font-size: .82rem;
  border: 1px solid var(--line); border-radius: 4px; background: #fff; text-align: left; }
.season-sheet.rate-grid thead th.seas input { text-align: left; background: #fff; color: var(--ink);
  border: 1px solid rgba(255,255,255,.35); border-radius: 4px; }
.season-sheet.rate-grid thead th.seas .dates input { text-align: center; font-size: .7rem; }
.season-sheet.rate-grid td input:focus { outline: 2px solid var(--brand, #12805a); outline-offset: -1px; }
/* Where one room category ends and the next begins. It was a 2px rule in
   --line, which is #E3EAEE on a white table — technically a divider, visually
   nothing, so eight rows read as one list and the second category's rates
   looked like more rows of the first.
   A table cannot carry a margin between row groups, so the gap is padding on
   the row that starts each block, above a rule dark enough to see. */
.season-sheet.rate-grid tbody tr.cat > * {
  border-top: 2px solid var(--brand-ink);
  padding-top: 14px;
}
/* The first block sits directly under the header, which is already a boundary. */
.season-sheet.rate-grid tbody tr.cat:first-child > * {
  border-top: 0;
  padding-top: 3px;
}
/* The category's own name row is tinted, so the block reads as belonging to it. */
.season-sheet.rate-grid tbody tr.cat th.rt { background: #F2F9FC; }
.season-sheet.rate-grid tbody tr.cat th.rt input { font-weight: 700; }
.season-sheet.rate-grid td.acts { text-align: center; }

/* The trash sits BESIDE the category name, not in the last column. It used to
   live in the far-right acts cell: on a three-season sheet that is column 14,
   ~1400px out, inside a half-width split — off-screen, with the name it would
   delete scrolled out of sight too. Nobody found it, so removing a category
   read as broken. */
.season-sheet.rate-grid th.rt .cat-name { display: flex; align-items: center; gap: 6px; }
.season-sheet.rate-grid th.rt .cat-name input { flex: 1 1 auto; min-width: 0; }
.season-sheet.rate-grid th.rt .cat-name .del-cat { flex: none; color: var(--danger); padding: 0 2px; }
.season-sheet.rate-grid th.rt .cat-name .del-cat:hover { color: #A3271B; }

/* What the room IS, under the name it is sold as. It belongs to the ROW, not to
   a season — the sheet's columns are dates — so it sits in the first column
   beneath the category name rather than as four more columns nobody could reach
   past three seasons of scrolling. */
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px 6px; margin-top: 6px;
}
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ label { display: block; font-weight: 400; }
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ label span {
  display: block; font-size: .58rem; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .03em; margin-bottom: 1px;
}
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ select,
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ input {
  width: 100%; padding: 3px 5px; font-size: .74rem; font-weight: 600; text-align: left;
  border: 1px solid var(--line); border-radius: 4px; background: #fff;
}
/* The total sits across both columns, directly above the line that reads it
   out: it is counted out of the two caps above it, not a fifth cap beside. */
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ label.heads { grid-column: 1 / -1; }
.season-sheet.rate-grid tbody tr.cat th.rt .cat-occ .sleeps {
  grid-column: 1 / -1; font-size: .62rem; font-weight: 600; color: var(--brand-ink);
}

/* ---- package editor: full width, in two parts, document at A4 -----------
   The editor takes the whole width and splits down the middle: what the trip IS
   on the left (adults, tier, price, dates, branding, actions), what its route
   and rates ARE on the right. The document then sits below it at A4 — the size
   it prints at, so the preview is the thing being sent.

   Two earlier attempts were worse. One column put six controls and a row of
   buttons above the route, so changing a night scrolled the price out of sight.
   Putting the editor beside the document halved both: the controls stacked one
   per line and the document stopped being A4, which is the size that matters. */
.pkg-editor-split {
  display: grid;
  /* Not equal: the left holds settings, the right holds a route that grows a row
     per stop. Equal widths left the settings side ending halfway down with a
     block of empty card under it. */
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 16px;
  align-items: start;
}
/* Three real columns on a desktop, so the whole quote is one screen: what the
   trip IS (1-3), what it costs and how it is sent (4-6), and the route beside
   both. Real columns rather than one column re-flowed by CSS — a grid aligns its
   rows, so a short card next to a tall one left a visible hole under it, and the
   first attempt at faking it asked for ninety-nine rows and grew a 1,500px band
   of blank card from the gaps alone. */
@media (min-width: 1360px) {
  .pkg-editor-split { grid-template-columns: minmax(0, 4fr) minmax(0, 4fr) minmax(0, 5fr); }
  .pkg-editor-split .pkg-control-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Between the two: the route keeps a column of its own and the steps share one. */
@media (min-width: 1100px) and (max-width: 1359px) {
  .pkg-editor-split { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
  .pkg-editor-split > .pkg-editor-col:nth-child(2) { grid-column: 1; }
  .pkg-editor-split > .pkg-editor-col:nth-child(3) { grid-column: 2; grid-row: 1 / span 2; }
}
/* A select that cannot show its own text is a select that does not say what it
   is — "01 FBR — 1 family roc" was the room plan, cut mid-word. */
.pkg-control-grid select,
.pkg-rooms select { width: 100%; min-width: 0; text-overflow: ellipsis; }
.pkg-rooms { grid-column: 1 / -1; }
.pkg-editor-col { min-width: 0; }
.pkg-side-group {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 12px 12px;
  margin-bottom: 10px;
}
.pkg-side-group:last-child { margin-bottom: 0; }
.pkg-side-group h4 {
  margin: 0 0 8px;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--brand-ink);
}
.pkg-side-group h4 i { margin-right: 5px; opacity: .8; }
/* Half the page fits three of the six trip controls per line, markup below. */
.pkg-editor-split .pkg-control-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
.pkg-editor-split .pkg-control-grid > label:last-child { grid-column: 1 / -1; }
.pkg-editor-split .pkg-actions-row { margin-top: 0; gap: 7px; flex-wrap: wrap; }
.pkg-editor-split .pkg-actions-row > span[style*="flex:1"] { display: none; }
/* One picker per line. Side by side in a half-width column neither could show
   its own text — "Document — detailed" was cut to "detailex" with the dropdown
   arrow sitting on the last letter. A select does not tell you what it is when
   its label does not fit. */
.pkg-editor-split #pk_designwrap { display: grid; gap: 6px; width: 100%; }
.pkg-editor-split #pk_designwrap select { width: 100%; min-width: 0; }
.pkg-editor-split .pkg-route-editor { margin-top: 0; padding-top: 0; border-top: 0; }
/* Nothing inside a column may be wider than the column. */
.pkg-editor-col input,
.pkg-editor-col select { max-width: 100%; }
.pkg-editor-col .season-sheet-scroll,
.pkg-editor-col .table-wrap { overflow-x: auto; }

/* The preview is the document, so it is the size the document prints at. */
.doc-wrap > .doc {
  max-width: 210mm;
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 1100px) {
  .pkg-editor-split { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .pkg-editor-split .pkg-control-grid { grid-template-columns: 1fr; }
}

/* The panel that asks what a new season should be built from. Sits above the
   sheet while adding, so the columns it will copy are still visible. */
.hx-newseason {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
  margin: 0 0 12px;
  padding: 10px 12px;
  border: 1px solid var(--brand-ink);
  border-radius: 10px;
  background: #EFF9FC;
}
.hx-newseason > b { align-self: center; color: var(--brand-ink); font-size: .9rem; }
.hx-newseason .field { margin: 0; min-width: 150px; }
.hx-newseason .field > span { font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.hx-newseason > span.muted { flex-basis: 100%; }

/* ================================================================= app shell ==
   Sidebar navigation. Replaces the per-page topbar nav that used to be
   copy-pasted into every HTML file (and had drifted out of sync). Markup comes
   from partials/shell.php, so this is the only place the chrome is styled.
   ============================================================================ */
.app-frame { display: flex; min-height: 100vh; }

.sidebar {
  --w: 258px;
  position: fixed; inset: 0 auto 0 0; z-index: 45; width: var(--w);
  display: flex; flex-direction: column; gap: 4px;
  background: var(--surface); border-right: 1px solid var(--line);
  padding: 14px 12px; overflow-y: auto; overscroll-behavior: contain;
  transition: width .18s ease, transform .22s cubic-bezier(.2,.7,.3,1);
}
.app-main { flex: 1; min-width: 0; margin-left: 258px; transition: margin-left .18s ease; }
/* The signed-in app is a WORKBENCH, not an article: it uses the room it has.
   1180px is a reading column and belongs to the public pages, which keep it —
   inside the frame it left ~460px of empty gutter on a normal laptop, so a
   leads table with five columns wrapped while a third of the screen sat blank.
   Set as the variable rather than as `max-width` on purpose: a page that has
   deliberately chosen its own width — /welcome's 760px form, an A4 document —
   still wins, because its own rule beats `.container` at equal specificity. */
.app-main { --maxw: 1760px; }

.side-brand { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 6px 14px; }
.side-brand .brandmark img, .side-brand .brandmark svg { height: 34px; max-width: 160px; }
.sidebar .side-close { display: none; }

.side-nav { display: grid; gap: 2px; }
.side-label {
  font-size: .66rem; letter-spacing: .16em; text-transform: uppercase; font-weight: 700;
  color: var(--muted); padding: 14px 12px 6px;
}
.side-item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 10px 12px; border-radius: 11px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: .9rem; font-weight: 600; color: var(--ink); text-align: left;
  position: relative; transition: background .15s, color .15s;
}
.side-item i { width: 20px; text-align: center; font-size: .95rem; color: var(--muted); transition: color .15s; }
.side-item:hover { background: #EFF9FC; }
.side-item:hover i { color: var(--brand-ink); }
.side-item.active { background: #E8F6FA; color: var(--brand-ink); }
.side-item.active i { color: var(--brand); }
.side-item.active::before {
  content: ''; position: absolute; left: -12px; top: 8px; bottom: 8px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--brand);
}
.side-foot { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line); display: grid; gap: 2px; }
.side-foot .side-item { font-size: .85rem; font-weight: 500; color: var(--muted); }
.side-foot .side-item:hover { color: var(--ink); }

/* Collapsed rail: icons only, labels on hover-out. */
:root.nav-rail .sidebar { --w: 76px; }
:root.nav-rail .app-main { margin-left: 76px; }
:root.nav-rail .side-item span, :root.nav-rail .side-label, :root.nav-rail .side-brand .brandmark span { display: none; }
:root.nav-rail .side-item { justify-content: center; padding: 11px 0; }
:root.nav-rail .side-item i { width: auto; font-size: 1.05rem; }
:root.nav-rail .side-brand { justify-content: center; }
:root.nav-rail .side-brand .brandmark img { max-width: 40px; }
:root.nav-rail .rail-flip { transform: rotate(180deg); }
:root.nav-rail .side-label { display: block; height: 1px; padding: 8px 0 0; overflow: hidden; }

/* --------------------------------------------------------------- topbar ---- */
.apptop {
  position: sticky; top: 0; z-index: 40;   /* .doc-toolbar is 30 and comes later in the DOM */
  display: flex; align-items: center; gap: 14px; height: 64px; padding: 0 clamp(14px, 2.4vw, 26px);
  background: rgba(255,255,255,.86); backdrop-filter: blur(10px); border-bottom: 1px solid var(--line);
}
.apptop-title { font-size: 1.08rem; font-weight: 700; letter-spacing: -.02em; margin: 0; }
.apptop-acts { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.shell-btn {
  display: grid; place-items: center; width: 38px; height: 38px; border-radius: 11px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink); cursor: pointer; font-size: .95rem;
}
.shell-btn:hover { border-color: var(--brand); color: var(--brand-ink); }
.side-burger { display: none; }

/* Account menu — <details> so it opens without a line of JavaScript. */
.usermenu { position: relative; }
.usermenu summary { list-style: none; cursor: pointer; }
.usermenu summary::-webkit-details-marker { display: none; }
.usermenu .avatar { width: 38px; height: 38px; }
.usermenu .menu {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: 50; width: 246px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 8px;
  box-shadow: 0 18px 44px rgba(60,38,12,.16); display: grid; gap: 2px;
}
.usermenu .menu-head { padding: 10px 10px 12px; display: grid; gap: 3px; border-bottom: 1px solid var(--line); margin-bottom: 6px; }
.usermenu .menu-head b { font-size: .92rem; }
.usermenu .menu-head .chip { justify-self: start; margin-top: 4px; }
.usermenu .menu a, .usermenu .menu button {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 9px;
  border: 0; background: none; font: inherit; font-size: .88rem; color: var(--ink); cursor: pointer; text-align: left; width: 100%;
}
.usermenu .menu a:hover, .usermenu .menu button:hover { background: #EFF9FC; color: var(--brand-ink); }
.usermenu .menu i { width: 16px; color: var(--muted); }

.side-scrim { display: none; }

@media (max-width: 900px) {
  .sidebar { transform: translateX(-100%); box-shadow: 0 0 60px rgba(0,0,0,.25); }
  .app-frame.nav-open .sidebar { transform: none; }
  .app-main, :root.nav-rail .app-main { margin-left: 0; }
  .side-burger, .sidebar .side-close { display: grid; }
  .app-frame.nav-open .side-scrim {
    display: block; position: fixed; inset: 0; z-index: 44; background: rgba(20,12,4,.45);
  }
  :root.nav-rail .sidebar { --w: 258px; }
  :root.nav-rail .side-item span, :root.nav-rail .side-label, :root.nav-rail .side-brand .brandmark span { display: revert; }
  :root.nav-rail .side-item { justify-content: flex-start; padding: 10px 12px; }
  .side-foot button.side-item { display: none; }   /* the rail is desktop-only */
  .apptop-acts .btn.sm span, .apptop-acts .btn.ghost.sm span { display: none; }
  /* !important because the wizard writes display:inline-flex straight onto
     #draftStatus, and an inline style beats a stylesheet rule — the chip came
     back on every autosave and wrapped onto three lines across the title. */
  .apptop-acts #stepChip, .apptop-acts #draftStatus { display: none !important; }
  .apptop-acts .btn.sm { padding: 10px 13px; }
  .apptop-title { font-size: .98rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .apptop { gap: 10px; }
}

/* A highlighted note inside a card — the "heads up" panels on the dashboard,
   the wizard and the leads drawer. They were three separate hard-coded warm
   gradients left from the orange palette; one class means the next one matches
   without anybody remembering the hexes. */
.card.note-tint {
  background: linear-gradient(135deg, #EFF9FC, #F7FBFC);
  border-color: #BFE4F0;
}

/* ---- wizard progress -------------------------------------------------
   The vertical rail is hidden in quick mode, so this is the only place the
   flow says where you are. Kept above the step body rather than in the top
   bar: a progress indicator you have to go looking for is not one. */
.wiz-progress {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 18px 16px; margin-bottom: 18px; box-shadow: var(--shadow);
}
/* Quick mode is one page, and render() returns before renderRail() there — so
   the element exists and is never filled. Empty means gone, rather than a bare
   bordered strip above the form. */
.wiz-progress:empty { display: none; }
.wiz-progress .wp-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.wiz-progress .wp-count {
  display: block; font-size: .7rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 3px;
}
.wiz-progress .wp-title { font-size: 1.06rem; letter-spacing: -.015em; }
.wiz-progress .wp-title i { color: var(--brand); margin-right: 6px; }
.wiz-progress .wp-pct {
  font-size: .82rem; font-weight: 700; color: var(--brand-ink);
  font-variant-numeric: tabular-nums; flex: none;
}
.wiz-progress .wp-bar {
  height: 5px; border-radius: 999px; background: var(--line);
  margin: 12px 0 0; overflow: hidden;
}
.wiz-progress .wp-bar i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--brand-2), var(--brand));
  transition: width .45s cubic-bezier(.2,.8,.2,1);
}
@media (prefers-reduced-motion: reduce) { .wiz-progress .wp-bar i { transition: none } }

.wiz-progress .wp-dots {
  list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 0; padding: 0;
}
.wiz-progress .wp-dots li > span {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: .74rem; font-weight: 700; font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--line); background: var(--surface); color: var(--muted);
  transition: .16s;
}
.wiz-progress .wp-dots li.done > span    { background: var(--brand); border-color: var(--brand); color: #fff; }
.wiz-progress .wp-dots li.current > span { border-color: var(--brand); color: var(--brand-ink); box-shadow: 0 0 0 3px rgba(37,168,203,.18); }
.wiz-progress .wp-dots li.locked > span  { opacity: .55; }
/* Only a step you are allowed to jump to looks clickable — the bar must not
   promise a jump that jump() will refuse. */
.wiz-progress .wp-dots li.done, .wiz-progress .wp-dots li.current { cursor: pointer; }
.wiz-progress .wp-dots li.done:hover > span { transform: scale(1.08); }

@media (max-width: 560px) {
  .wiz-progress { padding: 12px 14px 14px; }
  .wiz-progress .wp-title { font-size: .98rem; }
  .wiz-progress .wp-dots li > span { width: 23px; height: 23px; font-size: .68rem; }
}

/* ---- dashboard first run --------------------------------------------
   Shown instead of the stat grid until the agent has one quotation. Eight
   tiles reading zero describe an empty product; this describes a next step. */
.card.start-here { display: grid; grid-template-columns: 1.15fr .85fr; gap: 30px; align-items: center; padding: 26px 28px; }
.card.start-here h2 { font-size: 1.32rem; letter-spacing: -.02em; margin: 0 0 8px; }
.card.start-here p { margin: 0; line-height: 1.65; max-width: 46ch; }
.start-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.start-steps li {
  display: grid; gap: 2px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: 12px; background: var(--bg); position: relative; counter-increment: si;
}
.start-steps { counter-reset: si; }
.start-steps li::before {
  content: counter(si); position: absolute; right: 12px; top: 10px;
  font-size: .7rem; font-weight: 700; color: var(--muted-2);
}
.start-steps b { font-size: .94rem; }
.start-steps span { color: var(--muted); font-size: .86rem; line-height: 1.5; }
.start-steps a { font-size: .84rem; font-weight: 600; margin-top: 4px; }
@media (max-width: 820px) { .card.start-here { grid-template-columns: 1fr; gap: 22px; } }

/* An unopened website enquiry. Nobody has spoken to these people yet, so they
   should not look identical to a lead somebody has been working for a week. */
table.data tr.is-fresh > td:first-child { box-shadow: inset 3px 0 0 var(--brand); }
@media (max-width: 640px) {
  table.data tr.is-fresh { box-shadow: inset 3px 0 0 var(--brand), var(--shadow); }
  table.data tr.is-fresh > td:first-child { box-shadow: none; }
}

/* ---- settings & team, on a phone -------------------------------------
   These screens are dense two-column forms. Below 720px the pairs stack,
   the pane tabs scroll rather than wrapping into four ragged rows, and the
   mailbox rows read as cards. */
@media (max-width: 720px) {
  #tabBody .grid-2, #tabBody .grid-3 { grid-template-columns: 1fr; }
  /* The panel's own tab bar carries twenty tabs. Wrapped, that is ten ragged
     rows before the page even starts — taller than the content it labels. */
  #tabbar {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding-bottom: 4px;
    /* A fade on the right edge says "there is more", which a cut-off button
       on its own does not. */
    mask-image: linear-gradient(90deg, #000 88%, transparent);
  }
  #tabbar::-webkit-scrollbar { display: none; }
  #tabbar button { flex: 0 0 auto; white-space: nowrap; }
  /* The pane switcher is a horizontal scroller, not a wrapped block: four
     half-width buttons on two rows is harder to hit than one row you swipe. */
  #tabBody .tabbar {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding-bottom: 2px;
  }
  #tabBody .tabbar::-webkit-scrollbar { display: none; }
  #tabBody .tabbar button { flex: 0 0 auto; white-space: nowrap; }
  .mail-row { padding: 12px !important; }
  .mail-row .field span { font-size: .78rem; }
  /* A details/summary block needs a bigger tap target than its text. */
  #drawerHost summary, #tabBody summary { padding: 10px 0; }
}

/* Permission checkboxes want a row each with a real hit area — a 13px box
   beside 40 characters of label is a target only a mouse can find.
   SCOPED TO LABELS THAT ACTUALLY HOLD A CHECKBOX. Unscoped, `.stack > label`
   also matched every ordinary field in a .stack form — the login card among
   them — and beat `label.field { display:block }` on declaration order. That
   laid each label BESIDE its input instead of above it, so every input started
   at a different x: "Password" is wider than "Email", so the password box was
   25px narrower and 25px further right than the one above it. */
.stack > label:has(> input[type=checkbox]) {
  display: flex; align-items: flex-start; gap: 10px; line-height: 1.5; padding: 4px 0; cursor: pointer;
}
/* The box sits on the first line of the label, not on the middle of a wrapped
   paragraph. */
.stack > label:has(> input[type=checkbox]) > input[type=checkbox] { margin-top: .2em; }

/* ---- Settings ▸ Message templates: boxes beside the letter they produce ---- */

/* Two columns where there is room. The preview is the point of the screen —
   wording you cannot see the effect of is wording you edit by guesswork — so it
   sits beside the boxes rather than under them, and sticks while they scroll. */
.tpl-wrap { display: grid; gap: 16px; grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1080px) {
  .tpl-wrap { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .tpl-preview { position: sticky; top: 14px; }
}

/* Each placeholder next to the value it will stand for. A definition list in
   prose told you the codes existed; this tells you which is which. */
.tpl-keys { display: grid; gap: 6px; margin: 0 0 4px; }
/* Explicit rows rather than a wrapping flex line: the code and the value it
   stands for are the comparison being made, so they stay on one line together
   and the description drops underneath. Left to wrap, a long description pushed
   the value onto its own line for some placeholders and not others, and the
   column of values stopped being a column. */
.tpl-key { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 1px 9px;
           padding: 7px 10px; border-radius: 9px; background: var(--paper-2, #F6F9FA); }
.tpl-key code { grid-area: 1 / 1; font-size: .82rem; color: #17819F; background: #E8F6FA;
                padding: 1px 7px; border-radius: 6px; justify-self: start; }
.tpl-key .tpl-key-val { grid-area: 1 / 2; font-size: .84rem; font-weight: 600; color: var(--ink);
                        text-align: right; overflow-wrap: anywhere; }
.tpl-key > span.muted { grid-area: 2 / 1 / 3 / -1; }

.tpl-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.tpl-tabs .btn.is-on { background: var(--brand, #25A8CB); border-color: var(--brand, #25A8CB); color: #fff; }

.tpl-subject { border: 1px solid var(--line, #E3EAEE); border-radius: 10px; padding: 8px 12px;
               background: var(--paper-2, #F6F9FA); }
.tpl-subject-line { font-weight: 600; overflow-wrap: anywhere; }

/* White, not transparent: the letter is designed against its own background and
   would otherwise inherit the panel's. */
.tpl-frame { width: 100%; height: 520px; margin-top: 10px; border: 1px solid var(--line, #E3EAEE);
             border-radius: 12px; background: #fff; display: block; }
@media (max-width: 700px) { .tpl-frame { height: 420px; } }

/* Long values (a mailbox address, an SMTP host) must not widen the panel. */
#tabBody input, #tabBody select, #tabBody textarea { max-width: 100%; min-width: 0; }

/* Campaign progress: a bar beside the numbers, because "812/4000" is a fact and
   a bar is a glance. */
.camp-bar { height: 4px; border-radius: 999px; background: var(--line); margin-top: 5px; max-width: 160px; overflow: hidden; }
.camp-bar i { display: block; height: 100%; border-radius: 999px; background: var(--brand); transition: width .4s ease; }

/* ---- sidebar-less app pages ($HIDE_SIDEBAR) --------------------------------
   The sidebar is position:fixed, so the frame and the topbar pad themselves by
   its width. With no sidebar to pad around, that padding is just a gap on the
   left of an otherwise centred page. */
.app-frame.no-side { padding-left: 0; }
.app-frame.no-side .topbar,
.app-frame.no-side .app-main { margin-left: 0; padding-left: 0; }

/* ---- first-run onboarding (/welcome) --------------------------------------- */
.wc { max-width: 760px; margin-inline: auto; padding-block: clamp(22px, 4vw, 46px); }
.wc-card { background: var(--surface, #fff); border: 1px solid var(--line, #E3EAEE);
           border-radius: 20px; padding: clamp(24px, 4vw, 44px); }
.wc-hd { margin-bottom: 34px; }
.wc-step { display: inline-block; font-size: .72rem; font-weight: 700; letter-spacing: .12em;
           text-transform: uppercase; color: #17819F; background: #E8F6FA;
           padding: 5px 11px; border-radius: 999px; margin-bottom: 14px; }
.wc-hd h1 { font-size: clamp(1.6rem, 1.2rem + 1.7vw, 2.2rem); line-height: 1.15; margin: 0 0 10px;
            letter-spacing: -.02em; }
.wc-hd p  { color: var(--muted, #4C5860); line-height: 1.62; margin: 0; max-width: 58ch; }

.wc-sec { padding-top: 26px; margin-top: 26px; border-top: 1px solid var(--line, #E3EAEE); }
.wc-sec:first-of-type { padding-top: 0; margin-top: 0; border-top: 0; }
.wc-sec h2 { display: flex; align-items: center; gap: 11px; font-size: 1.04rem; font-weight: 650;
             margin: 0 0 18px; letter-spacing: -.01em; }
.wc-n { width: 25px; height: 25px; flex: none; border-radius: 50%; display: grid; place-items: center;
        background: #E8F6FA; color: #17819F; font-size: .8rem; font-weight: 700; }
.wc-note { display: flex; gap: 9px; align-items: flex-start; font-size: .88rem; line-height: 1.55;
           color: var(--muted, #4C5860); background: var(--paper-2, #F6F9FA);
           border-radius: 11px; padding: 12px 14px; margin: -6px 0 18px; }
.wc-note i { color: #17819F; margin-top: .18em; }
.wc-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }

/* The terms, scrollable in place. A link alone gets clicked by nobody; a wall of
   text inline pushes the button off the page. */
.wc-terms { max-height: 210px; overflow-y: auto; border: 1px solid var(--line, #E3EAEE);
            border-radius: 13px; padding: 18px 20px; background: var(--paper-2, #F6F9FA);
            font-size: .91rem; line-height: 1.62; color: var(--muted, #4C5860); }
.wc-terms:focus-visible { outline: 2px solid #25A8CB; outline-offset: 2px; }
.wc-terms h3 { font-size: .76rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
               color: var(--ink-3, #7B888F); margin: 0 0 12px; }
.wc-terms ul { margin: 0; padding-left: 19px; display: grid; gap: 9px; }
.wc-terms-link { margin: 14px 0 0; font-size: .86rem; }

/* The one control that gates the button, so it gets a box of its own rather than
   a checkbox loose on the page. */
.wc-accept { display: flex; gap: 12px; align-items: flex-start; margin-top: 18px;
             font-size: .93rem; line-height: 1.55; cursor: pointer;
             border: 1.5px solid var(--line, #E3EAEE); border-radius: 13px;
             padding: 14px 16px; transition: border-color .15s, background .15s; }
.wc-accept:hover { border-color: #B9D9E4; background: var(--paper-2, #F6F9FA); }
/* min-width:0 so a long sentence wraps inside the row instead of pushing the
   row wider than the card. */
.wc-accept > span { flex: 1; min-width: 0; }
.wc-accept input { margin-top: .15em; }
/* Focus lands on the checkbox, but the box is what the eye is on. */
.wc-accept:focus-within { border-color: var(--brand, #25A8CB); box-shadow: var(--ring); }

.wc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 30px; }
.wc-msg:empty { display: none; }
.wc-msg { margin: 16px 0 0; font-size: .92rem; padding: 12px 15px; border-radius: 11px;
          background: #FDECEC; color: #A32323; }
@media (max-width: 480px) {
  .wc-actions { flex-direction: column; align-items: stretch; }
  .wc-actions .btn { width: 100%; justify-content: center; }
}

/* ---- Help & troubleshooting (/help and the panel's Help tab) -------------
   Native <details>, so the open/close state costs no JavaScript and the whole
   page stays searchable by the browser's own find. */
.help-group { margin-bottom: 16px; padding: 18px 20px; }
.help-item { border-top: 1px solid var(--line); }
.help-item:first-of-type { border-top: 0; }
.help-item > summary { display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
                       padding: 13px 0; font-weight: 600; line-height: 1.5; list-style: none; }
.help-item > summary::-webkit-details-marker { display: none; }
.help-item > summary:hover { color: var(--brand); }
.help-item > summary > i { color: var(--brand); font-size: .78rem; margin-top: .32em;
                           transition: transform .15s ease; flex: none; }
.help-item[open] > summary > i { transform: rotate(90deg); }
.help-body { padding: 0 0 16px 24px; }
.help-body ul { margin: 10px 0 0; padding-left: 18px; display: grid; gap: 8px;
                font-size: .92rem; line-height: 1.6; }
.help-body code { background: #EEF0F3; border-radius: 5px; padding: 1px 5px; font-size: .86em; }
@media (max-width: 560px) { .help-body { padding-left: 0; } }

/* ---- leads: the row is a person, not four values ------------------------- */
/*
 * The generic phone rule above turns any .data row into a card of label/value
 * pairs, which is right for a table of figures. A lead's first cell is not a
 * value: it is a name, a phone number and an email address. Pushed to the right
 * by the label/value split they wrapped into each other and into the name, and
 * one lead filled an entire phone screen — with 34 of them, unusable.
 *
 * So the Guest cell becomes the card's title, full width and left aligned, and
 * everything under it tightens. Scoped to #leadList: every other data table on
 * the site still wants the generic treatment.
 */
@media (max-width: 640px) {
  #leadList table.data tr { margin-bottom: 10px; padding: 2px 2px 4px; }
  #leadList table.data td { padding: 8px 12px; }

  /* Title: no column name, no right alignment, and room to breathe under it. */
  #leadList table.data td[data-label="Guest"] {
    display: block; text-align: left !important; padding: 12px 12px 9px;
  }
  #leadList table.data td[data-label="Guest"]::before { display: none; }
  #leadList table.data td[data-label="Guest"] b { font-size: 1.02rem; }
  #leadList table.data td[data-label="Guest"] .small { margin-top: 3px; line-height: 1.5; }
  /* The note is capped on desktop so it cannot push the column wide; on a phone
     that cap is narrower than the card and truncates far too early. (It used to
     match `.small[style]` — the cap was an inline style then. It is .lead-note
     now, which is why that selector had quietly stopped matching anything.) */
  #leadList table.data td[data-label="Guest"] .lead-note { max-width: 100%; }

  /* Interest reads as a sentence, not a right-aligned value with a gap. */
  #leadList table.data td[data-label="Interest"] {
    display: block; text-align: left !important; padding-top: 0;
  }
  #leadList table.data td[data-label="Interest"]::before { display: block; margin-bottom: 2px; }

  /* A full-width date box and status pill wasted half the card each. */
  #leadList table.data select,
  #leadList table.data input[type="date"] { max-width: 190px; padding: 8px 10px; }

  /* Actions on one line, left aligned, at the foot of the card. */
  #leadList table.data td:last-child { text-align: left !important; padding: 10px 12px 12px; }
}

/* The page header was 700px before the first lead: a full-size hero, a button,
   six status chips on two rows and a search box. The chips become one swipeable
   strip, as on the Library, and the hero gives back what it does not need. */
@media (max-width: 640px) {
  .page > .spread.wrap h1 { font-size: 1.55rem !important; }
  .page > .spread.wrap .muted { font-size: .92rem; }
  /* The status filters used to be a nowrap scroller with its scrollbar hidden,
     so on a phone "Converted" and "Lost" sat off the right edge with nothing
     on screen to say they were there — a filter you cannot see is a filter
     nobody uses. The markup has always asked for `wrap`; let it. Two short
     rows of chips costs less than a hidden one. */
  #pipeline { flex-wrap: wrap; padding-bottom: 2px; }
  #pipeline > * { flex: 0 0 auto; }
}

/* Desktop: a long package title had a narrow column to wrap in, so an eight-word
   name became six stacked lines and every row in the table grew to match it. */
@media (min-width: 641px) {
  #leadList table.data th:nth-child(2),
  #leadList table.data td[data-label="Interest"] { min-width: 210px; }
  #leadList table.data td[data-label="Follow-up"] input[type="date"] { max-width: 160px; }
}

/* Tablet: the leads table becomes cards early.
   Five columns need ~950px and a 768px tablet gives the table 722, so at that
   width Itinerary, Quote, edit and delete sat off the right edge again — the
   same complaint the desktop fix answered, one screen size down. No amount of
   column trimming closes a 250px gap; the card layout is the answer and it is
   already written and used below 640. This turns it on for THIS table up to
   900px rather than moving the app-wide breakpoint, which would restyle every
   other table in the panel without anyone having looked at them.
   The declarations mirror the @media (max-width: 640px) block above; keep the
   two in step if that one is ever reworked. */
@media (min-width: 641px) and (max-width: 900px) {
  #leadList .table-wrap { overflow: visible; box-shadow: none; border: 0; background: transparent; }
  #leadList table.data, #leadList table.data tbody,
  #leadList table.data tr, #leadList table.data td { display: block; width: 100%; }
  #leadList table.data thead { display: none; }
  #leadList table.data tr {
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: var(--shadow); margin-bottom: 12px; padding: 6px 4px;
  }
  #leadList table.data td {
    border-bottom: 1px solid var(--line); padding: 10px 12px;
    display: flex; gap: 12px; align-items: baseline; justify-content: space-between;
    text-align: right;
  }
  #leadList table.data td:last-child { border-bottom: 0; }
  #leadList table.data td::before {
    content: attr(data-label); flex: none; text-align: left;
    font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--muted); font-weight: 700;
  }
  #leadList table.data td:not([data-label]) { justify-content: flex-start; text-align: left; }
  /* The same card polish the phone gets, so the two read alike: the guest is a
     title rather than a labelled value, Interest reads as a sentence, and the
     status and date controls stop eating half a row each. */
  #leadList table.data td[data-label="Guest"] { display: block; text-align: left; padding: 12px 12px 9px; }
  #leadList table.data td[data-label="Guest"]::before { display: none; }
  #leadList table.data td[data-label="Guest"] b { font-size: 1.02rem; }
  #leadList table.data td[data-label="Interest"] { display: block; text-align: left; padding-top: 0; }
  #leadList table.data td[data-label="Interest"]::before { display: block; margin-bottom: 2px; }
  #leadList table.data select,
  #leadList table.data input[type="date"] { max-width: 190px; padding: 8px 10px; }
  #leadList .lead-note { max-width: none; -webkit-line-clamp: 3; }
  #leadList td.lead-acts { text-align: left; flex-wrap: wrap; padding: 10px 12px 12px; }
  #leadList td.lead-acts > * { margin: 2px 4px 2px 0; }
}

/* ---- the leads row ------------------------------------------------------
   Both of these were inline styles in leads.js, which is why neither could
   answer to a screen size.

   The note is the customer's own words — on this row it is the only thing that
   says what they actually want. It was ONE nowrap line clipped at 320px, so a
   5,700-character enquiry rendered as "Email enquiry to … Subject:…" and not a
   syllable of the request. Two clamped lines keep the row height honest and
   still say something; the card layout below has room for four.

   The actions were one nowrap line 311px wide. With the sidebar open on a
   1280px laptop the table needed 1218px inside a 976px wrapper, so Itinerary,
   Quote, edit and delete were ALL off-screen — behind a scrollbar the theme
   hides. Letting them wrap onto two short lines brings the column to 135px and
   the whole table inside its container. */
.lead-note {
  /* 320px of note was what pushed the Guest column to 348 and the table past
     its wrapper. 240 still carries two readable lines and brings the actions
     on screen; the whole note is in the row's editor, one click away. */
  margin-top: 2px; max-width: 240px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
td.lead-acts { text-align: right; white-space: normal; }
td.lead-acts > * { margin: 2px 0 2px 4px; }

@media (max-width: 640px) {
  /* The card has the width the table never had. */
  .lead-note { max-width: none; -webkit-line-clamp: 4; }
  /* The card layout already makes this cell a flex row, and flex items do not
     wrap unless told to — so the four buttons stayed on one line and the delete
     icon hung 5px past the card's own edge. */
  td.lead-acts { text-align: left; flex-wrap: wrap; }
  td.lead-acts > * { margin: 2px 4px 2px 0; }
}

/* ---- country / state / city picker (ui.js geoPicker) --------------------- */
.geo-picker { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.geo-picker .field { margin: 0; }
@media (max-width: 640px) { .geo-picker { grid-template-columns: 1fr; } }

/* ---- a package whose price does not follow its nights (b2c.js) ----------- */
.pkg-locked-note { margin: 10px 0 0; padding: 12px 14px; border: 1px solid var(--line);
  border-left: 3px solid var(--brand); border-radius: 10px; background: var(--paper-2, #F6F9FA); }
.pkg-locked-note p { margin: 0 0 6px; line-height: 1.55; }
.pkg-locked-note p:last-of-type { margin-bottom: 10px; }
.pkg-locked-note i.fa-lock { color: var(--brand); }
