/* Utility and primitive layer.
 *
 * Load order in base.html is tokens.css -> ui.css -> site.css (and admin.css
 * after that in the admin). ui.css therefore loads BEFORE the page
 * stylesheets, so a page rule of equal specificity still wins. Utilities here
 * are intentionally low-specificity and unobtrusive; when one must beat a page
 * rule, use a more specific selector or !important at the point of use.
 *
 * Everything here is built from tokens: no raw colours, spacing or radii.
 *
 * Two tiers:
 *   1. Primitives — .ui-page, .ui-panel, .ui-stack, .ui-btn, .ui-field. Use
 *      these first; they carry the site's intended look and change globally.
 *   2. Utilities — single-purpose helpers (.flex, .gap-4, .text-muted). Use
 *      these to adjust a primitive, not to rebuild one.
 *
 * Primitives carry a `ui-` prefix. The customer site already defines .panel,
 * .btn, .badge, .notice, .field, .empty and .eyebrow with its own look (e.g.
 * .notice is a centred page message, not an inline banner), so the shared
 * layer must not claim those bare names and silently restyle live pages.
 *
 * Never write a raw value in a template `style=` attribute; use a token-backed
 * class so the design stays changeable in one place.
 */

/* ===================================================================== */
/* Reset-ish                                                             */
/* ===================================================================== */

* { box-sizing: border-box; }

/* The `hidden` attribute must always win. Class rules such as
   `.event-modal { display: flex }` otherwise out-specify the user-agent
   `[hidden] { display: none }`, so setting `element.hidden = true` leaves the
   element on screen and buttons appear to do nothing. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading-base);
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  margin: 0 0 var(--space-2);
  line-height: var(--leading-tight);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
}
h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); }

p { margin: 0 0 var(--space-4); }

a { color: var(--color-brand-link); }

img { max-width: 100%; height: auto; }

code, kbd, pre {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

/* ===================================================================== */
/* Layout primitives                                                     */
/* ===================================================================== */

/* A standard page: centred, generous gutters, consistent vertical rhythm. */
.ui-page {
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--space-8) var(--space-5) var(--space-12);
}
.ui-page--narrow { max-width: var(--content-max); }

/* Heading + lead paragraph + optional actions, used at the top of every page. */
.ui-page__head { margin-bottom: var(--space-6); }
.ui-page__head h1 { margin-bottom: var(--space-1); }
.ui-page__head--row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* The short explanatory line under a heading. */
.ui-lead {
  font-size: var(--text-base);
  color: var(--color-text-muted);
  max-width: var(--measure);
  margin: 0 0 var(--space-4);
}

/* A bordered surface. Named .ui-panel because .card is already the
   clickable product tile in site.css. */
.ui-panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  padding: var(--space-5) var(--space-5);
  margin-bottom: var(--space-4);
}
.ui-panel--flush { padding: 0; overflow: hidden; }
.ui-panel--soft { background: var(--color-bg-soft); }
.ui-panel--danger { border-color: var(--color-danger-bg); background: var(--color-warning-soft); }
.ui-panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
}
.ui-panel__head h2, .ui-panel__head h3 { margin: 0; }

/* Vertical rhythm helpers — replace one-off margins. */
.ui-stack > * + * { margin-top: var(--space-4); }
.ui-stack--tight > * + * { margin-top: var(--space-2); }
.ui-stack--loose > * + * { margin-top: var(--space-6); }

.ui-divider {
  border: 0;
  border-top: 1px solid var(--color-border);
  margin: var(--space-5) 0;
}

/* ===================================================================== */
/* Text utilities                                                        */
/* ===================================================================== */

.text-muted   { color: var(--color-text-muted); }
.text-faint   { color: var(--color-text-faint); }
.text-soft    { color: var(--color-text-soft); }
.text-danger  { color: var(--color-danger); }
.text-success { color: var(--color-success); }
.text-sm      { font-size: var(--text-sm); }
.text-xs      { font-size: var(--text-xs); }
.text-lg      { font-size: var(--text-lg); }
.text-right   { text-align: right; }
.text-center  { text-align: center; }
.ui-mono         { font-family: var(--font-mono); font-size: var(--text-sm); }

/* Small uppercase caption, e.g. a stat label or an eyebrow. */
.ui-eyebrow {
  margin: 0;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
}

.ui-measure { max-width: var(--measure); }

/* ===================================================================== */
/* Flex / grid utilities                                                 */
/* ===================================================================== */

.flex        { display: flex; }
.inline-flex { display: inline-flex; }
.grid        { display: grid; }
.flex-wrap   { flex-wrap: wrap; }
.flex-col    { flex-direction: column; }
.items-start   { align-items: flex-start; }
.items-center  { align-items: center; }
.items-baseline{ align-items: baseline; }
.justify-between { justify-content: space-between; }
.justify-center  { justify-content: center; }
.flex-1 { flex: 1 1 0%; min-width: 0; }

