:root {
  --green-dark: #2d6a4f;
  --green: #40916c;
  --green-light: #d8f3dc;
  /* Buttons: the facility's color, letters that read on it. 5 Oct 2026. */
  --brand-fill: var(--green-dark);
  --on-fill: #fff;
  --accent: var(--green-dark);
  /* Text sitting ON the brand bar, and nowhere else. Sep 3, 2026: words and
     numbers in that lime green belong on the bar and nowhere else -- not in
     the boxes on the page. */
  --on-brand: #d8f3dc;
  --ink: #1b2a22;
  --muted: #5c6b63;
  --bg: #f6f8f6;
  --card: #ffffff;
  --border: #e2e8e4;
  --warn-bg: #fff4e5;
  --warn-text: #8a5a00;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--ink);
}

a { color: var(--green-dark); }

.topbar {
  background: var(--green-dark);
  color: #fff;
  padding: 8px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Two rows at every width: who you are and where you can go on top, the
     find box underneath. Her ruling, 01 Oct 2026 -- on one row the box
     pushed eleven links onto two rows on a 1280 or 1366 laptop, and it did
     that at any box width. */
  flex-wrap: wrap;
  row-gap: 6px;
}

.topbar .brand { font-weight: 700; font-size: 1.1rem; display: inline-flex;
  align-items: center; gap: 8px; }
/* A facility's own logo, scaled to the bar rather than the bar to the logo --
   a tall image must not push the navigation around. */
/* Sized for a SQUARE mark as well as a wide one -- Kawa's is 2000x2000, so a
   slot shaped for a banner rendered it as a small square adrift in the bar. */
.topbar .brand-logo { height: 52px; width: auto; max-width: 260px;
  object-fit: contain; display: block; }
.topbar a.logout { color: var(--on-brand); font-size: 0.9rem; text-decoration: none; }
/* LOG OUT IS A FORM NOW, NOT A LINK. Sep 5, 2026 -- Django 5 refuses a GET on
   logout and the link had been answering 405. The button is dressed as the
   link it replaces so nothing on the bar moves. */
.topbar form.logout-form { display: inline; margin: 0; padding: 0; }
.topbar form.logout-form button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--on-brand); font-size: 0.9rem;
}
.topbar form.logout-form button:hover { text-decoration: underline; }
.topbar .nav-links { display: flex; gap: 18px; flex: 1; margin-left: 28px; }
.topbar .nav-links a { color: var(--on-brand); text-decoration: none; font-size: 0.9rem; }
.topbar .nav-links a:hover { color: #fff; text-decoration: underline; }

/* Find a dog or a person, on the bar of every staff page (Q112, 01 Oct 2026).
   It was `.find-bar` under the dashboard's heading until today; one template
   drew it and nothing else read those rules. Plain form, no type-ahead --
   "I don't wanna drop down list. I wanna just type it in a search bar." */
/* LAST on the bar whatever the markup says, so it takes the second row on
   its own and the links, the theme button and Log out keep the first. */
.topbar-find { display: flex; gap: 6px; align-items: center;
  order: 9; flex: 1 0 100%; margin: 0; }
.topbar-find input[type="search"] {
  flex: 1; min-width: 0; max-width: 420px;
  padding: 6px 10px; font: inherit; font-size: 0.9rem;
  border: 1px solid rgba(255, 255, 255, 0.45); border-radius: 6px;
  background: rgba(255, 255, 255, 0.12); color: #fff;
}
.topbar-find input[type="search"]::placeholder { color: rgba(255, 255, 255, 0.75); }
.topbar-find button {
  background: none; border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 6px; padding: 6px 10px; font: inherit; font-size: 0.9rem;
  color: var(--on-brand); cursor: pointer;
}
.topbar-find button:hover { background: rgba(255, 255, 255, 0.18); }

/* The menu button and the log-out link that lives inside the menu belong to a
   phone only. On anything wider they are not drawn at all. */
.nav-toggle { display: none; }
.topbar .nav-links a.nav-logout { display: none; }
.topbar .nav-links form.nav-logout { display: none; }

.container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 16px;
}

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  margin-bottom: 16px;
}

.card h2, .card h3 {
  margin-top: 0;
}

.stat-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.stat-tile {
  background: var(--green-light);
  border-radius: 8px;
  padding: 10px 14px;
  min-width: 100px;
  text-align: center;
}

.stat-tile .num { font-size: 1.5rem; font-weight: 700; color: var(--green-dark); }
.stat-tile .label { font-size: 0.75rem; color: var(--muted); }

table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }

/* A WIDE TABLE SCROLLS INSIDE ITS CARD. IT DOES NOT RUN OFF THE PAGE.
   Sep 3, 2026, on the bookings list with one client's six dogs in it: the
   money was running over the edge of the page.

   The Dogs column carries a photo, a name, badges, a breed and a room per
   dog, so a six-dog booking pushed the table wider than the card -- and the
   columns that fell off the right were Total and View. The money and the way
   into the booking were the two things you could not see.

   Every table in a card sits in one of these now, and a test fails the build
   if a new one does not. */
.table-scroll { overflow-x: auto; }

/* And a figure never breaks across two lines. "$3,353.50" split after the
   comma reads as two numbers. */
td[data-label="Amount"], td[data-label="Total"], td[data-label="Balance"],
td[data-label="Paid"] { white-space: nowrap; }
th { text-align: left; color: var(--muted); font-size: 0.75rem; text-transform: uppercase; padding: 6px 8px; border-bottom: 1px solid var(--border); }
td { padding: 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.75rem;
  background: var(--green-light);
  color: var(--green-dark);
}

.badge.archived {
  background: #eee;
  color: #666;
}

form.inline { display: flex; gap: 8px; flex-wrap: wrap; align-items: end; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; }

/* The HTML `hidden` attribute has to win over the rule above.
   Added Aug 30, 2026, after a form that rearranges itself did not rearrange.
   `.field { display: flex }` is an AUTHOR rule and the browser's built-in
   `[hidden] { display: none }` is a USER-AGENT rule, so the author rule wins
   and `hidden` silently does nothing on any .field div. Every hidden section
   on the Record Activity form had been visible the whole time, including the
   Where field two deploys earlier, while the JavaScript setting el.hidden ran
   perfectly and had no effect anyone could see.
   This is the CSS version of the same lesson as the browser-required dropdown:
   the code was right and the page was wrong. */
[hidden] { display: none !important; }
/* input[type=time] was missing from this list, so every time field in the app
   rendered with no padding and no border -- shorter than the fields beside it,
   which in a bottom-aligned row drops its label out of line. It was spotted
   on Quick Checkin's Start time, Aug 31, 2026; a first attempt blamed the
   "optional" tag in the label and removed that instead, which changed nothing
   because the label was never the problem. Verify the page, not the theory. */
select, input[type=text], input[type=datetime-local], input[type=date], input[type=time], input[type=number], input[type=password], textarea {
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.9rem;
}

/* A DATE FIELD HAS TO LOOK LIKE A FIELD.  Sep 3, 2026.

   On a phone held upright: Date and Start time were a single
   continuous gray band across the card with no edges and no text, sitting
   between "Dog" and "How long", both of which were plainly white boxes with
   visible borders. They did not read as fields -- they read as nothing being
   there.

   iOS Safari paints its own gray fill on date and time inputs and the pale
   border above disappears into it. The rule above sets padding, border and
   radius on these types and had done since Aug 31; what it never set was a
   background, so on that platform it was overruled by a fill it did not know
   about.

   Not a portrait bug. It was the same in landscape, and on every date field
   in the app -- the narrow screen is only where it became obvious, because
   two of them landed side by side and merged into one bar.

   The same class as the accent color wired to a variable nothing read, and
   the applies_to box that took commas while the seed wrote spaces: a control
   that is silently doing nothing while the code around it looks right. */
input[type=date], input[type=time], input[type=datetime-local] {
  -webkit-appearance: none;
  appearance: none;
  background: var(--card);
  min-height: 38px;
}

/* Admin-locked fields (Aug 25, 2026 fix): every gated field now looks
   consistently locked, whichever control type it is. Before this, only
   <select> fields (Sex, Pet Size) visibly grayed out when disabled — Chrome
   renders disabled <input type=date>/<input type=number> almost identically
   to an enabled one, so Date of Birth, Weight, and Spayed/Neutered looked
   editable even though the server was silently rejecting changes to them
   until "Unlock with admin code" was used. This isn't a logic bug (the
   gating itself was already correct and working) — it's a missing visual
   cue, fixed here. */
select:disabled, input:disabled, textarea:disabled {
  background: var(--bg);
  color: var(--muted);
  border-color: var(--border);
  cursor: not-allowed;
  opacity: 1;
  -webkit-text-fill-color: var(--muted);
}