.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.gap-5 { gap: var(--space-5); }
.gap-6 { gap: var(--space-6); }

/* Auto-fitting grid: the responsive card/tile pattern used site-wide. */
.grid-auto {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.grid-auto--narrow { grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); }

/* ===================================================================== */
/* Spacing utilities                                                     */
/* ===================================================================== */

.m-0 { margin: 0; }
.mt-1 { margin-top: var(--space-1); }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mt-8 { margin-top: var(--space-8); }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--space-2); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }
.mb-8 { margin-bottom: var(--space-8); }
.ml-auto { margin-left: auto; }
.mr-auto { margin-right: auto; }

.p-0 { padding: 0; }
.p-2 { padding: var(--space-2); }
.p-3 { padding: var(--space-3); }
.p-4 { padding: var(--space-4); }
.p-5 { padding: var(--space-5); }
.p-6 { padding: var(--space-6); }
.py-2 { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.py-4 { padding-top: var(--space-4); padding-bottom: var(--space-4); }
.px-3 { padding-left: var(--space-3); padding-right: var(--space-3); }
.px-5 { padding-left: var(--space-5); padding-right: var(--space-5); }

/* ===================================================================== */
/* Buttons                                                               */
/* ===================================================================== */

.ui-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-brand);
  border-radius: var(--radius-md);
  background: var(--color-brand);
  color: var(--ink-900);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.ui-btn:hover { background: var(--color-brand-dark); border-color: var(--color-brand-dark); }
.ui-btn:disabled, .ui-btn.is-busy { opacity: 0.55; cursor: default; }

.ui-btn--ghost {
  background: var(--color-bg);
  border-color: var(--color-border-strong);
  color: var(--color-text);
  font-weight: var(--weight-medium);
}
.ui-btn--ghost:hover { background: var(--color-bg-mute); border-color: var(--ink-300); }

.ui-btn--danger {
  background: var(--color-bg);
  border-color: var(--color-danger-bg);
  color: var(--color-danger);
  font-weight: var(--weight-medium);
}
.ui-btn--danger:hover { background: var(--color-danger-soft); border-color: var(--color-danger); }

.ui-btn--sm { padding: var(--space-1) var(--space-3); font-size: var(--text-sm); }
.ui-btn--block { width: 100%; }

/* A row of actions (buttons/forms) that wraps cleanly. */
.ui-btn-row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.ui-btn-row form { margin: 0; }

/* ===================================================================== */
/* Links                                                                 */
/* ===================================================================== */

.ui-link-plain {
  color: var(--color-brand-link);
  font-size: var(--text-sm);
  text-decoration: none;
}
.ui-link-plain:hover { text-decoration: underline; }

/* ===================================================================== */
/* Badges / pills                                                        */
/* ===================================================================== */

.ui-badge {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-bg-mute);
  color: var(--color-text-soft);
  white-space: nowrap;
}
.ui-badge--ok      { background: var(--color-success-soft); color: var(--color-success); }
.ui-badge--out     { background: var(--color-danger-bg);    color: var(--color-danger-text); }
.ui-badge--note    { background: var(--color-brand-link);   color: var(--paper); }
.ui-badge--brand   { background: var(--gold-50);            color: var(--color-brand-link); }

/* ===================================================================== */
/* Forms                                                                 */
/* ===================================================================== */

/* A <fieldset> used as a form group is a layout container, not a drawn box.
 * Browsers give it a default 2px groove border plus a legend notch, which
 * showed up as a stray dark outline around "Applies to rental items" once the
 * admin forms moved onto the shared .field class. Reset it here so every
 * fieldset-as-field is flat, and style its legend like a normal field label. */
fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
legend {
  padding: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--color-text-soft);
}

.ui-field { margin-bottom: var(--space-4); }
.ui-field > label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--color-text-soft);
}
.ui-field input[type="text"],
.ui-field input[type="email"],
.ui-field input[type="tel"],
.ui-field input[type="number"],
.ui-field input[type="date"],
.ui-field input[type="password"],
.ui-field input[type="search"],
.ui-field select,
.ui-field textarea {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  font-family: inherit;
  font-size: var(--text-md);
  color: var(--color-text);
}
.ui-field textarea { line-height: var(--leading-base); resize: vertical; }
.ui-field input:focus, .ui-field select:focus, .ui-field textarea:focus {
  outline: 2px solid var(--color-brand);
  outline-offset: 1px;
  border-color: var(--color-brand);
}

/* A short explanatory note under an input. */
.ui-form-note {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* ===================================================================== */
/* Tables                                                                */
/* ===================================================================== */

.ui-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
}
.ui-table { width: 100%; border-collapse: collapse; font-size: var(--text-base); }
.ui-table th, .ui-table td {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
.ui-table th {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-muted);
  font-weight: var(--weight-semibold);
  background: var(--color-bg-soft);
}
.ui-table tbody tr:last-child td { border-bottom: 0; }
.ui-table tbody tr:hover { background: var(--color-bg-soft); }

/* ===================================================================== */
/* Lists                                                                 */
/* ===================================================================== */

.ui-list-plain { list-style: none; margin: 0; padding: 0; }
.ui-list-plain > li { padding: var(--space-2) 0; border-bottom: 1px solid var(--color-border-soft); }
.ui-list-plain > li:last-child { border-bottom: 0; }

/* Icon + text rows, e.g. the contract requirement checklist. */
.ui-checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
.ui-checklist--cols { grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.ui-checklist__item {
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  gap: var(--space-2);
  font-size: var(--text-base);
  line-height: var(--leading-base);
}
.ui-checklist__mark { font-weight: var(--weight-semibold); line-height: var(--leading-base); }
.ui-checklist__item--ok .ui-checklist__mark { color: var(--color-success); }
.ui-checklist__item--missing .ui-checklist__mark { color: var(--color-danger); }

/* ===================================================================== */
/* States                                                                */
/* ===================================================================== */

.ui-empty {
  padding: var(--space-6);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--text-base);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  background: var(--color-bg-soft);
}

.ui-alert {
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
  margin-bottom: var(--space-4);
  border: 1px solid var(--color-border);
  background: var(--color-bg-soft);
}
.ui-alert--danger  { border-color: var(--color-danger-bg); background: var(--color-danger-soft);  color: var(--color-danger-text); }
.ui-alert--success { border-color: var(--green-50);        background: var(--color-success-soft); color: var(--color-success); }
.ui-alert--warn    { border-color: var(--gold-100);        background: var(--gold-50);            color: var(--color-warning); }

/* ===================================================================== */
/* Visibility                                                            */
/* ===================================================================== */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ===================================================================== */
/* Responsive stacking                                                   */
/* ===================================================================== */

.ui-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
@media (max-width: 820px) {
  .ui-split { grid-template-columns: 1fr; }
  .ui-page { padding: var(--space-6) var(--space-4) var(--space-10); }
}

/* ===================================================================== */
/* htmx: request indicator and out-of-band toasts                        */
/* ===================================================================== */

/* An uncued in-place swap just blinks: the old content vanishes and the new
   one appears with no sign anything happened.

   htmx ships the indicator rules itself (includeIndicatorStyles is on by
   default): it hides anything carrying .htmx-indicator, and reveals it while a
   request named in some `hx-indicator` is in flight. So the indicator is just
   an element with class="htmx-indicator", and there is nothing to style here
   except its spacing.

   The indicator must be a SEPARATE, stable element -- never the region being
   swapped. Putting the request state on the swapped node dims and disables the
   very thing being replaced, and on a table section it forces a relayout that
   costs the page its scroll position. */
.contracts-indicator {
  margin: 0 0 var(--space-2);
}

/* Toasts live in the page shell, not in a swappable fragment, so a toast
   survives the swap that triggered it. Fixed so a scrolling container cannot
   clip it, and top-centre so it clears the floating site nav. */
.toast-host {
  position: fixed;
  top: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(28rem, calc(100vw - var(--space-8)));
  pointer-events: none;
}
.toast {
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  box-shadow: var(--shadow-md);
  color: var(--color-text);
  font-size: var(--text-sm);
  pointer-events: auto;
  opacity: 1;
  transition: opacity .2s ease-in-out;
}
.toast--success { border-color: var(--color-success); background: var(--color-success-soft); }
.toast--error,
.toast--danger { border-color: var(--color-danger); background: var(--color-danger-bg); }
.toast--warning { border-color: var(--color-warning); background: var(--color-warning-soft); }
.toast--leaving { opacity: 0; }

/* ------------------------------------------------------- trouble prompt
 *
 * The customer-opt-in "are you having trouble?" ask from errors.js. Fixed to
 * the bottom, above the toast host's stacking context, and never a modal: it
 * must be possible to keep using the page while it is on screen. Nothing here
 * steals focus or scrolls. */
.trouble-prompt {
  position: fixed;
  left: 50%;
  bottom: var(--space-4);
  transform: translateX(-50%);
  z-index: 61;
  width: min(30rem, calc(100vw - var(--space-8)));
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  box-shadow: var(--shadow-md);
  color: var(--color-text);
}
.trouble-prompt__title { margin: 0 0 var(--space-1); font-weight: 600; font-size: var(--text-sm); }
.trouble-prompt__body { margin: 0 0 var(--space-3); font-size: var(--text-sm); color: var(--color-text-soft); }
.trouble-prompt__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