button, .btn {
  background: var(--brand-fill);
  color: var(--on-fill);
  border: none;
  padding: 9px 16px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  text-decoration: none;
  display: inline-block;
}
button.small, .btn.small { padding: 5px 10px; font-size: 0.8rem; }
button.secondary { background: #fff; color: var(--green-dark); border: 1px solid var(--green-dark); }

.empty { color: var(--muted); font-style: italic; padding: 8px 0; }

.badge.over { background: #fbe9e7; color: #a33; }

/* Dashboard Feeding/Medications record forms (Aug 24, 2026) */
.slot-record-group { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.slot-record { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.slot-record select { padding: 5px 6px; font-size: 0.8rem; }
.done { font-size: 0.8rem; color: var(--green-dark); font-weight: 600; white-space: nowrap; }
/* Q253: a feeding put down and not finished yet -- a link to finish it. */
.slot-open { font-size: 0.8rem; font-weight: 600; color: var(--warn-text); }
.done-row { display: flex; align-items: center; gap: 8px; }
.slot-undo { display: inline; margin: 0; }
.slot-undo button { padding: 3px 8px; font-size: 0.72rem; }

.messages { list-style: none; padding: 0; margin: 0 0 12px; }
.messages li { padding: 10px 14px; border-radius: 6px; margin-bottom: 6px; background: var(--green-light); color: var(--green-dark); }
.messages li.error { background: #fbe9e7; color: #a33; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; }
.form-grid .field.full { grid-column: 1 / -1; }
.checkbox-list { display: flex; flex-direction: column; gap: 6px; max-height: 220px; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px; padding: 10px; }
.checkbox-list label { display: flex; align-items: center; gap: 8px; font-size: 0.9rem; font-weight: normal; }
.detail-row { display: flex; gap: 24px; flex-wrap: wrap; margin-bottom: 6px; }
.detail-row .k { color: var(--muted); font-size: 0.75rem; text-transform: uppercase; }
.detail-row .v { font-size: 0.95rem; }
.actions-row { display: flex; gap: 10px; margin-bottom: 16px; }
@media (max-width: 640px) {
  .form-grid { grid-template-columns: 1fr; }
}

/* Resource calendar */
.calendar-scroll { overflow-x: auto; }
.cal-table { border-collapse: collapse; font-size: 0.82rem; }
.cal-table th, .cal-table td { border: 1px solid var(--border); padding: 4px 6px; text-align: center; vertical-align: top; white-space: nowrap; }
.cal-resource-col { text-align: left; position: sticky; left: 0; background: var(--card); z-index: 1; min-width: 150px; white-space: normal; }
.cal-resource-meta { font-size: 0.72rem; color: var(--muted); font-weight: normal; }
.cal-today { background: var(--green-light); }
.cal-cell { min-width: 92px; height: 30px; }
/* A WHOLE MONTH WITHOUT SCROLLING SIDEWAYS. Sep 3, 2026. Thirty-one columns
   at the fortnight width is 2,800px of swiping, which is the thing this view
   was asked for to avoid. The bar keeps its name; a bar too short to show one
   clips rather than stretching the grid. */
.cal-month .cal-cell { min-width: 26px; }
.cal-month th, .cal-month td { padding: 3px 2px; font-size: 0.74rem; }
.cal-month .cal-resource-col { min-width: 120px; }
.cal-month .cal-pill { overflow: hidden; text-overflow: ellipsis; }
.cal-over { background: #fbe9e7; }
.cal-over-label { font-size: 0.68rem; color: #a33; font-weight: 600; text-transform: uppercase; }
.cal-bar-cell { padding: 3px 4px; text-align: left; }
.cal-pill {
  display: block;
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 0.75rem;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-pill.cal-cont-before { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.cal-pill.cal-cont-after { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.cal-boarding { background: #d8f3dc; }
.cal-board_train { background: #ffe8cc; }
.cal-day_academy { background: #d0ebff; }
.cal-grooming { background: #ffd6e8; }
.cal-training { background: #e5dbff; }
.cal-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 12px; font-size: 0.8rem; color: var(--muted); }
.cal-legend .swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 4px; vertical-align: middle; }
.cal-legend .cal-over-swatch { background: #fbe9e7; border: 1px solid #e0a89f; }

.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-dark);
}
.login-card {
  background: #fff;
  padding: 32px;
  border-radius: 12px;
  width: 320px;
}

/* ---------------------------------------------------------------------------
   A PHONE HELD UPRIGHT.  Sep 3, 2026.

   Relayed from staff: the view on the phone was great in landscape and not so
   good in portrait.

   Landscape was fine because a landscape phone is about as wide as a small
   laptop, so nothing here ever fired. Everything below is what breaks when the
   same page is 390px across instead of 844.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {

  /* 1. THE NAVIGATION RAN OFF THE RIGHT-HAND EDGE AND TOOK THE PAGE WITH IT.
     .nav-links is a single non-wrapping flex row of nine links. On a phone
     held upright it fitted four, and the other five were not scrolled to,
     hidden, or grayed out -- they were simply off the side of the glass with
     no way to reach them. Record Activity was one of them, which is the page
     staff open on a phone more than any other.
     So on a narrow screen the bar becomes two rows: who you are on top, where
     you can go underneath, wrapping as far down as it needs to. */
  .topbar { flex-wrap: wrap; padding: 8px 14px; row-gap: 6px; }
  .topbar .brand { font-size: 1rem; }
  .topbar .brand-logo { height: 34px; max-width: 150px; }
  .topbar .nav-links {
    order: 3;
    flex: 1 0 100%;
    margin-left: 0;
    /* One link per line, behind the Menu button. Nine of them wrapped across
       two rows was already the ceiling -- Sep 3, 2026: add any more links up
       there and it might as well be a hamburger menu.
       Wrapping degrades a link at a time and silently; a menu does not. */
    display: none;
    flex-direction: column;
    gap: 0;
    font-size: 1rem;
    border-top: 1px solid rgba(255, 255, 255, 0.25);
    margin-top: 4px;
    padding-top: 4px;
  }
  .nav-toggle-box:checked ~ .nav-links { display: flex; }
  /* Its own row, above the menu and always drawn. A search box behind the
     Menu button is a search box she cannot reach from where she is. */
  /* On a phone it sits ABOVE the menu list rather than below it, so opening
     the menu does not push the box off the screen. */
  .topbar-find { order: 2; }
  .topbar-find input[type="search"] { max-width: none; }
  /* A whole line to tap, not a word. */
  .topbar .nav-links a { padding: 9px 2px; display: block; }
  .topbar .nav-links a + a { border-top: 1px solid rgba(255, 255, 255, 0.15); }

  /* The button sits ON the brand bar, so it takes the bar's own text color --
     and says so on the line that reads the variable, which is how the accent
     is kept off the rest of the page. */
  .topbar .nav-toggle { color: var(--on-brand); }
  .nav-toggle {
    display: inline-block;
    font-size: 0.95rem;
    font-weight: 600;
    padding: 5px 10px;
    border: 1px solid rgba(255, 255, 255, 0.45);
    border-radius: 6px;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
  }
  /* Open, the button stays lit, so it is obvious what is holding the list
     down and what will put it away again. */
  .nav-toggle-box:checked ~ .nav-toggle { background: rgba(255, 255, 255, 0.18); }

  /* Log out moves into the menu, so the bar is a name and one button. */
  .topbar a.logout { display: none; }
  .topbar form.logout { display: none; }
  .topbar .nav-links a.nav-logout { display: block; }
  .topbar .nav-links form.nav-logout { display: block; }

  /* 2. A STACKED TABLE ROW THAT STILL SAYS WHAT EACH THING IS.
     The old rule hid <thead> and stacked the cells, so an Occupants row read
     as seven unlabeled lines -- "owner / dog / breed / Boarding / Run 3 /
     Paid / 2 days till check-out" -- with nothing saying
     which was the run and which was the breed.
     Now each cell carries its column name from the header (data-label), and
     the cells sit side by side and wrap instead of one per line, so a dog is
     about three lines instead of seven. That is the same objection made about
     feeding an hour earlier: too tall, and it made the page too long. */
  table, tbody, tr, td { display: block; }
  thead { display: none; }
  tr {
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card);
    padding: 8px 10px;
    margin-bottom: 8px;
  }
  td {
    display: inline-block;
    vertical-align: top;
    border: none;
    padding: 3px 16px 3px 0;
    max-width: 100%;
  }
  td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
    font-weight: 600;
  }
  /* The customer is the heading of the block, not one chip among seven. */
  tr > td:first-child { display: block; font-weight: 700; padding-right: 0; }
  tr > td:first-child::before { content: none; }
  /* An action cell with nothing in it must not leave a gap. */
  td:empty { display: none; }

  /* The handling-rule line belongs to the dog above it. Left as its own
     stacked block it floated free of the booking it warns about -- which on a
     safety line is not a cosmetic problem. */
  tr.handling-row {
    margin-top: -8px;
    border-top: none;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    padding-top: 4px;
  }
  tr.handling-row td { display: block; padding: 0; }

  /* 3. THE FORMS.
     form.inline bottom-aligns a row of fields, which on a phone squeezed Date,
     Start time and How long into slivers. Two to a row, and full width for
     anything that needs the space. */
  .stat-row { justify-content: space-between; }
  .stat-tile { min-width: 40%; flex: 1; }
  form.inline { align-items: stretch; }
  form.inline .field { flex: 1 1 140px; }
  form.inline .field select,
  form.inline .field input { width: 100%; }

  /* The resource calendar is a real grid and must stay one -- it already
     lives inside .calendar-scroll, which swipes sideways. Stacking it turned
     a week's occupancy into a column of dates. */
  .calendar-scroll table { display: table; }
  .calendar-scroll thead { display: table-header-group; }
  .calendar-scroll tbody { display: table-row-group; }
  .calendar-scroll tr { display: table-row; border: none; border-radius: 0;
    background: none; padding: 0; margin: 0; }
  .calendar-scroll td, .calendar-scroll th { display: table-cell;
    border: 1px solid var(--border); padding: 4px 6px; }
  .calendar-scroll td::before { content: none; }

  /* 4. A card should not spend a fifth of the screen on its own margins. */
  .container { padding: 12px 10px; }
  .card { padding: 12px; }
}

/* Customers list (Aug 25, 2026 — item 1) */
.az-filter { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.az-letter { display: inline-block; min-width: 22px; text-align: center; padding: 3px 6px; border-radius: 4px; font-size: 0.8rem; text-decoration: none; color: var(--green-dark); border: 1px solid var(--border); }
.az-letter.active, .az-letter:hover { background: var(--green-light); }
.pet-chip-row { display: flex; flex-wrap: wrap; gap: 10px 20px; }
.pet-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 0.9rem; text-decoration: none; color: var(--ink); position: relative; }
.pet-chip img, .pet-chip-noimg { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; background: var(--green-light); display: inline-flex; align-items: center; justify-content: center; font-size: 1.1rem; }
.pet-chip img { transition: transform 0.15s ease-out, border-radius 0.15s ease-out; transform-origin: left center; cursor: zoom-in; }
.pet-chip:hover { z-index: 30; }
.pet-chip:hover img { transform: scale(3.25); border-radius: 8px; box-shadow: 0 6px 18px rgba(0,0,0,0.35); border: 2px solid #fff; }

/* Pet "block" style (Aug 26, 2026 — just the photo and the dog's name, one for
   each dog — photo on top, name underneath, one clearly separated
   block per pet. Used on Booking pages and Customer Detail's bookings tables.
   Replaces the earlier inline pet-chip-row-compact attempt on those pages. */
.pet-block-row { display: flex; flex-wrap: wrap; gap: 14px 18px; }
.pet-block { display: flex; flex-direction: column; align-items: center; text-decoration: none; color: var(--ink); width: 72px; text-align: center; }
.pet-block img, .pet-block-noimg { width: 60px; height: 60px; border-radius: 10px; object-fit: cover; background: var(--green-light); display: flex; align-items: center; justify-content: center; font-size: 1.4rem; }
.pet-block .name { margin-top: 5px; font-size: 0.82rem; font-weight: 600; line-height: 1.2; word-break: break-word; }

/* Compact variant for Booking pages (Aug 26, 2026 — doesn't need to be
   as big as the Customer page's version, but needs clear separation). */
.pet-block-row-compact { gap: 10px 14px; }
.pet-block-row-compact .pet-block { width: 46px; }
.pet-block-row-compact .pet-block img,
.pet-block-row-compact .pet-block-noimg { width: 40px; height: 40px; border-radius: 8px; font-size: 1.05rem; }
.pet-block-row-compact .pet-block .name { font-size: 0.7rem; margin-top: 3px; }

/* Booking Detail page — bordered photo-card grid for the main Pet(s) list
   (Aug 26, 2026 — an actual drawing was sent after the pet-block attempt
   above still wasn't right: bordered box per dog, photo filling most of the
   box, name bold underneath, wrapping into rows; the per-resource-assignment
   list below it should show plain dog names only, no photos — see the
   removal of .pet-block-row from that spot in booking_detail.html). Scoped
   to the Booking Detail page only, per an explicit answer — the
   Bookings list table and Customer Detail's booking tables keep the
   existing compact .pet-block-row-compact treatment above. Cards remain
   clickable through to the dog's own Pet Detail page. */
.pet-card-grid { display: flex; flex-wrap: wrap; gap: 14px; margin: 6px 0 4px; }
.pet-card { display: flex; flex-direction: column; align-items: center; width: 120px; padding: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--card); box-shadow: 0 1px 3px rgba(0,0,0,0.08); text-decoration: none; color: var(--ink); transition: box-shadow 0.15s ease, transform 0.15s ease; }
.pet-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.15); transform: translateY(-2px); }
.pet-card img, .pet-card-noimg { width: 100px; height: 100px; border-radius: 8px; object-fit: cover; background: var(--green-light); display: flex; align-items: center; justify-content: center; font-size: 2rem; }
.pet-card .name { margin-top: 8px; font-weight: 700; text-align: center; word-break: break-word; }

/* Customers list — photo-card grid (requested Aug 25, 2026) */
.customer-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 18px; margin-top: 14px; }
.customer-card { display: block; background: var(--card); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; text-decoration: none; color: var(--ink); transition: box-shadow 0.15s ease, transform 0.15s ease; }
.customer-card:hover { box-shadow: 0 6px 16px rgba(0,0,0,0.10); transform: translateY(-2px); }
.customer-card-photo { position: relative; width: 100%; aspect-ratio: 4 / 3.3; background: var(--green-light); overflow: hidden; }
.customer-card-photo-strip { display: flex; width: 100%; height: 100%; will-change: transform; }
.customer-card-photo-slot { flex: 0 0 100%; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.customer-card-photo-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.customer-card-photo-slot .placeholder-icon { font-size: 2.6rem; opacity: 0.45; }
.customer-card-body { padding: 12px 14px 14px; }
.customer-card-name { font-weight: 700; font-size: 1.05rem; margin: 0 0 10px; color: var(--ink); }
.customer-card-field { margin-bottom: 8px; }
.customer-card-field:last-child { margin-bottom: 0; }
.customer-card-field .k { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); margin-bottom: 3px; }
.customer-card-field .v { font-size: 0.9rem; }
.customer-card-field .v.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.k9-pill { display: inline-block; background: var(--green-light); color: var(--green-dark); font-size: 0.78rem; padding: 2px 9px; border-radius: 10px; margin: 0 4px 4px 0; }
.email-pill { display: inline-block; background: var(--brand-fill); color: var(--on-fill); font-size: 0.8rem; padding: 3px 10px; border-radius: 10px; }


.pet-photo-gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.pet-photo-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.pet-photo-item img {
  width: 120px;
  height: 120px;
  border-radius: 8px;
  object-fit: cover;
  border: 1px solid var(--border);
  background: var(--green-light);
}

.badge.deceased { background: #2f2f2f; color: #e8c468; }

.pet-memorial-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
  vertical-align: middle;
}
.pet-memorial-badge img {
    height: 44px;
  width: auto;
  display: block;
  background: none;
  border-radius: 0;
  object-fit: contain;
}

/* ---------------------------------------------------------------------------
   Safety surfaces (safety and handling model §5, §13) — Aug 28, 2026.

   Color discipline, agreed Aug 28: RED is reserved for a dog-safety
   fact — an active handling rule, or a No-Go with a dog currently on property.
   AMBER is everything administrative: vaccinations, medications, stale
   verdicts. If red comes to mean four different things it stops meaning any of
   them, and staff learn that red means "that client's dogs, as usual".

   A border alone says "look", not "why" — so every red surface here carries a
   reason next to it, never a bare outline.
--------------------------------------------------------------------------- */

.safety-alert {
  border: 3px solid #c62828;
  border-radius: 8px;
  background: #fdf3f3;
  padding: 10px 14px;
  margin: 12px 0;
}

.safety-alert-label {
  color: #c62828;
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 4px;
}

.safety-alert-list {
  margin: 0;
  padding-left: 18px;
}

.safety-alert-list li { margin: 2px 0; }

/* Compact inline version for cards on list/overview screens. */
.safety-flag {
  display: block;
  gap: 5px;
  border: 2px solid #c62828;
  border-radius: 5px;
  background: #fdf3f3;
  color: #a01c1c;
  font-size: 0.74rem;
  font-weight: 600;
  line-height: 1.25;
  padding: 2px 6px;
  margin-top: 4px;
  max-width: 100%;
  text-align: left;
}

/* The marker used where a flag has no room for words -- a 46px pet chip in
   a list. The title attribute is unchanged, so hovering still gives the full
   rule text, which is the part actually used: scrolling over it tells you
   everything. The words themselves move to .handling-line. */
/* A dog that went home before the money did. Deliberately still visible
   after the client pays -- the debt gets settled, the night it happened
   does not get unhappened. */
/* Weight (Aug 30, 2026). A flag is an open question, so it looks like one
   until somebody answers it. */
/* ⛔ "edit" IS A WRITE CONTROL, so it stopped being a faint gray caption on
   12 Sep 2026 -- same rule as `summary.opens` at the foot of this file. It
   keeps its small size, because it sits beside the thing it corrects and the
   page must not shout; what it loses is the 0.65 opacity and the gray that
   made the eye skip it. */
.amend > summary {
  cursor: pointer;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--accent, #2d6a4f);
  text-decoration: underline;
  text-underline-offset: 2px;
  list-style: none;
}
.amend > summary:hover { color: var(--green-dark); }
.amend[open] > summary { opacity: 1; }
.amend-was {
  font-size: 0.72rem;
  color: var(--muted);
  margin: 3px 0 0;
  font-style: italic;
}

.typeahead-hits {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 40;
  min-width: 260px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.15);
  overflow: hidden;
}
.typeahead-hit {
  display: block;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}
.typeahead-hit:hover, .typeahead-hit:focus { background: var(--green-light); }
.typeahead-none { padding: 7px 10px; font-size: 0.82rem; color: var(--muted); }

.weight-pattern {
  background: var(--green-light, #eaf3ec);
  border-radius: 6px;
  padding: 8px 10px;
  margin: 8px 0;
  font-size: 0.86rem;
}
.weight-stay { margin: 8px 0; }
.weight-stay > summary {
  cursor: pointer;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
}
.weight-stay > summary:hover { background: var(--green-light, #eaf3ec); }
.weight-older > summary {
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--muted);
  padding: 4px 0;
}
.weight-down { color: #a01c1c; }
.weight-up { color: #2e6b3a; }

.weight-flag {
  border-left: 4px solid #c62828;
  background: #fdf3f3;
  padding: 8px 10px;
  margin: 6px 0;
  border-radius: 0 6px 6px 0;
  color: #a01c1c;
}
.weight-flag-inline {
  color: #a01c1c;
  font-size: 0.74rem;
  font-weight: 600;
  margin-top: 2px;
}
.weight-change { color: #a01c1c; font-weight: 600; }
/* The weight chart. Rebuilt 18 Sep 2026.

   It used to be squeezed into a fixed 300 wide with no labels on it at all,
   and the only two numbers on the card sat in the bottom corners where dates
   belong. Nobody could read that unless they were a computer. Every point now
   prints its weight and its date, so the drawing is
   as wide as it needs to be and this box scrolls sideways instead of crushing
   the labels together. */
.weight-chart-wrap {
  margin: 10px 0 4px;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}
.weight-chart {
  height: auto;
  color: var(--green-dark, #2e5d3a);
  overflow: visible;
}
.weight-chart .wc-rule { stroke: var(--line, #d8d8d8); stroke-width: 1; }
.weight-chart .wc-val {
  font-size: 11px;
  font-weight: 600;
  fill: currentColor;
}
.weight-chart .wc-day { font-size: 10px; fill: var(--muted, #6b6b6b); }
.weight-chart .wc-edge { font-size: 10px; fill: var(--muted, #6b6b6b); }
.weight-chart-scale {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  color: var(--muted);
}

.went-home-owing {
  color: #a01c1c;
  font-size: 0.74rem;
  font-weight: 600;
}

.safety-flag-mark {
  display: inline-block;
  margin-top: 3px;
  color: #c62828;
  font-size: 0.95rem;
  line-height: 1;
  cursor: help;
}

/* One line per booking, naming each rule once, full width of the table. */
.handling-row td {
  border-top: 0;
  padding-top: 0;
  padding-bottom: 10px;
}
.handling-line {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  align-items: baseline;
  font-size: 0.78rem;
}
.handling-line-label {
  color: #a01c1c;
  font-weight: 700;
  white-space: nowrap;
}
.handling-line-rule {
  border: 1px solid #e0b4b4;
  background: #fdf3f3;
  color: #a01c1c;
  border-radius: 4px;
  padding: 1px 6px;
  font-weight: 600;
}
.handling-line-pets { font-weight: 500; opacity: 0.85; }

.pet-card.has-safety-flag,
.pet-block.has-safety-flag {
  border: 2px solid #c62828;
  border-radius: 8px;
  padding: 6px;
}

.handling-rule-row {
  padding: 8px 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  flex-wrap: wrap;
  border-left: 4px solid #c62828;
}

.handling-rule-lift {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.handling-rule-lift input[type="text"] { max-width: 190px; }

.verdict-signoff { font-style: italic; }

/* "Not assessed" must never read as "fine" — safety model §2. */
.verdict-unsigned {
  color: #8a6d00;
  background: #fff6d8;
  border: 1px solid #e0c66a;
  border-radius: 4px;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 1px 6px;
}


/* Payment STATUS badges — visible to everyone, unlike amounts.
   Staff need to know a booking is settled before a dog leaves; they do not
   need the figures (Aug 28, 2026). */
.pay-badge {
  display: inline-block; font-size: 0.72rem; font-weight: 700;
  padding: 1px 7px; border-radius: 4px; letter-spacing: 0.02em;
}
.pay-badge.paid   { background: #d8f3dc; color: #1b5e33; border: 1px solid #a9d9bb; }
.pay-badge.part   { background: #fff6d8; color: #8a6d00; border: 1px solid #e0c66a; }
.pay-badge.unpaid { background: #fdf3f3; color: #a01c1c; border: 1px solid #e0a0a0; }

/* The amount on a bookings row is context, not the headline. 12 Sep 2026 --
   What matters on the list is not the total of the invoice or the booking --
   it is whether the booking has been paid or not. So the figure recedes and
   the badge under it is what the eye
   lands on while she reads down a week of arrivals. */
.booking-rows .row-amount { color: #6b625a; font-size: 0.88rem; }
.booking-rows td.num .pay-badge { margin-top: 2px; }


/* Codes — the general classification mechanism (config inventory §3.3).

   THE COLOR DISCIPLINE, and it is the whole reason a code carries a kind:

     RED    the dog's physical safety, or a person's. Biter. Dog Reactive.
            A food allergy, if the facility says so.
     AMBER  administrative. Early pickup. Paperwork.
     SLATE  identity and classification. Working Dog. Service Dog. Trailing.

   Red never means paperwork (safety model §13.3). The moment an
   administrative code borrows red, red stops meaning "stop and read" and
   every genuinely dangerous dog loses its only visual claim on attention.
   That is why the color is decided by the code's kind rather than by whoever
   types the label. */
.code-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin: 8px 0 4px;
}
.code-badge, .code-badge-sm {
  display: inline-block; border-radius: 4px; font-weight: 600;
}
.code-badge { font-size: 0.76rem; padding: 2px 8px; }
.code-badge-sm {
  font-size: 0.68rem; padding: 0 5px; margin: 0 4px 2px 0; border-radius: 3px;
}

.code-badge.slate, .code-badge-sm.slate {
  background: #e8eef5; color: #24405c; border: 1px solid #adc0d4;
}
.code-badge.amber, .code-badge-sm.amber {
  background: #fff6d8; color: #8a6d00; border: 1px solid #e0c66a;
}
/* Red carries the heavier border deliberately — it has to survive being one
   badge among six on a booking card. */
.code-badge.red, .code-badge-sm.red {
  background: #fdf3f3; color: #a01c1c; border: 2px solid #c62828;
}

/* Handling notes print under the strip rather than living in a tooltip. Staff
   work from an iPad a great deal, where there is no hover, and a note that
   only exists on hover may as well not exist at 6am. */
.code-note { font-size: 0.76rem; color: #5b6b7c; font-style: italic; }
.code-note.red { color: #a01c1c; font-style: normal; font-weight: 600; }

/* Picker — grouped by kind, because this list only ever grows. */
.code-group-label {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: #35506b; margin: 10px 0 2px;
}
.code-group-label.safety { color: #a01c1c; }
.code-group-label.care { color: #8a6d00; }
.code-group-label.operational { color: #8a6d00; }

.code-picker { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 2px 0 6px; }
.code-pick {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.84rem; font-weight: normal; white-space: nowrap;
}
.code-pick input { margin: 0; }

/* Nesting, shown by indent and a rule rather than by a tree widget. SAR is an
   umbrella, not a peer — area search, trailing, tracking and HRD sit inside
   it, and a picker that offers SAR beside HRD tells any handler at a glance
   that the software was not built by one. */
.code-pick.depth-1, .code-pick.depth-2, .code-pick.depth-3 {
  border-left: 2px solid #cfd8e0; padding-left: 8px;
}
.code-pick.depth-1 { margin-left: 10px; }
.code-pick.depth-2 { margin-left: 24px; }
.code-pick.depth-3 { margin-left: 38px; }

.code-add {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px dashed #cfd8e0;
}

/* Collapsed by default — most dogs at most kennels carry no codes at all, and
   they should not carry the editing form on every page view (Aug 28).

   But collapsed is not the same as invisible. On Aug 30 somebody went looking for
   where to mark a dog a Service Dog Candidate and could not find it: this sat
   directly above Handling Rules and Buddy/No-Go, both of which show a real
   button, so the only hidden control on the page was the one being hunted for.
   It stays collapsed and it looks like something you can press. */
.code-details > summary {
  cursor: pointer; width: fit-content; margin-top: 10px;
  list-style: none;
}
.code-details > summary::-webkit-details-marker { display: none; }
.code-details > summary.disclosure-button {
  display: inline-block; padding: 6px 14px;
  font-size: 0.85rem; font-weight: 600; color: #35506b;
  background: #fff; border: 1px solid #35506b; border-radius: 5px;
}
.code-details > summary.disclosure-button::before { content: "+ "; font-weight: 700; }
.code-details > summary.disclosure-button:hover { background: #eef3f8; }
.code-details[open] > summary.disclosure-button::before { content: "\2212 "; }
.code-details[open] > summary { margin-bottom: 8px; }

.btn.code-btn { background: #35506b; border-color: #35506b; color: #fff; }
.btn.code-btn:hover { background: #2a4157; }

/* Staged bookings: blocks, not a table.
   Aug 31, 2026. Ten columns of form controls needed a horizontal scrollbar,
   and a row you have to drag sideways is a row whose right-hand end nobody
   reads -- Cost, "Then what" and Remove were all off the edge. It should be
   longer, so there is no need to scroll. Each staged booking is now
   a block whose fields wrap, so it grows down the page. Same shape works on a
   phone, which is where the staff app lives. */
.staged-row {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 10px;
}
.staged-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.staged-head > div { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.staged-fields { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: end; }

/* The booking flow's step 1 (Aug 31, 2026). The rail is a real sequence, so
   the numbers carry information rather than decorating the page. */
.steps-rail { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.step-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 6px 11px; border: 1px solid var(--border); border-radius: 4px;
  background: #fff; color: var(--muted); font-size: 0.82rem;
}
.step-chip b { font-variant-numeric: tabular-nums; }
.step-chip.now { border-color: var(--green-dark); color: var(--text); box-shadow: inset 0 -3px 0 var(--green-dark); }

.segmented { display: flex; flex-wrap: wrap; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.segmented button {
  flex: 1 1 auto; padding: 9px 14px; border: 0; border-right: 1px solid var(--border);
  background: #fff; color: var(--muted); font-size: 0.9rem; font-weight: 600; cursor: pointer;
}
.segmented button:last-child { border-right: 0; }
.segmented button.on { background: var(--brand-fill); color: var(--on-fill); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--green-light); color: var(--green-dark);
  border-radius: 4px; padding: 4px 8px; font-size: 0.9rem; font-weight: 600;
}
.chip button { border: 0; background: transparent; color: inherit; cursor: pointer; font-size: 1rem; line-height: 1; padding: 0; }

.family { margin-top: 10px; padding: 10px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; }
.family-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.family-rule { margin: 0; font-size: 0.82rem; color: var(--muted); }

.typeahead-none { padding: 8px 10px; color: var(--muted); font-size: 0.9rem; }

/* Space proposals. "Propose, you choose" was chosen over auto-assigning, and
   a busy space is still offered — warn, don't block. */
.space-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }
.space {
  display: flex; flex-direction: column; gap: 3px; text-align: left; cursor: pointer;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--card); color: var(--ink); font-family: inherit; font-size: 0.9rem;
}
/* ⭐ 3 Oct 2026: the cards were painted white with a color that was never
   defined, so on the dark look the kennel names were light text on white --
   "nearly invisible." They take the page's own colors now. */
.space:hover { border-color: var(--green-dark); }
.space-name { font-weight: 700; font-size: 0.98rem; }
.space-free { color: var(--green-dark); font-weight: 600; font-size: 0.82rem; }
.space-warn { color: var(--warn-text); font-size: 0.82rem; }
.space-busy { background: var(--warn-bg); }

/* Moving a dog between spaces, from the booking page (Aug 31, 2026). */
.move-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 6px; }
.move-row strong { min-width: 90px; }
.move-row select, .move-row input[type=text] { padding: 5px 7px; font-size: 0.88rem; }
.move-row input[type=text] { width: 160px; }

/* The pricing page (Aug 31, 2026). The worked figure beside each price is the
   point of the screen: every drifted number found in KennelBooker was caught
   by doing this arithmetic, and none was visible as a price on its own. */
.worked { color: var(--muted); font-variant-numeric: tabular-nums; }
.note-line {
  border-left: 3px solid var(--border); padding: 8px 12px;
  color: var(--muted); background: var(--bg); border-radius: 4px;
}

/* Discounts and comped sessions, shown as lines beside the quote (Aug 31, 2026). */
.adjustment-void { opacity: 0.62; }
.adjustment-void > strong { text-decoration: line-through; }
.adjustment { margin-top: 6px; font-size: 0.9rem; }
.adjust-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 8px; }
.adjust-row select, .adjust-row input { padding: 5px 7px; font-size: 0.88rem; }

/* Extras, step 3 of a booking (Aug 31, 2026). */
.extras-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(18rem,1fr)); gap: 8px; }
.extra { display: flex; gap: 8px; align-items: flex-start; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer; font-weight: 400; }
.extra:hover { border-color: var(--green-dark); }

/* The step rail goes backwards (Aug 31, 2026). A step already passed is a
   button; a step ahead is not somewhere you can jump to. */
button.step-chip { font-family: inherit; font-size: 0.82rem; cursor: pointer; }
button.step-chip:hover { border-color: var(--green-dark); color: var(--text); }
.step-chip.ahead { opacity: 0.55; }

.shared-offer { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 6px; }

/* A line waiting on an answer reads red, so it is not mistaken for a price
   that has already been worked out. Aug 31, 2026: those words go red. */
.needs-answer { color: #a3321a; }

/* Putting each dog in a room, one click per dog (Aug 31, 2026). */
.seating { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.seat {
  display: inline-flex; gap: 6px; align-items: baseline;
  background: var(--green-light); color: var(--green-dark);
  border-radius: 4px; padding: 5px 9px; font-size: 0.9rem;
}
.seat-empty { background: var(--bg); color: var(--muted); border: 1px dashed var(--border); }
/* ⭐ 3 Oct 2026: the dogs sit beside "Free for those dates", and each one is
   pressed to pick it, then its kennel. Any one dog comes back out on its own. */
.seat-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px;
  scroll-margin-top: 16px; }
.seat-head h3 { margin: 0; }
.seat-head .seating { margin-top: 0; }
.seat { align-items: center; padding: 0; overflow: hidden; }
.seat-dog { background: none; border: 0; color: inherit; font: inherit;
  padding: 5px 9px; cursor: pointer; display: inline-flex; gap: 6px; align-items: baseline; }
.seat-picked { outline: 2px solid var(--green); outline-offset: 1px; }
.seat-out { background: none; border: 0; border-left: 1px solid var(--border);
  color: inherit; font: inherit; font-size: 0.8rem; padding: 5px 8px; cursor: pointer; }
.seat-out:hover { text-decoration: underline; }
.seat-help { color: var(--muted); font-size: 0.85rem; margin: 6px 0 12px; }
.space-ours { color: var(--green-dark); font-weight: 600; font-size: 0.85rem; }
/* A room you have put a dog in goes green, so somebody placing six dogs can
   see at a glance which rooms they have already used. Aug 31, 2026: the
   clicked color goes green, so whoever is placing dogs can see right away
   that they have two, three or more assigned. */
.space-taken-by-us {
  background: var(--green-light);
  border-color: var(--green-dark);
  box-shadow: inset 0 0 0 2px var(--green-dark);
}
.space-taken-by-us .space-name { color: var(--green-dark); }


/* The way into a booking from a dashboard row. Sep 3, 2026.

   A plain link, not a button -- a picture of what was wanted was sent after
   the first attempt used the small secondary button style: "I don't want a
   visible open link. I really like the little view link. So not that it says
   open. I think it should say view."

   It takes the facility's own link color like every other link on the page,
   so it stays quiet next to the Check In and Check Out buttons, which are the
   things a person is actually reaching for on those rows. */
.row-view { font-weight: 600; text-decoration: none; white-space: nowrap; }
.row-view:hover { text-decoration: underline; }


/* Viewing as somebody else, outside Settings. Deliberately loud: an owner
   looking through a kennel tech's eyes must never forget they are. */
.view-as-bar {
  background: var(--warn-bg);
  color: var(--warn-text);
  border-bottom: 2px solid var(--warn-text);
  padding: 8px 20px;
  font-size: 0.88rem;
}
.view-as-bar a { color: var(--warn-text); font-weight: 700; margin-left: 10px; }


/* Feeding and medications as one block per dog rather than one wide table row.
   Sep 3, 2026: too tall, and it made the page too long. The old
   shape repeated a staff dropdown and a button per slot per dog inside a
   table cell, so a dog cost several inches whether it ate once or three
   times. */
.slot-cards {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.slot-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  background: var(--card);
}
.slot-card-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.slot-card-who { font-weight: 700; text-decoration: none; }
.slot-card-room {
  font-size: 0.78rem;
  color: var(--muted);
  text-decoration: none;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0 7px;
}
.slot-card-note {
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 3px;
  line-height: 1.35;
}
.slot-card-slots {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.slot-card-slots .slot {
  flex: 1 1 90px;
  min-width: 92px;
  border-top: 2px solid var(--border);
  padding-top: 5px;
}
.slot-when { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted); }
.slot-amount { font-size: 0.82rem; margin: 1px 0 5px; }
.slot-card-slots select { width: 100%; font-size: 0.78rem; padding: 2px 4px; }
.slot-card-slots button { width: 100%; margin-top: 3px; }
.slot-none { font-size: 0.8rem; color: var(--muted); }

/* ONE LINE PER DOG. Sep 3, 2026 -- one client's six dogs were reading as three
   comma-separated lists. The ask: "the pictures, the name, the canine, the
   triangle, laboratory retriever, and their run all are in a row. Everything
   is stacked neatly on top of each other, but they're all in a nice row."
   Each dog's facts sit together, so they cannot fall out of alignment the way
   three separate columns did. */
/* A GRID, so the columns line up. Sep 3, 2026 -- the first version was a
   flowing line per dog, and a dog with no K9 badge had his breed and room
   sitting a badge's width left of everyone else's. The names all need to start
   left-justified, and the badges too -- otherwise nothing lines up.

   Five auto columns, so each takes the width of its widest entry across every
   dog on the booking and they all begin on the same vertical line. It is also
   how you check six dogs are in six different runs at a glance -- a column you
   can run your eye down, instead of reading every line. */
.dog-lines { display: grid; grid-template-columns: auto auto auto auto auto auto;
             justify-content: start; align-items: center; gap: 5px 10px; }
.dog-photo { display: inline-flex; }
.dog-photo img, .dog-photo .pet-chip-noimg {
  width: 26px; height: 26px; border-radius: 50%; object-fit: cover;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--chip); font-size: 0.8rem; }
.dog-name { font-weight: 600; text-decoration: none; white-space: nowrap; }
/* Codes and the triangle are SEPARATE columns. Sharing one meant a dog with no
   K9 badge had his triangle slide left into the gap and stop lining up with
   everyone else's. Sep 3, 2026 -- the triangles all need to be left
   justified. */
.dog-codes, .dog-flag { display: inline-flex; align-items: center; gap: 4px;
                        white-space: nowrap; }
.dog-line-breed { color: var(--muted); font-size: 0.8rem; white-space: nowrap; }
.dog-line-room { font-size: 0.78rem; font-weight: 600;
                 border: 1px solid var(--line); border-radius: 999px;
                 padding: 1px 8px; white-space: nowrap; }

/* On a phone five columns do not fit, and the dashboard IS a phone surface.
   The breed goes rather than the alignment: at a kennel door the name, the
   safety badge and the room are what somebody is reading, and breed is on the
   dog's own page. Four columns still line up. Sep 3, 2026. */
@media (max-width: 640px) {
  .dog-lines { grid-template-columns: auto auto auto auto auto; }
  .dog-line-breed { display: none; }
}

/* ---------------------------------------------------------------------------
   THE HOUSE PAGE PATTERN -- the client and dog records, redrawn.

   Sep 4, 2026. Designed with the facility in two published sandboxes and
   recorded in the project documents: identity header,
   then the one thing that must never be hidden, then facts in cards with
   their own Edit, then ONE tabbed card, then buttons and locks that follow
   the role.

   Used by customer_preview.html and pet_preview.html. Nothing else reads
   these yet, and nothing is being restyled underneath anybody.
   --------------------------------------------------------------------------- */

/* Two columns on a desktop, one on a phone. Facts on the left, what is
   happening on the right. */
.pv-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); gap: 18px; align-items: start; }
@media (max-width: 900px) { .pv-cols { grid-template-columns: minmax(0, 1fr); } }

/* Facts as label-and-value pairs. Read as text; a card becomes its own form
   only when somebody presses that card's Edit. */
dl.facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 5px 16px; margin: 0; }
dl.facts dt { color: var(--muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.03em; padding-top: 2px; }
dl.facts dd { margin: 0; font-size: 0.92rem; }
dl.facts dd.mono { font-variant-numeric: tabular-nums; }
@media (max-width: 480px) { dl.facts { grid-template-columns: minmax(0, 1fr); gap: 2px; } dl.facts dd { margin-bottom: 8px; } }

/* Who may change this card, said on the card rather than found out by
   pressing something. */
.whocan { font-size: 0.72rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; margin-left: 8px; }
.card h2 .whocan, .card h3 .whocan { vertical-align: middle; }

/* THE TABS, WITHOUT JAVASCRIPT.

   Radio buttons and labels, the same reasoning as the phone menu in base.html:
   the only way to the rest of a dog's record must not depend on a script
   loading. The radios are moved off-screen rather than display:none, so they
   stay in the tab order and a keyboard still walks the strip.

   Positional classes (t1..t8 / l1..l8 / p1..p8) rather than one rule per tab
   name, so a page can name its own tabs and this block never has to be
   edited again to add one. */
.tabbed { position: relative; }
.tabbed > input.tp { position: absolute; left: -9999px; width: 1px; height: 1px; }
.tab-strip { display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--border); margin: 0 -16px 14px; padding: 0 16px; }
.tab-strip label { padding: 10px 14px; cursor: pointer; font-weight: 600; font-size: 0.85rem;
                   color: var(--muted); border-bottom: 3px solid transparent; margin-bottom: -1px; }
.tab-strip label:hover { color: var(--ink); }
.tab-strip label .n { font-weight: 400; font-size: 0.78rem; color: var(--muted); margin-left: 5px; font-variant-numeric: tabular-nums; }
.tab-strip label .lk { font-weight: 400; font-size: 0.78rem; margin-left: 5px; }
.tab-page { display: none; }

.tabbed > .t1:checked ~ .tab-strip .l1,
.tabbed > .t2:checked ~ .tab-strip .l2,
.tabbed > .t3:checked ~ .tab-strip .l3,
.tabbed > .t4:checked ~ .tab-strip .l4,
.tabbed > .t5:checked ~ .tab-strip .l5,
.tabbed > .t6:checked ~ .tab-strip .l6,
.tabbed > .t7:checked ~ .tab-strip .l7,
.tabbed > .t8:checked ~ .tab-strip .l8 {
  color: var(--green-dark); border-bottom-color: var(--green-dark); background: var(--card);
}

.tabbed > .t1:focus-visible ~ .tab-strip .l1,
.tabbed > .t2:focus-visible ~ .tab-strip .l2,
.tabbed > .t3:focus-visible ~ .tab-strip .l3,
.tabbed > .t4:focus-visible ~ .tab-strip .l4,
.tabbed > .t5:focus-visible ~ .tab-strip .l5,
.tabbed > .t6:focus-visible ~ .tab-strip .l6,
.tabbed > .t7:focus-visible ~ .tab-strip .l7,
.tabbed > .t8:focus-visible ~ .tab-strip .l8 { outline: 2px solid var(--green); outline-offset: -2px; }

.tabbed > .t1:checked ~ .p1,
.tabbed > .t2:checked ~ .p2,
.tabbed > .t3:checked ~ .p3,
.tabbed > .t4:checked ~ .p4,
.tabbed > .t5:checked ~ .p5,
.tabbed > .t6:checked ~ .p6,
.tabbed > .t7:checked ~ .p7,
.tabbed > .t8:checked ~ .p8 { display: block; }

/* The identity line at the top of a record. */
.pv-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 6px; }
.pv-head h1 { margin: 0; font-size: 1.7rem; }
.pv-head .sub { color: var(--muted); font-size: 0.95rem; }
.pv-photo { width: 68px; height: 68px; border-radius: 10px; object-fit: cover; border: 1px solid var(--border); }

/* The read-only banner. These two pages cannot save anything, and saying so
   is cheaper than somebody discovering it by typing into a field that was
   never going to keep it. */
.pv-readonly { background: var(--warn-bg); color: var(--warn-text); border: 1px solid #f0d9ab;
               border-radius: 8px; padding: 9px 14px; margin-bottom: 14px; font-size: 0.88rem; }

.mono { font-variant-numeric: tabular-nums; }


/* THE THREE ANSWERS ON A REGISTRATION QUESTION. Sep 5, 2026.
   No · Yes · Unsure or don't know, laid out along one line so the choice is a
   glance rather than a dropdown to open. Three states -- yes, no, unsure or
   don't know -- because they might not know. */
.q-answers { display: flex; flex-wrap: wrap; gap: 16px; margin: 4px 0 6px; }
.q-pick { font-weight: 400; display: inline-flex; align-items: center; gap: 5px; }
.q-pick input { margin: 0; }

/* ⭐ PRACTICE — the client who ships with the software. Sep 7, 2026.

   Deliberately NOT the VIP badge's color and not an alarm color either. It is
   a statement of fact about the record, read before anything else on it: what
   follows is not real. */
.badge.practice, .pchip.practice {
  background: #4a4a52; color: #f2f2f4; border-color: #4a4a52;
}

/* ⭐⭐ NOT REAL — muted, with the word written across it. Sep 7, 2026.

   Practice bookings stay ON the calendar rather than hidden, so a
   facility learning the software can watch one appear where a real one would.
   Then: "muted plus words that say practice written straight across it."

   ⛔ NOT A NEW COLOR. The colors on this board already mean which KIND of
   booking it is. A bright practice color would compete with meaning that is
   already there and read as an alert, which is the opposite of true.

   ⚠️ And the word is required, because muted alone is ambiguous — faded
   already reads as canceled on this board. */
.cal-pill.cal-not-real {
  opacity: 0.45;
  filter: saturate(0.35);
  position: relative;
}
.cal-pill.cal-not-real .cal-across {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: #1a1a1a;
  /* ⚠️ The bar underneath must stay legible, so the word sits on a wash
     rather than a block. */
  background: rgba(255, 255, 255, 0.55);
  pointer-events: none;
}
.booking-rows tr.booking-row.not-real td {
  opacity: 0.55;
}

/* ⭐⭐ A DOG ON THIS BOOKING HAS PASSED. Sep 7, 2026: a booking for a recently
   deceased dog has to be highlighted.

   ⛔ AMBER, NOT RED. Red on these pages means danger -- biter, allergy, the
   safety flags -- and this is not a hazard. It is something somebody has to
   pick up the phone about, which is exactly what amber already means here. */
.gone-mark {
  display: inline-block; font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 11.5px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; white-space: nowrap;
  background: var(--warn-bg); color: var(--warn-text);
  border: 1px solid var(--warn-text);
  border-radius: 3px; padding: 1px 6px; margin-left: 6px;
}

/* ===========================================================================
   ⭐⭐ THE INVOICE AS A PIECE OF PAPER — 09 Sep 2026.

   The invoice has to be makeable into a PDF. The
   browser's own Save as PDF makes it; this is what it saves. Until tonight
   this stylesheet had NO print rules at all, so pressing Print on an invoice
   put the top bar, the menu and every button on the page onto the paper.

   ⛔ THE DOCUMENT IS BLACK ON WHITE WHATEVER THEME SHE IS IN. A person working
   in the dark theme who prints an invoice should not get a black page, and a
   client should not receive one.

   ⭐ NOTHING HERE IS NAMED AFTER KAWA. `.sheet` is any printed document; the
   facility's own name, phone, email and logo come out of Settings.
   =========================================================================== */

.print-sheet { margin-top: 18px; }

.sheet {
  background: #fff; color: #111;
  border: 1px solid #d8d8d8;
  padding: 30px 32px 34px;
  max-width: 780px;
  font-size: 14px; line-height: 1.5;
}

.sheet-head {
  display: flex; flex-wrap: wrap; gap: 20px;
  align-items: flex-start; justify-content: space-between;
  border-bottom: 2px solid #111; padding-bottom: 14px;
}
.sheet-logo { max-height: 56px; max-width: 220px; display: block; margin-bottom: 8px; }
.sheet-name { font-size: 21px; font-weight: 700; line-height: 1.2; }
.sheet-where { font-size: 13px; color: #333; margin-top: 6px; line-height: 1.4; }
.sheet-contact { font-size: 13px; color: #555; margin-top: 4px; }
.sheet-doc { text-align: right; }
.sheet-doc-word {
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: #555;
}
.sheet-doc-no { font-size: 19px; font-weight: 700; }
.sheet-doc-date { font-size: 13px; color: #555; }
/* An invoice that was canceled must say so on the paper. A printed copy
   outlives the screen it came from. */
.sheet-void {
  display: inline-block; margin-top: 6px; padding: 1px 8px;
  border: 1px solid #a11; color: #a11;
  font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
}

.sheet-parties {
  display: flex; flex-wrap: wrap; gap: 14px 48px; margin: 18px 0 6px;
}
.sheet-k {
  font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: #666;
}
.sheet-v { font-size: 15px; }
.sheet-sub { font-size: 13px; color: #555; }
.sheet-since { margin-top: 22px; }

.sheet table { width: 100%; border-collapse: collapse; margin-top: 8px; }
.sheet-lines th {
  text-align: left; font-size: 11px; letter-spacing: .08em;
  text-transform: uppercase; color: #666;
  border-bottom: 1px solid #111; padding: 6px 0;
}
.sheet-lines td { padding: 7px 0; border-bottom: 1px solid #e4e4e4; vertical-align: top; }
.sheet .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.sheet-totals { margin-top: 14px; margin-left: auto; width: auto; min-width: 240px; }
.sheet-totals td { padding: 4px 0 4px 24px; }
.sheet-totals .due td {
  border-top: 2px solid #111; font-weight: 700; font-size: 16px; padding-top: 8px;
}

.sheet-note {
  margin-top: 22px; padding-top: 12px; border-top: 1px solid #e4e4e4;
  font-size: 13px; color: #333;
}

/* ⭐ A REPORT IS PROSE, NOT LINE ITEMS. 14 Sep 2026. The invoice sheet is a
   table because a bill is; an incident report is somebody's account of what
   happened, and it prints as paragraphs under labelled headings. */
.sheet-said { margin: 4px 0 0; font-size: 14px; line-height: 1.55; }
.sheet-said + .sheet-k { margin-top: 18px; }
.sheet-added { margin-top: 10px; }
.sheet-when {
  display: inline-block; min-width: 92px; white-space: nowrap;
  font-variant-numeric: tabular-nums; color: #555;
}

/* ===========================================================================
   ⛔⛔ THE PAPER STAYS PAPER ON A DARK PAGE. 14 Sep 2026.

   `.sheet` in app.css sets its own white ground and near-black text, which is
   right -- it is a document, not a screen, and it prints. But this scope
   restyles bare `td`, `th` and `a` for the themed pages, and those selectors
   out-specify the sheet's own. Left alone, the printable incident report drew
   a white sheet with theme-colored rules through it.

   Same class of fault as the step-chip painting itself white on Sep 8: a rule
   written for the dark ground reaching a thing that is not on the dark ground.
   =========================================================================== */
body.k9-preview .sheet,
body.k9-preview .sheet p,
body.k9-preview .sheet td,
body.k9-preview .sheet div { color: #111; }
body.k9-preview .sheet .sheet-where { color: #333; }
body.k9-preview .sheet .sheet-contact,
body.k9-preview .sheet .sheet-k,
body.k9-preview .sheet .sheet-sub,
body.k9-preview .sheet .sheet-doc-word,
body.k9-preview .sheet .sheet-doc-date { color: #555; }
body.k9-preview .sheet .sheet-note { color: #333; }
body.k9-preview .sheet a { color: #111; }
body.k9-preview .sheet th {
  background: none; color: #666; border-bottom: 1px solid #111;
  padding: 6px 0; text-transform: uppercase;
}
body.k9-preview .sheet td {
  padding: 7px 0; border-bottom: 1px solid #e4e4e4; vertical-align: top;
}
body.k9-preview .sheet .sheet-head { border-bottom-color: #111; }


@media print {
  /* Only the document goes on the paper. Everything the page needs in order
     to BE a page -- the bar, the menu, the buttons -- is not the document. */
  .topbar, .nav-links, .nav-toggle, .messages, .actions-row,
  .view-as-bar, .looking-bar, .no-print, footer { display: none !important; }

  html, body { background: #fff !important; color: #111 !important; margin: 0; }
  .container { margin: 0 !important; padding: 0 !important; max-width: none !important; }

  .print-sheet { margin: 0; }
  .sheet {
    border: 0; padding: 0; max-width: none;
    background: #fff !important; color: #111 !important;
  }
  .sheet a { color: #111; text-decoration: none; }

  /* A stay long enough to run over a page must not split a row in half. */
  .sheet tr, .sheet-totals { break-inside: avoid; page-break-inside: avoid; }

  @page { margin: 16mm; }
}

/* ===========================================================================
   ⭐⭐⭐ THE TRAINING CALENDAR — 09 Sep 2026.

   On the resource grid with Training selected: "to me, this is horrible.
   It reads like a really badly put together spreadsheet." It was a grid of
   ROOMS, so training listed eleven runs and four crates and pushed the actual
   sessions to the bottom of the page.

   "When I think of training, I want who's training, where they're training,
    and what they're training. And what time they're training."

   So: no rooms on either axis. A month of days, or a week against the clock.
   =========================================================================== */

.tcal-head {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: 12px; margin-bottom: 4px;
}
.tcal-head h1 { margin: 0; }
.tcal-controls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; margin: 0; }
.tcal-controls .field { margin: 0; }
.tcal-when { margin: 6px 0 14px; font-weight: 600; }

/* ---- the month: seven columns, whole weeks, a rectangle ---- */
.tcal-month {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px; background: var(--line, #ddd);
  border: 1px solid var(--line, #ddd);
}
.tcal-dow {
  background: var(--surface-2, #f4f4f4); padding: 8px 10px;
  font-size: 12.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; text-align: center;
}
.tcal-day {
  background: var(--surface, #fff); min-height: 116px; padding: 6px 7px 8px;
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
}
/* A day from the month either side is still drawn, so the grid keeps its
   shape, and is quiet so it cannot be mistaken for this month. */
.tcal-day.other-month { opacity: .45; }
.tcal-day.today { box-shadow: inset 0 0 0 2px var(--accent, #2d6a4f); }
.tcal-num { font-size: 12px; color: var(--muted, #777); text-align: right; }

.tcal-entry {
  display: block; text-decoration: none; color: inherit;
  border-left: 3px solid var(--accent, #2d6a4f);
  padding: 3px 0 3px 7px; font-size: 13px; line-height: 1.35; min-width: 0;
}
.tcal-entry:hover { background: var(--surface-2, #f4f4f4); }
.tcal-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent, #2d6a4f); margin-right: 5px; vertical-align: middle;
}
.tcal-line1 { overflow-wrap: anywhere; }
.tcal-line2 { font-size: 12px; color: var(--muted, #777); overflow-wrap: anywhere; }

/* ---- the week: the clock down the side, a block at its real time ---- */
.tcal-week {
  --tcal-hour: 46px;
  display: grid; grid-template-columns: 62px repeat(7, minmax(0, 1fr));
  gap: 1px; background: var(--line, #ddd);
  border: 1px solid var(--line, #ddd);
  overflow-x: auto;
}
.tcal-hours, .tcal-col { background: var(--surface, #fff); min-width: 0; }
.tcal-daycap {
  height: 52px; padding: 7px 8px; text-align: center;
  background: var(--surface-2, #f4f4f4);
  border-bottom: 1px solid var(--line, #ddd);
}
.tcal-dayname { font-weight: 600; font-size: 13px; }
.tcal-daydate { font-size: 12px; color: var(--muted, #777); }
.tcal-col.today .tcal-daycap { box-shadow: inset 0 0 0 2px var(--accent, #2d6a4f); }
.tcal-hours .tcal-hour {
  height: var(--tcal-hour); position: relative;
  border-bottom: 1px solid var(--line-2, #eee);
}
.tcal-hours .tcal-hour span {
  position: absolute; top: -8px; right: 8px;
  font-size: 11.5px; color: var(--muted, #777);
}
.tcal-slots { position: relative; }
.tcal-slots .tcal-hour {
  height: var(--tcal-hour); border-bottom: 1px solid var(--line-2, #eee);
}
.tcal-block {
  position: absolute; left: 3px; right: 3px; overflow: hidden;
  background: var(--accent-soft, #e8f2ec);
  border-left: 3px solid var(--accent, #2d6a4f);
  border-radius: 2px; padding: 4px 6px; font-size: 12.5px; line-height: 1.3;
  text-decoration: none; color: inherit;
}
.tcal-block:hover { filter: brightness(.97); }
.tcal-who { font-weight: 600; }
.tcal-dogs { }
.tcal-meta, .tcal-time { color: var(--muted, #777); font-size: 11.5px; }

@media (max-width: 900px) {
  /* A month of seven columns is unreadable on a phone; the week already
     scrolls sideways inside its own box. */
  .tcal-month { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tcal-dow { display: none; }
  .tcal-day { min-height: 0; }
  .tcal-day.other-month { display: none; }
}

/* The second line under a booking's dates: what actually happened, beside what
   was booked. Sep 9, 2026 -- see booking_detail.html. Quiet, because the
   booked line is still the headline; this one is the correction to it. */
.actually-went { display: block; margin-top: 3px; font-size: 0.92rem; color: var(--muted); }
.actually-went strong { color: var(--ink); }
.went-at .cal-resource-meta { margin-left: 6px; }

/* ===========================================================================
   COURSEWORK -- the training container. Walked through 09 Sep 2026; the
   design record is in the project documents.
   Four blocks: the plan, the packets, the staff notes, the daily log.
   =========================================================================== */
.tabbed > .t9:checked ~ .tab-strip .l9 { color: var(--green-dark); border-bottom-color: var(--green-dark); background: var(--card); }
.tabbed > .t9:focus-visible ~ .tab-strip .l9 { outline: 2px solid var(--green); outline-offset: -2px; }
.tabbed > .t9:checked ~ .p9 { display: block; }

/* ⭐ THE TENTH TAB -- INCIDENTS. 14 Sep 2026. Added by hand like the ninth,
   because this strip is a CSS radio pattern with one rule per position. */
.tabbed > .t10:checked ~ .tab-strip .l10 { color: var(--green-dark); border-bottom-color: var(--green-dark); background: var(--card); }
.tabbed > .t10:focus-visible ~ .tab-strip .l10 { outline: 2px solid var(--green); outline-offset: -2px; }
.tabbed > .t10:checked ~ .p10 { display: block; }
.cwprog { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 14px; margin: 0 0 16px; font-size: 1.02rem; }
.cwblock { border-top: 1px solid var(--border); padding: 14px 0 8px; }
.cwblock.staff { background: rgba(128,128,128,.05); padding-left: 12px; padding-right: 12px; }
.cwhead { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; margin: 0 0 8px; font-weight: 700; font-size: .95rem; }
.cwrow { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px; padding: 4px 0; border-bottom: 1px solid var(--border); font-size: .9rem; }
.cwrow:last-child { border-bottom: 0; }
.cwrow.live .cwname a { font-weight: 700; }
.cwname { flex: 1 1 20rem; }
.cwpacket { border-left: 3px solid var(--border); padding-left: 12px; margin: 0 0 14px; }
.cwpackhead { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; margin: 0 0 4px; font-weight: 600; }
.cwlogrow { display: flex; gap: 14px; padding: 5px 0; border-bottom: 1px solid var(--border); font-size: .9rem; line-height: 1.5; }
.cwlogrow .mono { flex: 0 0 5.5rem; color: var(--muted); }
.cwsay { display: block; margin: 6px 0 8px; font-size: .85rem; color: var(--muted); }
.cwsay textarea { display: block; width: 100%; max-width: 44rem; margin-top: 4px; }
/* Copy these days (Q211): two date boxes and the button, wrapping on a phone. */
.cwdays { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 10px 0 4px; }
.cwdays label { font-size: .85rem; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
.cwdays #cw-days-say { flex-basis: 100%; }
.cwdays textarea { flex-basis: 100%; max-width: 44rem; min-height: 8rem; }
.cwfacility { border: 1px dashed var(--border); padding: 10px 12px; margin-top: 10px; }
.empty.small { font-size: .88rem; margin: 0 0 6px; }
/* Seen / not opened. Amber is "waiting on somebody", the same as everywhere
   else on the board -- it is not an error, it is a fact about the client. */
.seen { color: var(--muted); font-size: .82rem; white-space: nowrap; }
.unseen { color: #a86400; font-size: .82rem; white-space: nowrap; }
.lockcell { color: var(--muted); font-size: .82rem; }

/* ⭐⭐ THE WAY IN HAS TO LOOK LIKE A WAY IN. 09 Sep 2026.
   These are the only controls that put anything into Coursework, and they
   first shipped wearing `.amend` -- the 0.7rem, 65%-opacity style meant for
   the word "edit" beside a note. They could not be seen, and the feature was
   reported as unbuilt. A control somebody cannot see is not a control. */

.cwmore { margin: 10px 0 0; font-size: 0.9rem; }

/* ⭐⭐ THE DROP ZONE, AND THE × THAT TAKES IT BACK OFF. 09 Sep 2026.
   Drop a file in and there is a little x on top: drag the wrong one in and it
   can be deleted right there. The native picker sits
   inside it and still works; this is what makes un-choosing possible. */
.dropzone { position: relative; border: 1px dashed var(--border); border-radius: 4px;
            padding: 14px 16px; cursor: pointer; max-width: 32rem; }
.dropzone:hover { border-color: var(--green-dark); }
.dropzone.over { border-color: var(--green-dark); border-style: solid; }
.dropzone.has { border-style: solid; }
.dropzone > input[type="file"] { position: absolute; left: -9999px; width: 1px; height: 1px; }
.dropsay { margin: 0; font-size: 0.85rem; color: var(--muted); }
.dropgot { margin: 0; display: flex; align-items: center; gap: 10px; font-size: 0.9rem; }
.dropname { flex: 1 1 auto; overflow-wrap: anywhere; }
.dropx { flex: 0 0 auto; cursor: pointer; border: 1px solid var(--border);
         background: var(--card); color: var(--ink); border-radius: 3px;
         font-size: 1rem; line-height: 1; padding: 2px 8px; }
.dropx:hover { border-color: #a33; color: #a33; }

/* Rename or take off, on every Coursework row. 09 Sep 2026: if it can be put
   in, it must be possible to adjust it, amend it, or take it out. */
a.rowamend { flex: 0 0 auto; font-size: 0.78rem; color: var(--muted);
             border: 1px solid var(--border); border-radius: 3px;
             padding: 1px 8px; text-decoration: none; }
a.rowamend:hover { color: var(--green-dark); border-color: var(--green-dark); }
.rowamend.open { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
                 margin: 6px 0; width: 100%; }
.rowamend.open input[type="text"] { flex: 1 1 18rem; }
/* The four doors into Coursework. A link until it is pressed -- this page
   carries no form until somebody opens a card. */
a.cwadd { display: inline-block; margin: 8px 0 2px; padding: 6px 14px;
          font-size: 0.85rem; font-weight: 600; color: var(--ink);
          background: var(--card); border: 1px solid var(--border);
          border-radius: 4px; text-decoration: none; }
a.cwadd:hover { border-color: var(--green-dark); color: var(--green-dark); }
.cwform { border: 1px solid var(--green-dark); padding: 12px 14px; margin: 8px 0; }
button.danger, .btn.danger { border-color: #a33; color: #a33; background: transparent; }
button.danger:hover { background: #a33; color: #fff; }

/* ⭐⭐ A CONTROL THAT DOES SOMETHING HAS TO LOOK LIKE IT. 12 Sep 2026.
   Found after a booking was priced at $100 instead of $50, and the only
   control that could put it right was gray caption text that got walked past.
   Words that are not highlighted and can barely be seen get skipped; the eye
   reads what is highlighted.

   ⛔ AND NOT BY TURNING THE PAGE INTO BUTTONS. The other rule cuts the other
   way: a crowded page -- too much information, too many pushy buttons, too
   many moving parts -- does not get read. So this reads as a LINK -- colored,
   underlined, its own size -- not as another thing shouting to be pressed.

   ⭐ THE LINE IT DRAWS: a fold that WRITES something wears this. A fold that
   only reveals a record already on the page -- the moves on a booking, the
   lifted rules on a dog -- stays quiet, because reading is not doing.

   The same lesson was already learned once, on Aug 30, and fixed in exactly
   one place (`.code-details > summary.disclosure-button`, above): somebody went
   looking for where to mark a dog a Service Dog Candidate and could not find
   it. That fix was never carried to the other folds. This is that carry. */
summary.opens {
  cursor: pointer;
  width: fit-content;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent, #2d6a4f);
  text-decoration: underline;
  text-underline-offset: 3px;
  list-style: none;
  padding: 2px 0;
}
summary.opens::-webkit-details-marker { display: none; }
summary.opens::before { content: "+ "; font-weight: 700; }
details[open] > summary.opens::before { content: "\2212 "; }
summary.opens:hover { color: var(--green-dark); }
summary.opens:focus-visible {
  outline: 2px solid var(--accent, #2d6a4f);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Putting a weighing right, or taking it off and keeping it. 18 Sep 2026.
   Only the note on a reading could ever be amended; the number, the day and
   where it came from stood forever. */
.weight-fix > summary { cursor: pointer; }
.weight-fix form { margin: 6px 0 0; }
.weight-pull { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
.weight-pull input[type="text"] { min-width: 200px; }
.weight-offrow { margin: 4px 0; font-size: 0.82rem; }
.weight-offrow s { color: var(--muted, #6b6b6b); }
.weight-off > summary { color: var(--muted, #6b6b6b); }

/* ⭐⭐⭐ THE HOMEWORK CARD ON THE CLIENT'S SIDE. 25 Sep 2026.

   ⛔ THE CARD HAD NO STYLING HERE AT ALL. Every `hw-` rule lived in
   preview.css behind `body.k9-preview`, which the client's shell does not
   load -- so the family's card has always been drawn with whatever the plain
   input rules gave it. That went unnoticed while the card was one box a day.
   The moment sets arrive it stops being survivable, so the rules the card
   needs are written here, for the shell the family actually gets.

   ⭐ THE DAY SHE WAS WITH THEM IS OPEN; THE DAYS AT HOME FOLD -- her design,
   25 Sep. The days are named by their real weekday and date, never "day two",
   so an empty row is a named day nobody worked. */
.hw-aim { font-weight: 600; }
.hw-days-sets { display: block; }
.hw-setday {
  margin: 0 0 6px; border: 1px solid rgba(128, 128, 128, .35);
  border-radius: 7px; padding: 5px 8px 6px;
}
.hw-setday > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center;
  gap: 6px;
}
.hw-setday > summary::-webkit-details-marker { display: none; }
.hw-setday > summary::before {
  content: "\25B8"; font-size: 11px; display: inline-block;
  transition: transform .12s ease;
}
.hw-setday[open] > summary::before { transform: rotate(90deg); }
.hw-when { display: block; font-size: 11px; font-weight: 700; }
.hw-withus {
  display: block; font-size: 9.5px; letter-spacing: .06em;
  text-transform: uppercase; margin-bottom: 3px;
}
.hw-withus.hw-inline { display: inline; margin-left: 6px; }
.hw-setrow {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: stretch;
  margin-top: 4px;
}
.hw-setbox {
  flex: 0 0 auto; min-width: 84px;
  border: 1px solid rgba(128, 128, 128, .35); border-radius: 7px;
  padding: 6px 8px 7px;
}
.hw-setno { display: block; font-size: 11px; font-weight: 700; margin-bottom: 2px; }
.hw-cell { display: block; margin-top: 3px; }
.hw-lab {
  display: block; font-size: 9.5px; letter-spacing: .05em;
  text-transform: uppercase; opacity: .75;
}
.hw-in {
  width: 100%; box-sizing: border-box; padding: 3px 5px;
  border: 1px solid rgba(128, 128, 128, .45); border-radius: 5px;
  font-size: 13px; font-variant-numeric: tabular-nums; text-align: center;
}
.hw-pair { display: flex; align-items: center; gap: 2px; }
/* ⛔ ADD A SET IS ITS OWN DASHED BOX AT THE END, so adding one never reads as
   part of the set above it. Same shape as her side, deliberately -- a second
   shape for the same job is a thing to learn twice. */
.hw-addset {
  flex: 0 0 auto; min-width: 84px; padding: 6px 10px; cursor: pointer;
  border: 1px dashed currentColor; border-radius: 7px;
  background: transparent; font-size: 13px; font-weight: 600;
}
.hw-note { margin: 7px 0; }
.hw-nin {
  width: 100%; box-sizing: border-box; padding: 5px 8px;
  border: 1px solid rgba(128, 128, 128, .45); border-radius: 6px;
  font-size: 13px;
}
.hw-save { margin: 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* ⭐ THE CARD SAVES ITSELF. Q161, 07 Oct 2026. Each box says what happened
   to it: saving, saved, or not saved. Not saved is never only a color. */
.hw-status { display: block; margin-top: 3px; font-size: 11px; font-weight: 600; opacity: .8; }
.hw-status.ok { color: var(--accent, var(--green-dark)); }
.hw-status.bad { color: var(--red, #9f2b1f); opacity: 1; }
/* Inside a set it takes the box's width and never widens it. */
.hw-setbox .hw-status { width: 0; min-width: 100%; }
.hw-note .hw-status { display: inline; margin-left: 6px; }
.hw-save .hw-status { display: inline; margin-top: 0; }
.hw-auto { font-size: 12px; font-weight: 600; }

/*  ⭐ 28 Sep 2026. The order of a facility's own tabs. Bands sit above the
    rule and carry no box; a number is typed in, not an arrow pressed. */
.portal-sections th.ord, .portal-sections td.ord { width: 78px; }
.portal-sections tr.section-split td { border-bottom: 0; padding: 0; }
.portal-sections tr.section-split hr {
  border: 0; border-top: 2px solid var(--ink); opacity: .55; margin: 10px 0 0;
}
.portal-sections tr.section-head2 th { padding-top: 10px; }
.portal-sections input.ordnum {
  width: 46px; box-sizing: border-box; padding: 6px 4px; text-align: center;
  border: 1px solid rgba(128, 128, 128, .45); border-radius: 5px;
  font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
}

/* ⭐ 3 Oct 2026: a contract client's money in and out, on its client page. */
.cm-totals { display: flex; flex-wrap: wrap; gap: 8px 28px; margin-bottom: 10px; }
.cm-totals span { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.cm-totals b { font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.cm-lines { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.cm-lines th { text-align: left; font-size: 0.72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); padding: 4px 6px; border-bottom: 1px solid var(--border); }
.cm-lines td { padding: 6px; border-bottom: 1px solid var(--border); vertical-align: top; }
.cm-lines .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cm-do { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; margin-top: 6px; white-space: nowrap; }
.cm-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin-bottom: 8px; }
.cm-fields label { display: flex; flex-direction: column; gap: 3px; font-size: 0.8rem; color: var(--muted); }
.cm-fields input, .cm-fields select { font: inherit; color: var(--ink); }
.cm-fields .cm-tick { flex-direction: row; align-items: center; gap: 6px; }
.cm-off { margin-top: 10px; }
.org-name { font-size: 1rem; font-weight: 600; color: var(--muted); margin-top: 2px; }
.cm-totals b.cm-short { color: var(--red, var(--warn-text)); }

/* ⭐ Contracts, 3 Oct 2026 — one fold per contract. */
.ct { border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 12px; }
.ct-head { cursor: pointer; display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.ct-head strong { font-size: 1.02rem; }
.ct-when { font-size: 0.85rem; color: var(--muted); }
.ct-open { color: var(--green, var(--accent)); }
.ct-new, .ct-closed, .ct-loose { border: 1px dashed var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 12px; }
.ct-new summary, .ct-closed summary { cursor: pointer; }
.ct-form { margin-top: 10px; }
.ct-wide { grid-column: 1 / -1; }
.ct-wide textarea, .ct-wide input { width: 100%; }
.ct-close { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
.ct-who { list-style: none; padding: 0; margin: 4px 0 8px; }
.ct-who li { padding: 6px 0; border-bottom: 1px solid var(--border); }
.ct-why { display: flex; flex-direction: column; gap: 3px; margin: 8px 0; font-size: 0.85rem; }
.ct-paper { font-size: 0.8rem; margin-top: 3px; overflow-wrap: anywhere; }
.ct-files { display: flex; flex-direction: column; gap: 3px; font-size: 0.8rem; color: var(--muted); margin-bottom: 8px; }
/* A drop strip under each contract money line. 3 Oct 2026. */
.ct-drop-row td { border-top: 0 !important; padding-top: 0 !important; }
.ct-drop { max-width: none; padding: 8px 12px; }
.ct-files .dropzone { max-width: none; margin-top: 3px; }

/* ⭐ Q162, 07 Oct 2026. The row the gallery page comes back to after an add
   is marked for a moment, so the eye finds it. */
.tb-landed { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 6px; }

/* Q229, 16 Oct 2026: one session a no-show. */
.no-show-door { display: inline-block; vertical-align: middle; }
.no-show-door > summary { list-style: none; cursor: pointer; display: inline-block; }
.no-show-door > summary::-webkit-details-marker { display: none; }
.no-show-door[open] > summary { opacity: .7; }
.no-show-box { margin-top: 6px; padding: 10px 12px; border: 1px solid var(--line, rgba(128,128,128,.4)); border-radius: 6px; max-width: 420px; white-space: normal; }
.no-show-box p { margin: 0 0 8px; font-size: 13px; }
.no-show-tag { color: #c0392b; border-color: #c0392b; }
.no-show-said { font-size: 12px; margin-right: 6px; }

/* Q231, 16 Oct 2026: whose name goes on a record, in small gray letters. */
.who-line { font-size: 0.78rem; color: var(--muted); white-space: nowrap; }

/* A form someone may read but not change (second build, 16 Oct 2026). */
fieldset.k9-ro { border: 0; padding: 0; margin: 0; min-width: 0; display: contents; }
fieldset.k9-ro button, fieldset.k9-ro input, fieldset.k9-ro select, fieldset.k9-ro textarea { opacity: .55; cursor: not-allowed; }

/* Q254: on Record Activity, the finish box runs from under the dog to the button. */
#unfinished tr:has(+ tr.finish-line) td { border-bottom: 0; }
.finish-form { display: flex; gap: 8px; align-items: center; margin: 0; }
.finish-form input[type=text] { flex: 1; min-width: 0; }
