/* ===========================================================================
   THE LOOK, AS SETTLED IN THE SANDBOXES -- Sep 4, 2026.

   On the sandbox drawing: "I love the look that you built... It does
   not look like KB nor does it look like DBP, so it works completely."
   And on why the app's own look does not do the job: "I can't see everything
   when it's flat and looks like a document to me."

   That is the whole brief. Regions are separated by SURFACE and BORDER, not
   by whitespace, so the eye can find where one thing ends and the next
   begins. Labels are condensed uppercase; every number is monospaced and
   tabular so columns of figures line up; corners are square; borders are one
   pixel and everywhere.

   SCOPED, DELIBERATELY. Everything in this file lives under `body.k9-preview`
   and only the two preview pages carry that class. The app went live Sep 3
   and the kennel runs on it; a palette swap across forty pages would
   have somebody finding black-on-black text during a check-in. The call, and it
   was the right one: "it seems like the safest way to go is to make two
   preview pages."

   WHEN THIS IS ADOPTED, the scope comes off and this becomes app.css. That
   unscoping is where things drift, so the rule to carry forward: no color
   is written as a literal outside the two blocks at the top of this file.

   DARK AND LIGHT BOTH, following the device, with a switch on the bar.
   Decided Sep 4 -- it follows the device, a person may override it, and no
   facility can force it. The reason for the last part, and it settles it:
   "especially if someone has accessibility colors on their system due to bad
   eyes, or being color blind or something."
   =========================================================================== */

body.k9-preview {
  --ground:#f5f4ef; --surface:#ffffff; --surface-2:#efeee7;
  --pk:#1b201c; --pk-2:#4d534d; --pk-3:#7d837c;
  --line:#dcdbd2; --line-2:#c8c8bd;
  --accent:#2f5d4a; --accent-soft:#e2ebe5;
  --brand-fill:#2f5d4a; --on-fill:#ffffff; --rail-hover:#ffffff;
  --red:#9f2b1f; --red-soft:#f7e6e3; --red-line:#e0b7b0;
  --amber:#8a5c0d; --amber-soft:#f7edd8; --ok:#356b47;
  --lock:#5d6570; --lock-soft:#e8eaed;
  --rail:#242b28; --rail-ink:#e4e7e2; --rail-line:#3a4340; --rail-2:#2e3733;
  --note:#7a5a12; --note-bg:#fbf3df; --note-line:#e6d3a6;
  --shadow:0 1px 0 rgba(27,32,28,.04), 0 1px 3px rgba(27,32,28,.06);
  /* ⭐ The looking-at-the-portal bar. Deliberately NOT the facility's
     accent: it must not be brandable, because its whole job is to say
     'this is not a client's session' on a page that otherwise looks
     exactly like one. In the palette so it follows dark mode. */
  --looking:#8a5a00; --looking-ink:#6d4700;
  /* ⛔ And the same bar standing on a REAL client's record, 18 Sep
     2026. A different family from the practice one on purpose: the
     practice bar says 'nothing here is real' and this one is the
     opposite, so they must not read alike at a glance. */
  --looking-real:#8a1c1c; --looking-real-ink:#6d1616;
  /* The calendar's booking colors, so they follow dark mode. 4 Oct 2026. */
  --cal-boarding:#d8f3dc; --cal-bt:#ffe8cc; --cal-day:#d0ebff;
  --cal-groom:#ffd6e8; --cal-train:#e5dbff;
  --cal-over:#fbe9e7; --cal-over-line:#e0a89f; --cal-over-ink:#a33333;
}

/* THE DEVICE DECIDES, unless the person has said otherwise on the bar. */
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) body.k9-preview {
    --ground:#13171a; --surface:#1b2124; --surface-2:#232a2e;
    --pk:#e7e9e4; --pk-2:#a8afab; --pk-3:#7d857f;
    --line:#2d3539; --line-2:#3c4649;
    --accent:#7fc0a2; --accent-soft:#1e2f28;
    --brand-fill:#7fc0a2; --on-fill:#111418;
    --red:#e08375; --red-soft:#331f1c; --red-line:#5d332c;
    --amber:#d7a44c; --amber-soft:#2e2617; --ok:#79b98e;
    --lock:#9aa4b0; --lock-soft:#232a31;
    --rail:#0e1214; --rail-ink:#dfe3df; --rail-line:#293134; --rail-2:#171d20;
    --note:#d8b96a; --note-bg:#26210f; --note-line:#4a3f1c;
    --shadow:0 1px 0 rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.35);
    --looking:#a86f06; --looking-ink:#3c2700;
    --looking-real:#c0392b; --looking-real-ink:#3c0f0f;
    --cal-boarding:#1f3a2a; --cal-bt:#3d2e17; --cal-day:#1a3042;
    --cal-groom:#3b2030; --cal-train:#2c2645;
    --cal-over:#3a1f1b; --cal-over-line:#6b3a33; --cal-over-ink:#e08375;
  }
}
html[data-theme="dark"] body.k9-preview {
  --ground:#13171a; --surface:#1b2124; --surface-2:#232a2e;
  --pk:#e7e9e4; --pk-2:#a8afab; --pk-3:#7d857f;
  --line:#2d3539; --line-2:#3c4649;
  --accent:#7fc0a2; --accent-soft:#1e2f28;
  --brand-fill:#7fc0a2; --on-fill:#111418;
  --red:#e08375; --red-soft:#331f1c; --red-line:#5d332c;
  --amber:#d7a44c; --amber-soft:#2e2617; --ok:#79b98e;
  --lock:#9aa4b0; --lock-soft:#232a31;
  --rail:#0e1214; --rail-ink:#dfe3df; --rail-line:#293134; --rail-2:#171d20;
  --note:#d8b96a; --note-bg:#26210f; --note-line:#4a3f1c;
  --shadow:0 1px 0 rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.35);
    --looking:#a86f06; --looking-ink:#3c2700;
    --looking-real:#c0392b; --looking-real-ink:#3c0f0f;
    --cal-boarding:#1f3a2a; --cal-bt:#3d2e17; --cal-day:#1a3042;
    --cal-groom:#3b2030; --cal-train:#2c2645;
    --cal-over:#3a1f1b; --cal-over-line:#6b3a33; --cal-over-ink:#e08375;
}

/* The two type families the sandbox used. Loaded from Google in the preview
   only. BEFORE THIS IS ADOPTED they get self-hosted: the provenance
   inventory for the lawyers says zero third-party CDN, and a font link is a
   third-party CDN. Flagged rather than quietly kept. */
body.k9-preview {
  background: var(--ground);
  color: var(--pk);
  font-family: "Barlow", "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
body.k9-preview * { box-sizing: border-box; }

/* ---------------------------------------------------------------------------
   ⭐⭐ THE CONTROLS BELONG TO THE THEME TOO. Sep 8, 2026.

   On the live dashboard in dark mode: "those input points are black
   under the dark theme. Well, guess what you can't see when the words behind
   them, i e month month slash day day slash year year year, you can't read it
   because the theme is black and the Text is black."

   ⛔ MEASURED ON THE LIVE PAGE, and it was worse than the two fields she
   named. Every control in Quick Checkin, read out of the browser:

       date, time      dark background, BLACK text
       number          WHITE background, black text
       select          WHITE background, black text
       search          correct

   The search box was the only one anybody had written a rule for. Everything
   else fell through to app.css, whose palette is light-only -- var(--card) is
   #ffffff and there is no dark value for it -- so the fields were being drawn
   from a different theme than the page around them.

   ⭐ THE SAME MISTAKE AS THE PORTAL'S UNDRESSED BOXES, ONE FLOOR UP.
   That one was fixed by widening the DOOR's selector, which dressed the doors
   and not the shell; two pages built hours later arrived undressed. This is
   the staff-side version: the find bar got dressed and the form controls did
   not. So the rule goes on the SCOPE, once, and a control added next month is
   covered by existing rather than by somebody remembering.

   ⭐⭐ AND color-scheme, WHICH IS THE HALF NO STYLESHEET CAN REACH.
   Setting color on an input does not touch what the browser paints INSIDE
   it -- the mm/dd/yyyy placeholder, the calendar and clock icons, the number
   spinners, the dropdown list a select opens. Those are the user agent's, and
   the only way to tell it this page is dark is color-scheme. It was declared
   nowhere in this application, on any page, so the browser painted every one
   of them in light mode over a dark page.

   It is set HERE, on the scope, and not on :root -- the forty pages that do
   not carry this class are still on app.css's light-only palette, and telling
   the browser THEY are dark would put dark widgets on a light page. That is
   the wider fix and it is a bigger job than this one.
   --------------------------------------------------------------------------- */
body.k9-preview { color-scheme: light; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) body.k9-preview { color-scheme: dark; }
}
html[data-theme="dark"] body.k9-preview { color-scheme: dark; }

/* ⚠️ :where() SO THIS CANNOT OUTRANK ANYTHING. A :not() chain carries the
   specificity of everything inside it -- five of them would have scored higher
   than the find bar's own rule and higher than the portal's, and this blanket
   would have overruled two deliberate designs while fixing a third thing.
   :where() contributes nothing, so every existing rule still wins. */
body.k9-preview input:where(:not([type="checkbox"],[type="radio"],[type="submit"],[type="button"],[type="file"])),
body.k9-preview select,
body.k9-preview textarea {
  background: var(--surface);
  color: var(--pk);
  border: 1px solid var(--line-2);
}
/* ---------------------------------------------------------------------------
   ⛔ NO SPINNERS ON MONEY. Sep 8, 2026.

   The spinner comes off. An amount is either typed in or it arrives already
   set by the program -- and a spinner causes problems on money.

   A number spinner steps by ONE. On a price that means a stray scroll wheel or
   a mistimed click turns $500.00 into $501.00 silently, in a field whose whole
   job is to be exactly right -- and the arrows sit under the cursor on the way
   to the button beside them.

   The field keeps type="number", so the numeric keypad still comes up on a
   phone and the browser still refuses letters. Only the arrows go.
   --------------------------------------------------------------------------- */
body.k9-preview input[type="number"]::-webkit-outer-spin-button,
body.k9-preview input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
body.k9-preview input[type="number"] { -moz-appearance: textfield; }

/* The door the sibling row sits behind, so it reads as a thing you open
   rather than a question the page is asking. */
body.k9-preview details.add-a-sibling > summary {
  cursor: pointer;
  color: var(--accent);
  font-size: 13px;
  width: fit-content;
}

body.k9-preview input::placeholder,
body.k9-preview textarea::placeholder { color: var(--pk-3); opacity: 1; }
body.k9-preview input:disabled,
body.k9-preview select:disabled,
body.k9-preview textarea:disabled {
  background: var(--surface-2); color: var(--pk-3);
  -webkit-text-fill-color: var(--pk-3);
}

/* ---- the top bar, inside the scope ---- */
body.k9-preview .topbar {
  background: var(--rail); color: var(--rail-ink);
  border-bottom: 1px solid var(--rail-line); padding: 8px 20px;
}
body.k9-preview .topbar .brand {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 15px; letter-spacing: .09em; text-transform: uppercase;
}
body.k9-preview .topbar .brand-logo { height: 34px; }
body.k9-preview .topbar .nav-links a,
body.k9-preview .topbar a.logout { color: var(--rail-ink); font-size: 13.5px; }
/* The client shell logs out with a form, because Django requires POST. */
body.k9-preview .topbar form.logout-form { display: inline; margin: 0; padding: 0; }
/* ⛔⛔ TWO LOG OUTS ON ONE BAR. Sep 7, 2026: "on the dashboard and the
   record activity board, we have two logouts. We have a logout sitting right
   next to settings and another logout at the edge of the page on the right
   side. We need to remove the logout that's sitting right next to settings."

   ⭐ THERE ARE SUPPOSED TO BE TWO IN THE MARKUP, and only ever one on screen:
   the copy inside the menu is the PHONE's door, the copy at the right edge is
   the desktop's. base.html says so and app.css has hidden the wrong one at
   each width since it was drawn.

   What broke it was the line directly above. `body.k9-preview .topbar
   form.logout-form` carries one more element than app.css's
   `.topbar .nav-links form.nav-logout`, and at equal class counts the extra
   element wins -- so on every page wearing the preview skin, display:inline
   beat display:none and both doors came back. The dashboard and the activity
   board are two of those pages.

   ⚠️ The fix is NOT to delete the menu's copy. On a phone the bar's copy is
   the hidden one, and deleting the other would leave somebody with no way to
   sign out on the device she actually uses -- which is the same bug this
   button has already had once. So: restate app.css's rules at this skin's
   specificity, and nothing else changes. */
body.k9-preview .topbar .nav-links form.nav-logout { display: none; }
@media (max-width: 640px) {
  body.k9-preview .topbar form.logout { display: none; }
  body.k9-preview .topbar .nav-links form.nav-logout { display: block; }
}
body.k9-preview .topbar form.logout-form button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--rail-ink); font-size: 13.5px;
}
body.k9-preview .topbar form.logout-form button:hover { color: var(--rail-hover); }
body.k9-preview .topbar .nav-links a:hover { color: var(--rail-hover); }
body.k9-preview .view-as-bar { background: var(--amber-soft); color: var(--amber);
  border-bottom: 1px solid var(--line); }

/* The person's own light/dark switch. Sits on the bar because that is where
   it was asked for: "control on the top bar". */
body.k9-preview .theme-pick {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11.5px;
  letter-spacing: .07em; text-transform: uppercase;
  background: var(--rail-2); color: var(--rail-ink);
  border: 1px solid var(--rail-line); padding: 5px 11px; cursor: pointer;
  margin-right: 14px;
}
body.k9-preview .theme-pick:hover { border-color: var(--rail-ink); color: var(--rail-hover); }

body.k9-preview .container { max-width: 1180px; padding: 20px 20px 64px; }

/* ---- the read-only banner ---- */
body.k9-preview .pv-readonly {
  background: var(--note-bg); color: var(--note);
  border: 0; border-left: 2px solid var(--note-line); border-radius: 0;
  padding: 9px 13px; margin-bottom: 18px; font-size: 13px; line-height: 1.5;
}
body.k9-preview .pv-readonly a { color: var(--note); }

/* ⭐ A MESSAGE THE APP SAYS BACK TO SOMEBODY. Sep 6, 2026.

   `.msg` had no styling anywhere in this application -- not here, not in
   app.css -- so every "saved", "couldn't save" and "welcome" has been bare
   text floating above the page since the beginning. Nobody noticed because
   staff read them in passing and know what they mean.
   
   It was found the first time a stranger saw one: Fred Test signed himself
   up, and the sentence welcoming him to Kawa Farms rendered as an unstyled
   line hanging over the top of his account. That is the first thing a new
   client ever reads.
   
   ⭐ THE ERROR VARIANT IS THE ONE THAT MATTERS MOST. An error nobody can
   distinguish from body text is an error nobody reads -- which is the same
   defect as KennelBooker's "or sign in here" in really, really small
   letters, arriving from the other direction. */
body.k9-preview .msg {
  padding: 11px 14px; border-radius: 10px; margin-bottom: 12px;
  font-size: 14px; line-height: 1.45;
  background: var(--surface); border: 1px solid var(--line-2); color: var(--pk);
}
body.k9-preview .msg.success {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
body.k9-preview .msg.error {
  background: var(--red-soft); border-color: var(--red-line); color: var(--red);
}
body.k9-preview .msg.warning { border-color: var(--accent); }

/* ⭐ THE GREETING NEEDS ROOM UNDER IT ON A CLIENT PAGE. On the staff pages
   the identity block is followed by its tab strip, which is why it carries no
   bottom padding. The client's home page puts a CARD straight after it, and
   the two collided along their shared border the first time anybody looked. */
body.k9-preview.my-portal .ident {
  padding-bottom: 16px; margin-bottom: 14px;
}

/* ---- identity ---- */
/* ⭐ Your accounts, under Hello, for a login on more than one (15 Oct 2026,
   from the mockup she approved). */
body.k9-preview .my-accounts { margin-top: 12px; }
body.k9-preview .my-accounts .lbl { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin: 0 0 6px; }
body.k9-preview .my-accounts .row { display: flex; flex-wrap: wrap; gap: 8px; }
body.k9-preview .my-accounts .acct { display: inline-block; text-align: left; padding: 7px 12px; border: 1px solid var(--line); border-radius: 6px; background: transparent; color: inherit; font: inherit; font-size: 13.5px; cursor: pointer; }
body.k9-preview .my-accounts .acct.on { border: 2px solid var(--accent); font-weight: 700; }
body.k9-preview .my-accounts .acct span { display: block; font-size: 11px; font-weight: 400; color: var(--muted); }
body.k9-preview .ident {
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow); padding: 18px 20px 0;
}
body.k9-preview .ident-top {
  display: flex; flex-wrap: wrap; gap: 14px 26px;
  align-items: flex-end; justify-content: space-between;
}
body.k9-preview .ident-who { display: flex; align-items: flex-end; gap: 16px; }
body.k9-preview h1 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 34px; line-height: 1; margin: 0; letter-spacing: -.01em;
}
body.k9-preview .sub { color: var(--pk-2); font-size: 13.5px; margin-top: 6px; }
body.k9-preview .sub a { color: var(--accent); }
/* ⭐ THE TEMPERAMENT, AT THE SIZE OF THE DOG'S NAME. Sep 5, 2026.
   The temperament is as large as the letters of the dog's own name, on the
   right, above the service-dog line. So the right-hand
   column becomes a stack: the temperament on top, the chips under it.

   THE COLOR IS THE BOX, NOT A ROW OF ITS OWN -- "the temperament color will
   actually change the box that the word temperament is in." The color comes
   off the record as an inline style because it is DATA, not a class: the
   facility picks from ten and decides what each one means, and no stylesheet
   gets to encode that.

   White type on a picked color, with a dark shadow behind it so it stays
   legible on yellow as well as on black. Yellow with white on it is the one
   combination that fails, and it is the one already called out on the
   run card. */
body.k9-preview .ident-right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
}
body.k9-preview .temperament {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 34px; line-height: 1; letter-spacing: -.01em;
  padding: 6px 14px 8px; color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
  max-width: 100%; text-align: right;
}
/* Nothing picked: the word still shows, in the page's own ink rather than in
   a color that would mean something it has not been given. */
body.k9-preview .temperament.untinted {
  background: none; color: var(--pk); text-shadow: none;
  border: 1px solid var(--line-2); padding: 5px 13px 7px;
}
@media (max-width: 700px) {
  body.k9-preview .ident-right { align-items: flex-start; }
  body.k9-preview .temperament { font-size: 26px; text-align: left; }
}

/* A NOTE, AND THE LINE UNDER IT. Sep 5, 2026 -- a dog's notes became dated
   entries with a name on them, the same shape the client page got that
   morning. The text reads first and the attribution sits under it in the
   quiet type, because the note is what somebody came to read. */
body.k9-preview .note-entry {
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
body.k9-preview .note-entry:last-child { border-bottom: 0; }
body.k9-preview .note-said { line-height: 1.55; }
body.k9-preview .note-entry .whocan { display: block; margin-top: 4px; }
/* One small word, and the history is behind it rather than on it: the amended
   note, and a small footer that says it was amended. */
body.k9-preview .was-updated { font-style: italic; }
/* Folded by time. The summary is a heading you can press, so it reads as part
   of the page rather than as a control bolted onto it. */
body.k9-preview .notes-fold > summary {
  cursor: pointer; list-style: none; padding: 12px 16px 10px;
}
body.k9-preview .notes-fold > summary::-webkit-details-marker { display: none; }
body.k9-preview .notes-fold > summary:hover { color: var(--accent); }
body.k9-preview .notes-fold > summary::before { content: "▸ "; }
body.k9-preview .notes-fold[open] > summary::before { content: "▾ "; }

/* The facility's own legend, drawn only where they have written one. */
body.k9-preview .colorkey { display: inline-block; margin-right: 14px; white-space: nowrap; }
body.k9-preview .colorkey i {
  display: inline-block; width: 10px; height: 10px; margin-right: 5px;
  border: 1px solid rgba(0, 0, 0, .25); vertical-align: baseline;
}

body.k9-preview .ident-chips { display: flex; gap: 8px; flex-wrap: wrap; }
body.k9-preview .pchip {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 9px; border: 1px solid var(--line-2); color: var(--pk-2);
}
body.k9-preview .pchip.here { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
body.k9-preview .pchip.vip { background: var(--lock-soft); border-color: transparent; color: var(--lock); }
/* ⭐ VIP IS ORANGE, EVERYWHERE IT APPEARS. 22 Sep 2026 -- hers: it stands out.
   Its own class, because the gray chip above also reads "Active" and
   "Current" on a program and those stay gray. */
body.k9-preview .pchip.vip-mark { background: var(--amber-soft); border-color: var(--amber); color: var(--amber); }
/* ⭐ A CODE CHIP WEARS ITS OWN COLOR -- red safety, amber administrative,
   slate identity -- the color the code carries in Settings. 22 Sep 2026. */
body.k9-preview .pchip.red { background: var(--red-soft); border-color: var(--red-line); color: var(--red); }
body.k9-preview .pchip.amber { background: var(--amber-soft); border-color: transparent; color: var(--amber); }
body.k9-preview .pchip.slate { background: var(--lock-soft); border-color: transparent; color: var(--lock); }

/* THE DOG'S PHOTO. Sep 4: the dog page needs a dog picture.
   And the other way on the client page -- names and runs in Here Now and in
   the dog list, no photos: "I think it is appropriate there not to have
   their pictures." */
body.k9-preview .ident-photo {
  width: 84px; height: 84px; object-fit: cover;
  border: 1px solid var(--line-2); display: block;
}

/* ⭐ CLICK IT AND SEE HER PROPERLY. Sep 7, 2026 -- there was no way to click
   the picture for a better look when the dog was farther away.

   ⚠️ It LOOKS clickable before it is clicked. A control that does something
   and gives no sign of it is the same defect as one that looks like it does
   something and does not -- this project has found the second kind in other
   people's software eleven times. */
body.k9-preview .bigpic-open { cursor: zoom-in; display: block; }
body.k9-preview.my-portal .bigpic-open:hover .ident-photo,
body.k9-preview.my-portal .bigpic-open:focus-visible .ident-photo {
  border-color: var(--accent);
}
body.k9-preview .bigpic-open:hover .ident-photo,
body.k9-preview .bigpic-open:focus-visible .ident-photo {
  border-color: var(--pk);
}

body.k9-preview .bigpic-sheet {
  display: none; position: fixed; inset: 0; z-index: 90;
  background: rgba(17, 17, 17, 0.82);
  align-items: center; justify-content: center;
  padding: 24px; cursor: zoom-out;
}
body.k9-preview .bigpic-toggle:checked ~ .bigpic-sheet { display: flex; }
body.k9-preview .bigpic-sheet img {
  max-width: min(1100px, 92vw); max-height: 88vh;
  object-fit: contain; background: var(--bg);
  border: 1px solid var(--line-2);
}
/* The word, not only the dark ground, because "click anywhere to close" is
   knowledge somebody has to already have. */
body.k9-preview .bigpic-shut {
  position: absolute; top: 18px; right: 22px;
  color: #fff; font-size: 14.5px; font-weight: 500;
  letter-spacing: 0.02em;
}

body.k9-preview .actions {
  display: flex; flex-wrap: wrap; margin: 16px -20px 0;
  border-top: 1px solid var(--line);
}
/* THE THREE STATES OF A DOOR -- see the door tag in templatetags/kawa.py.
   not built | designing | and nothing at all when the page is redrawn, because
   Sep 4, 2026: once a door is built and redrawn it needs nothing on it,
   because it is done. */
body.k9-preview .door {
  font-weight: 500; color: var(--pk); border-right: 1px solid var(--line);
  padding: 11px 16px; text-decoration: none; font-size: 14.5px;
  display: inline-flex; align-items: baseline; gap: 7px;
}
body.k9-preview a.door:hover { background: var(--surface-2); }
body.k9-preview a.door.primary { color: var(--accent); font-weight: 600; }
body.k9-preview .door.off { color: var(--pk-3); cursor: default; }
body.k9-preview .door .mark {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 10.5px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--pk-3);
  border: 1px solid var(--line-2); padding: 1px 5px; white-space: nowrap;
}
/* Designing is work in progress, not a hole. Amber says "on its way". */
body.k9-preview .door .mark.designing { color: var(--amber); border-color: var(--amber); }

/* ---- the red strip ---- */
body.k9-preview .rules-strip {
  background: var(--red-soft); border: 1px solid var(--red-line); border-top: 0;
  padding: 12px 16px 14px;
}
body.k9-preview .rules-strip h2 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--red); margin: 0 0 8px;
}
body.k9-preview .rules-strip ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
body.k9-preview .rules-strip li { color: var(--red); font-size: 14px; }
body.k9-preview .rules-strip li b {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 15.5px; letter-spacing: .01em;
}
body.k9-preview .rules-strip .who { color: var(--pk-3); font-size: 12px; }

/* What the owner said about handling. Quiet on purpose: it is not a rule and
   must not read like one. */
body.k9-preview .owner-said {
  background: var(--panel-2, rgba(255,255,255,.03));
  border: 1px solid var(--line-2); border-top: 0; padding: 12px 16px 14px;
}
body.k9-preview .owner-said h2 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pk-2); margin: 0 0 8px;
}
body.k9-preview .owner-said p { margin: 0; font-size: 14px; color: var(--pk); }
body.k9-preview .owner-said .note {
  margin-top: 6px; font-size: 12.5px; color: var(--pk-3);
}

/* ---- at a glance ---- */
body.k9-preview .glance {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-top: 0;
  margin-bottom: 22px;
}
body.k9-preview .g { background: var(--surface); padding: 12px 16px 13px; }
body.k9-preview .g .k {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--pk-3);
}
body.k9-preview .g .v {
  font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: 19px;
  font-weight: 500; margin-top: 3px; font-variant-numeric: tabular-nums;
}
body.k9-preview .g .v small { font-family: "Barlow", sans-serif; font-size: 13px; color: var(--pk-2); font-weight: 400; }
body.k9-preview .g .v.warn { color: var(--amber); }
body.k9-preview .g .v.small { font-size: 15px; }

/* ---- columns and cards ---- */
body.k9-preview .cols {
  display: grid; grid-template-columns: minmax(280px, 1fr) minmax(0, 2.05fr);
  gap: 22px; align-items: start;
}
body.k9-preview .card {
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow); border-radius: 0; padding: 0; margin-bottom: 22px;
}
body.k9-preview .card > h2 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--pk-2); margin: 0; padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
body.k9-preview .whocan {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--lock); margin: 0;
}
body.k9-preview .card-body { padding: 14px 16px; }

/* Two cards that belong to each other share a line. Sep 9, 2026, on the bottom
   of a booking: shrink the payment block and put the invoice on the same
   line. Nothing is named in here -- any two cards can
   use it -- and it falls back to one column when the line is too narrow to
   hold both without cutting either off, which is the complaint that started
   the whole layout pass. */
body.k9-preview .two-cards {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px; align-items: start;
}
body.k9-preview .two-cards > .card { margin-bottom: 22px; }
body.k9-preview .two-cards > .card > form > .inline { flex-wrap: wrap; }
body.k9-preview .two-cards > .card > form > .inline .field { flex: 1 1 110px; min-width: 0; }
body.k9-preview .two-cards > .card > form > .inline .field select,
body.k9-preview .two-cards > .card > form > .inline .field input { width: 100%; }
@media (max-width: 900px) {
  body.k9-preview .two-cards { grid-template-columns: 1fr; gap: 0; }
}
body.k9-preview dl.facts { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 9px 16px; }
body.k9-preview dl.facts dt {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 12px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--pk-3); padding-top: 2px;
}
body.k9-preview dl.facts dd { margin: 0; font-size: 15px; }
body.k9-preview dl.facts dd.mono { font-family: "IBM Plex Mono", monospace; font-size: 13.5px; font-variant-numeric: tabular-nums; }

body.k9-preview .here-card { border-color: var(--accent); }
body.k9-preview .here-card > h2 { background: var(--accent-soft); color: var(--accent); border-bottom-color: var(--accent); }

/* ---- tables ---- */
body.k9-preview table { width: 100%; border-collapse: collapse; font-size: 14px; }
body.k9-preview th {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--pk-3); text-align: left; padding: 9px 16px;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
body.k9-preview td { padding: 10px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
body.k9-preview tr:last-child td { border-bottom: 0; }
body.k9-preview td.mono { font-family: "IBM Plex Mono", monospace; font-size: 13.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.k9-preview a { color: var(--accent); }
body.k9-preview .subhead {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--pk-3); padding: 14px 16px 0; margin: 0;
}
body.k9-preview .empty { padding: 14px 16px; color: var(--pk-3); font-style: normal; }
body.k9-preview .state {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11px;
  letter-spacing: .07em; text-transform: uppercase; padding: 2px 7px;
  border: 1px solid var(--line-2); color: var(--pk-3); white-space: nowrap;
  display: inline-block;
}
body.k9-preview .state.ok { color: var(--ok); border-color: var(--ok); }
body.k9-preview .state.un { color: var(--amber); border-color: var(--amber); }
body.k9-preview .state.bad { color: var(--red); border-color: var(--red); }
/* Called off. Legible, and plainly not a live booking. */
body.k9-preview .state.off { color: var(--pk-3); border-color: var(--pk-3); }
body.k9-preview .note {
  border-left: 2px solid var(--note-line); background: var(--note-bg);
  color: var(--note); font-size: 13px; line-height: 1.5; padding: 9px 13px;
  margin: 12px 16px 14px;
}

/* ---- the tabs, still radio buttons and labels ---- */
body.k9-preview .tab-strip {
  display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--line);
  background: var(--surface-2); margin: 0; padding: 0;
}
body.k9-preview .tab-strip label {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13.5px; letter-spacing: .05em; text-transform: uppercase;
  border: 0; border-right: 1px solid var(--line); border-bottom: 0;
  padding: 11px 15px; color: var(--pk-2); margin: 0;
}
body.k9-preview .tab-strip label:hover { color: var(--pk); }
body.k9-preview .tab-strip label .n {
  font-family: "IBM Plex Mono", monospace; font-size: 12px; color: var(--pk-3); margin-left: 5px;
}
body.k9-preview .tab-strip label .n.warn { color: var(--amber); }
/* ⭐ SOMEBODY IS WAITING ON YOU — amber, not red. Sep 7, 2026, decided
   after the argument was put to her: red already means danger on these pages
   (biter, allergy, the safety flags), and an unread message wearing the same
   red teaches people that red sometimes means "somebody wrote to you." Amber
   is what this board already uses for the client-requests band. */
body.k9-preview .tab-strip label .n.waiting {
  background: var(--amber); color: #fff; border-radius: 9px;
  padding: 0 7px; margin-left: 5px;
}
/* The same amber count, worn by the door at the top of the record. */
body.k9-preview .door .n.waiting {
  font-family: "IBM Plex Mono", monospace; font-size: 12px;
  background: var(--amber); color: #fff; border-radius: 9px;
  padding: 0 7px; margin-left: 4px;
}
body.k9-preview .unread-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--note-bg); border: 1px solid var(--note-line);
  color: var(--note); padding: 10px 14px; margin-bottom: 16px;
}
body.k9-preview .thread { display: grid; gap: 14px; margin-bottom: 18px; }
body.k9-preview .thread .said {
  border-left: 3px solid var(--line-2); padding-left: 12px;
}
body.k9-preview .thread .said.ours {
  border-left-color: var(--accent); margin-left: 28px;
}
body.k9-preview .thread .words { margin-top: 3px; }
body.k9-preview .answer-here {
  border-top: 1px solid var(--line); margin-top: 16px; padding-top: 14px;
}
body.k9-preview .answer-here textarea { width: 100%; max-width: 44rem; }
body.k9-preview .tabbed > .t1:checked ~ .tab-strip .l1,
body.k9-preview .tabbed > .t2:checked ~ .tab-strip .l2,
body.k9-preview .tabbed > .t3:checked ~ .tab-strip .l3,
body.k9-preview .tabbed > .t4:checked ~ .tab-strip .l4,
body.k9-preview .tabbed > .t5:checked ~ .tab-strip .l5,
body.k9-preview .tabbed > .t6:checked ~ .tab-strip .l6,
body.k9-preview .tabbed > .t7:checked ~ .tab-strip .l7,
body.k9-preview .tabbed > .t8:checked ~ .tab-strip .l8 {
  background: var(--surface); color: var(--pk);
  box-shadow: inset 0 2px 0 var(--accent); border-bottom-color: transparent;
}

@media (max-width: 900px) {
  body.k9-preview .glance { grid-template-columns: repeat(3, 1fr); }
  body.k9-preview .cols { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  body.k9-preview .glance { grid-template-columns: repeat(2, 1fr); }
  body.k9-preview h1 { font-size: 28px; }
  body.k9-preview dl.facts { grid-template-columns: 1fr; gap: 2px; }
  body.k9-preview dl.facts dd { margin-bottom: 8px; }
}


/* ---------------------------------------------------------------------------
   A STAY, DRAWN AS THE RUNS IT OCCUPIES. Sep 4, 2026 -- see
   _preview_stay_block.html for why this is not a table.
   --------------------------------------------------------------------------- */
body.k9-preview .stay-head {
  display: flex; flex-wrap: wrap; gap: 6px 20px; align-items: baseline;
  padding: 14px 16px 12px; border-bottom: 1px solid var(--line);
}
body.k9-preview .stay-head + .stay-head { border-top: 1px solid var(--line); }
body.k9-preview .stay-head .type {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: 20px;
}
body.k9-preview .stay-head .type a { color: var(--pk); text-decoration: none; }
body.k9-preview .stay-head .type a:hover { color: var(--accent); }
body.k9-preview .stay-head .when {
  font-family: "IBM Plex Mono", monospace; font-size: 13.5px; color: var(--pk-2);
  font-variant-numeric: tabular-nums;
}
body.k9-preview .stay-head .paid {
  margin-left: auto; font-family: "Barlow Semi Condensed", sans-serif;
  font-weight: 600; font-size: 12px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ok);
}
body.k9-preview .runs {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line);
}
/* The red edge is the run card's stripe: this seat has something on it. */
body.k9-preview .run {
  background: var(--surface); padding: 11px 14px 12px;
  display: flex; gap: 11px; align-items: flex-start;
  box-shadow: inset 3px 0 0 var(--red);
}
body.k9-preview .run.clear { box-shadow: inset 3px 0 0 var(--line-2); }
body.k9-preview .run .plate {
  font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 600;
  border: 1px solid var(--line-2); color: var(--pk-2); padding: 3px 6px;
  white-space: nowrap; margin-top: 1px;
}
body.k9-preview .run .dog {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 17px; line-height: 1.15; color: var(--pk); text-decoration: none;
}
body.k9-preview .run .dog:hover { color: var(--accent); }
/* THE SPACE BEFORE THE CODE. Sep 4: the code badge was running into the
   dog's name. A margin, not a space character, so it cannot be eaten by
   template whitespace trimming. */
body.k9-preview .run .k9 {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11px;
  letter-spacing: .07em; color: var(--pk-3); margin-left: 7px;
}
body.k9-preview .run .flags { font-size: 12.5px; color: var(--red); margin-top: 2px; }

@media (max-width: 700px) { body.k9-preview .runs { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   A SESSION IS ONE LINE. Sep 14, 2026, on eight sessions down one client's
   page: too big, too full. The text is right, but each session should sit on
   the same line as the dog's name, so Upcoming does not take up so much
   space.

   The dog leads, because that is the order she said it in. Everything else is
   the same type it already was -- nothing here restyles the words, it only
   stops them stacking.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   THE INCIDENT FORM. Sep 14, 2026 -- the sheet's style had to be fixed,
   found while filing a real one on a dog that was on the property at the time.
   --------------------------------------------------------------------------- */
body.k9-preview .inc-form {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px;
  align-items: end;
}
body.k9-preview .inc-form .field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
body.k9-preview .inc-form .field.full { grid-column: 1 / -1; }
body.k9-preview .inc-form label {
  font-family: "IBM Plex Mono", monospace; font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--pk-3);
}
body.k9-preview .inc-form select,
body.k9-preview .inc-form input,
body.k9-preview .inc-form textarea { width: 100%; padding: 7px 9px; border-radius: 3px; }
body.k9-preview .inc-form textarea { min-height: 120px; resize: vertical; }
body.k9-preview .inc-form button { grid-column: 1 / -1; width: fit-content; }
body.k9-preview .inc-hint { margin: 2px 0 0; font-size: 12px; color: var(--pk-3); }
/* The internal half is marked on the screen as well as in the model, so
   nobody types findings into the releasable box by accident. */
body.k9-preview .inc-internal { border-left: 3px solid var(--amber); padding-left: 11px; }
body.k9-preview .inc-record .inc-head {
  display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline;
  padding-bottom: 9px; margin-bottom: 10px; border-bottom: 1px solid var(--line);
}
body.k9-preview .inc-record .inc-head h3 { margin: 0; font-size: 18px; }
body.k9-preview .inc-record .inc-book { font-size: 14px; }
body.k9-preview .inc-record .inc-by {
  margin-left: auto; font-family: "IBM Plex Mono", monospace; font-size: 11px;
  color: var(--pk-3);
}
body.k9-preview .inc-lab {
  margin: 12px 0 4px; font-family: "IBM Plex Mono", monospace; font-size: 10.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--pk-3); font-weight: 600;
}
body.k9-preview .inc-record .inc-lab:first-of-type { margin-top: 0; }
body.k9-preview .inc-said { margin: 0; font-size: 15px; line-height: 1.45; }
body.k9-preview .inc-internal-read {
  border-left: 3px solid var(--amber); padding: 1px 0 1px 11px; margin-top: 12px;
}
body.k9-preview .inc-entries { display: flex; flex-direction: column; gap: 8px; }
body.k9-preview .inc-entry {
  display: grid; grid-template-columns: 92px 1fr auto; gap: 10px;
  padding: 7px 0; border-top: 1px solid rgba(255,255,255,.06); font-size: 14px;
}
body.k9-preview .inc-entry .when {
  font-family: "IBM Plex Mono", monospace; font-size: 11.5px; color: var(--pk-3);
}
body.k9-preview .inc-entry .who {
  font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--pk-3);
  white-space: nowrap;
}
body.k9-preview .inc-entry.internal { box-shadow: inset 3px 0 0 var(--amber); padding-left: 9px; }
body.k9-preview .inc-more { margin-top: 14px; }
/* ⛔ A CONTROL THAT DOES SOMETHING HAS TO LOOK LIKE IT -- 03-THE-RULES §5.9.
   14 Sep 2026: this shipped as faint underlined text labelled "Fix a typo in
   this". It was read on a real incident, on a dog on the property, as the
   record being closed -- and a delete was asked for so it could be started
   over. The words were wrong and the weight was wrong. */
body.k9-preview .inc-more > summary {
  cursor: pointer; color: var(--accent); font-size: 14px; width: fit-content;
  font-weight: 600;
  padding: 5px 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 6px;
  text-decoration: none;
}
body.k9-preview .inc-more > summary:hover {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
body.k9-preview .inc-more > .inc-form { margin-top: 11px; }
body.k9-preview .inc-check {
  display: flex; gap: 7px; align-items: center; font-family: inherit;
  font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--pk-2);
}
body.k9-preview .inc-check input { width: auto; }
@media (max-width: 640px) {
  body.k9-preview .inc-entry { grid-template-columns: 1fr; gap: 2px; }
}
@media (max-width: 640px) {
  body.k9-preview .inc-form { grid-template-columns: 1fr; }
}

body.k9-preview .stay-head.one-line { padding: 10px 16px; gap: 4px 14px; }
body.k9-preview .stay-head.one-line .dogs {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 17px; line-height: 1.15;
}
body.k9-preview .stay-head.one-line .dogs .dog {
  color: var(--pk); text-decoration: none;
}
body.k9-preview .stay-head.one-line .dogs .dog:hover { color: var(--accent); }
body.k9-preview .stay-head.one-line .dogs .sep { color: var(--pk-3); margin-right: 2px; }
/* Same margin the seat used, for the same reason: "the canine is running into
   the dog's name." */
body.k9-preview .stay-head.one-line .dogs .k9 {
  font-family: "Barlow Semi Condensed", sans-serif; font-size: 11px;
  letter-spacing: .07em; color: var(--pk-3); margin-left: 7px;
}
body.k9-preview .stay-head.one-line .type { font-size: 17px; }
/* The rules keep their red and their line. A dog that has none costs nothing. */
body.k9-preview .stay-line-flags {
  font-size: 12.5px; color: var(--red); padding: 0 16px 10px;
  border-bottom: 1px solid var(--line);
}
body.k9-preview .stay-line-flags b { font-weight: 600; }


/* THE CODES COLUMN. A badge that follows a name starts wherever that name
   ends, so a column of them lines up with nothing. Its own cell, left
   justified, narrow enough that it does not push the table around. */
body.k9-preview td.codes { white-space: nowrap; width: 1%; }
body.k9-preview td.codes .code-badge-sm { margin: 0 4px 0 0; }

/* The client's own code, beside the name: right next to it, not touching it,
   and not twenty feet away. The gap is a margin so template whitespace cannot
   eat it. */
body.k9-preview h1 .name-chip { margin-left: 12px; vertical-align: middle; }

/* MONEY'S OWN KINDS, INSIDE THE MONEY TAB.
   Sep 4, 2026, on the first attempt: it loaded ugly -- invoices, payments and
   wallet needed to sit lower so they did not hit the tab above, and invoices
   was hanging off the edge.

   Both were the same mistake -- it was pulled out to the card's edges with
   negative margins, so it spanned the full width like a SECOND tab bar and
   sat flush against the first. Two bars of the same weight, touching, and the
   left-hand one running past the content under it.

   It is not a second bar. It is a choice made INSIDE one tab, so it is
   indented to the content, given air above it, and drawn as segments rather
   than as tabs. */
/* ⭐ ONE SUB-STRIP, DRAWN ONE WAY. Sep 5, 2026, on the Health tab: its look is
   based on how money was done on the customer's page -- not how it works, but
   how it looks. So Health's four kinds and
   Money's three kinds are the SAME component under two names, rather than a
   second strip that drifts a pixel a month. `.money-tabbed` is kept as a name
   the client page already uses. */
body.k9-preview .money-tabbed,
body.k9-preview .sub-tabbed { margin: 0; padding: 16px 16px 0; }
body.k9-preview .money-tabbed > .tab-strip,
body.k9-preview .sub-tabbed > .tab-strip {
  background: none; border-bottom: 0; gap: 6px; padding: 0; margin: 0 0 14px;
}
body.k9-preview .money-tabbed > .tab-strip label,
body.k9-preview .sub-tabbed > .tab-strip label {
  font-size: 12px; padding: 6px 13px; border: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-2); color: var(--pk-2);
  background: var(--surface-2);
}
body.k9-preview .money-tabbed > .tab-strip label:hover,
body.k9-preview .sub-tabbed > .tab-strip label:hover { border-color: var(--accent); }
/* The chosen one is filled, not underlined -- an underline is what the tabs
   above use, and two things must not say "selected" the same way. */
body.k9-preview .money-tabbed > .t1:checked ~ .tab-strip .l1,
body.k9-preview .money-tabbed > .t2:checked ~ .tab-strip .l2,
body.k9-preview .money-tabbed > .t3:checked ~ .tab-strip .l3,
body.k9-preview .sub-tabbed > .t1:checked ~ .tab-strip .l1,
body.k9-preview .sub-tabbed > .t2:checked ~ .tab-strip .l2,
body.k9-preview .sub-tabbed > .t3:checked ~ .tab-strip .l3,
body.k9-preview .sub-tabbed > .t4:checked ~ .tab-strip .l4 {
  background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-fill);
  box-shadow: none;
}
body.k9-preview .money-tabbed .subhead,
body.k9-preview .sub-tabbed .subhead { padding-left: 0; padding-right: 0; }
body.k9-preview .money-tabbed .card-body,
body.k9-preview .sub-tabbed .card-body { padding-left: 0; padding-right: 0; }
body.k9-preview .money-tabbed .table-scroll,
body.k9-preview .sub-tabbed .table-scroll { margin: 0 -16px; }
body.k9-preview .money-tabbed .note,
body.k9-preview .sub-tabbed .note { margin-left: 0; margin-right: 0; }

/* THE WEIGHT CARD, BORROWED. It is drawn for the live pages and brings its
   own box; inside a tab it is already in one, so the box comes off and only
   the contents stay. */
body.k9-preview .sub-tabbed .card {
  border: 0; border-radius: 0; box-shadow: none; background: none;
  margin: 0; padding: 0;
}
body.k9-preview .sub-tabbed .card > h3 { display: none; }

/* THE MONEY BAR, at the top of the Money tab. Four cells, and it is the same
   component as the strip at the top of a record -- one bar drawn one way,
   wherever it appears. Sep 4, 2026. */
body.k9-preview .money-bar {
  grid-template-columns: repeat(4, 1fr); border-top: 0; margin: 0 0 0;
}
body.k9-preview .money-bar .v small { font-size: 15px; color: var(--pk-2); }
@media (max-width: 700px) { body.k9-preview .money-bar { grid-template-columns: repeat(2, 1fr); } }

/* ---------------------------------------------------------------------------
   A CARD, OPEN. Sep 4, 2026 — the rule: a card is text until you press
   its Edit, so the editing state has to look unmistakably different from the
   reading state, not merely have boxes in it.
   --------------------------------------------------------------------------- */
body.k9-preview .card > h2 .edit {
  font-family: "Barlow", sans-serif; text-transform: none; letter-spacing: 0;
  font-size: 13.5px; font-weight: 500; color: var(--accent);
  border: 1px solid var(--line-2); background: none; padding: 3px 11px;
  text-decoration: none;
}
body.k9-preview .card > h2 .edit:hover { border-color: var(--accent); background: var(--accent-soft); }

body.k9-preview dl.facts.editing { gap: 10px 16px; align-items: center; }
body.k9-preview dl.facts.editing input[type="text"],
body.k9-preview dl.facts.editing input[type="email"],
body.k9-preview dl.facts.editing input[type="date"],
body.k9-preview dl.facts.editing select,
body.k9-preview dl.facts.editing textarea {
  font: inherit; width: 100%; background: var(--surface-2);
  border: 1px solid var(--line-2); color: var(--pk); padding: 5px 8px;
}
body.k9-preview dl.facts.editing textarea { resize: vertical; }
body.k9-preview dl.facts.editing input:focus,
body.k9-preview dl.facts.editing select:focus,
body.k9-preview dl.facts.editing textarea:focus {
  outline: 2px solid var(--accent); outline-offset: -2px;
}
/* ⭐ THE CODES: what they have, and a door to the rest.
   Sep 4, 2026: not a picker like this -- twenty codes would run down the whole
   page. So the ones a client holds are ticks on the card, and everything else
   folds away behind "Add a code". */
body.k9-preview .code-tick {
  display: inline-flex; align-items: center; gap: 6px; font-size: 14px;
  margin: 0 14px 4px 0; white-space: nowrap;
}
body.k9-preview .code-tick input { width: auto; }
body.k9-preview .code-tick.on { font-weight: 500; }
body.k9-preview .code-more { margin-top: 6px; }
body.k9-preview .code-more > summary {
  cursor: pointer; font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 12px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--accent); display: inline-block; padding: 3px 0;
}
body.k9-preview .code-more > summary::marker { color: var(--pk-3); }
body.k9-preview .code-tick-row {
  display: flex; flex-wrap: wrap; margin-top: 6px; padding: 9px 11px;
  background: var(--surface-2); border: 1px solid var(--line);
}

body.k9-preview .card-actions { display: flex; align-items: center; gap: 14px; margin-top: 16px; }
body.k9-preview .card-actions button {
  font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
  background: var(--brand-fill); border: 1px solid var(--brand-fill);
  color: var(--on-fill); padding: 7px 20px;
}
body.k9-preview .card-actions button:hover { filter: brightness(1.08); }
/* Cancel is a way out, not a second Save -- so it is a link, not a button. */
body.k9-preview .card-actions .cancel { color: var(--pk-2); font-size: 14px; }

/* An open card says so from across the page. */
body.k9-preview .card:has(dl.facts.editing) { border-color: var(--accent); }

/* WALLET'S FOUR BOXES. Points, Credit and Wallet are set by a person; Lifetime
   is the door to the money from before this system. Drawn as boxes because
   that is how they were asked for -- each in its own little box, not looking
   like text boxes. Sep 4, 2026. */
body.k9-preview .money-boxes {
  grid-template-columns: repeat(5, 1fr); border-top: 0; margin: 0 0 18px;
}
body.k9-preview .money-boxes .box { text-decoration: none; color: inherit; display: block; }
body.k9-preview .money-boxes .box:hover { background: var(--surface-2); }
body.k9-preview .money-boxes .box:hover .k { color: var(--accent); }
body.k9-preview .money-boxes .v .none {
  font-family: "Barlow", sans-serif; font-size: 14px; color: var(--accent);
}
@media (max-width: 700px) { body.k9-preview .money-boxes { grid-template-columns: repeat(2, 1fr); } }

/* A box, opened. */
body.k9-preview .opened {
  border: 1px solid var(--accent); background: var(--surface);
  padding: 0 16px 16px; margin: 0 0 18px;
}
body.k9-preview .opened .subhead { padding-left: 0; }
body.k9-preview .opened .note { margin: 0 0 14px; }


/* --- The write doors, and what they open. Sep 5, 2026. ------------------
 * The form opens under the button row, never inside the tab that shows what
 * it made -- redesign doc SS 4c.
 */
.door.on { border-color: var(--accent); color: var(--accent); }
.opened.writing { margin-top: 12px; }
.opened.writing .facts.editing { margin-bottom: 10px; }

/* A list of names you click, never a document drawn into the page.
 * They are named, and clicking the name opens the document.
 */
.named-list { list-style: none; margin: 6px 0 0; padding: 0; }
.named-list li { padding: 7px 0; border-bottom: 1px solid var(--line); }
.named-list li:last-child { border-bottom: 0; }
.named-list a { font-weight: 600; }
.named-list .whocan { margin-left: 10px; }

/* A note is a record: what was said, then who said it and when. */
ul.notes { list-style: none; margin: 6px 0 0; padding: 0; }
ul.notes li { padding: 10px 0; border-bottom: 1px solid var(--line); }
ul.notes li:last-child { border-bottom: 0; }
.note-said { margin-bottom: 4px; }

/* The wording somebody agreed to, read on a screen. Long, and read once --
 * so it gets reading measure and room to breathe rather than table density.
 */
.waiver-text { max-width: 68ch; line-height: 1.6; }

/* --- Stays, folded by time. Sep 5, 2026. ------------------------------
 * A month is a month for everybody; ten stays is right for one client and
 * absurd for the next. Closed by default, opens in place.
 */
details.folded { border-top: 1px solid var(--line); }
details.folded > summary {
  cursor: pointer; padding: 10px 2px; list-style: none;
  display: flex; align-items: center; gap: 8px;
}
details.folded > summary::-webkit-details-marker { display: none; }
details.folded > summary::before {
  content: "\25B8"; font-size: 11px; opacity: .6; transition: transform .12s;
}
details.folded[open] > summary::before { transform: rotate(90deg); }
details.folded.inner { border-top: 0; margin-left: 14px; }

/* ===========================================================================
   THE CLIENT'S FRONT DOOR  (body.my-door)  Sep 5, 2026

   Deliberately quiet. This page has one job -- get a client into their
   account -- and everything on it that is not that job is competing with it.

   The background image asked for lands here later: one photograph, with
   a wash between it and the text. The wash is a layer rather than an edit to
   the photo, so it can be tuned in seconds and the original stays original --
   and dark mode gets its own wash over the same file rather than a second
   picture.
   =========================================================================== */
/* ⭐ THE CARD SITS LEFT, NOT CENTER. Sep 5, 2026, a correction made after
   seeing it live -- the kind of rework that is fair: an idea can be great at
   first, and then you see it in reality.

   The first version centered the card, which put it straight over the dog:
   "most of his body ended up behind the sign in screen." Moving the card is
   the fix rather than moving the photograph, because it is also the better
   layout -- a card on one side and the picture breathing on the other.

   Her reason for LEFT specifically, and it decides nothing else: "so that you
   can see all four feet are off the ground."

   On a phone the card is full width whatever this says, so the rule only
   applies once there is room for both. */
/* The door page was a flex box that centered the card over a full-page
   photograph. That whole idea was replaced by the band below, and leaving the
   old rule here meant two rules fighting -- the later one winning by accident
   rather than by intent. */
body.k9-preview .door-page { max-width: 460px; width: 100%; padding: 32px 20px 64px; }

/* ⭐⭐ THE PHOTOGRAPH IS A BAND ACROSS THE TOP, NOT A BACKGROUND BEHIND
   EVERYTHING -- and getting here took four looks at the live page.

   1. CENTERED card: "most of his body ended up behind the sign in screen."
   2. LEFT: head and chest clear, "but that back foot is being covered."
   3. LOW, frame lifted: right on one window and wrong on the next -- one
      screen was much wider than tall, another nearly square, and the crop
      moved him under the card again.

   THE LESSON, AND IT IS THE ONLY REASON THIS COMMENT IS LONG: he runs the
   FULL WIDTH of that frame, tail at one edge and nose near the other. On a
   full-bleed background there is NO window shape where a centered card misses
   him. Three rounds were spent nudging percentages at a problem that had no
   solution in that shape. Tuning it for one screen guaranteed breaking it on
   the next.

   So the picture stopped being a background. It is a band across the top and
   the card sits on solid ground beneath it, which means the dog is never
   behind anything -- on any window, on any phone, at any zoom. The wash on
   the band drops to 0.28 because nothing is written over it any more.

   ⭐ THE GENERAL RULE: when a fix has to be re-tuned for each viewport, the
   layout is wrong, not the numbers. */
body.k9-preview.my-door { display: block; min-height: 100vh; }

/* ⭐⭐ THE BAND TAKES THE PICTURE'S OWN SHAPE, CAPPED. Sep 6, 2026, and
   it is the fifth arrangement of this one photograph.

   WHAT WAS WRONG. The band used to take whatever height was left over after
   the card's room was reserved: max(180px, 100vh - 700px). On a tall window
   that left about 450px and the dog fitted. On a laptop it collapsed onto
   the 180px floor -- and because the photograph still filled the WIDTH, a
   180px window onto a 576px-tall picture cut off everything above it. His
   whole head and shoulders. Her words, Sep 6: "if I have it open on my
   laptop, it kinda cuts off his head a little bit."

   ⭐ WHY THE FOCAL POINT WAS NOT THE FIX. background-position only chooses
   WHICH slice of the picture a too-short band shows. He fills that frame nose
   to tail, so moving it up would have bought his head by losing his feet --
   the same trade the three earlier rounds kept making. THE HEIGHT WAS THE
   FAULT, NOT THE FRAMING.

   WHAT IT IS NOW. The band is a real <img> in the flow at its own aspect
   ratio, so the browser does the arithmetic and the whole animal is there at
   every width. Nothing in this file knows or cares that Kawa's photograph is
   2.5:1 -- a facility that uploads a square one gets a square band. There is
   no number here to get wrong for the next facility, which is the same reason
   the temperament list and the play areas are data and not code.

   ⭐ THE CAP IS THE ONLY JUDGMENT ON THIS PAGE, and it was made looking at
   both: 55vh, so a big picture can never push the sign-in form off the bottom
   of a short window. When the cap bites it crops from the BOTTOM -- his head,
   his collar and his tail stay, and his back feet go. She chose that over the
   whole dog with the email box below the fold. */
body.k9-preview.my-door .door-band {
  position: relative; max-height: 55vh; overflow: hidden;
}
body.k9-preview.my-door .door-band img {
  display: block; width: 100%; height: auto;
}
/* The card sits close under the band, brought up a little higher as asked.
   The band is in the flow now, so "under it" needs
   no arithmetic and the two can no longer drift apart at all. */
body.k9-preview.my-door .door-page {
  margin: 0 auto; padding-top: 10px; padding-bottom: 16px;
}
body.k9-preview.my-door .door-logo { max-height: 52px; }
body.k9-preview.my-door .door-brand { margin: 0 0 10px; }
body.k9-preview.my-door .door-brand h1 { margin-top: 4px; font-size: 21px; }

body.k9-preview .door-brand { text-align: center; margin-bottom: 22px; }
body.k9-preview .door-logo { max-height: 96px; max-width: 100%; }
body.k9-preview .door-mark { font-size: 44px; line-height: 1; }
body.k9-preview .door-brand h1 { margin: 10px 0 0; font-size: 26px; }

body.k9-preview .door-card { margin-bottom: 16px; }
body.k9-preview .door-card .field { margin-bottom: 14px; }
body.k9-preview .door-card label {
  display: block; margin-bottom: 5px; font-size: 13px; color: var(--pk-2);
}
/* ⚠️ EVERY TYPE THE DOORS ACTUALLY USE, and it is a list because CSS cannot
   ask. It was email and password only until Sep 6, when the second door
   arrived with names and a phone number -- and those three boxes rendered
   stark white on the dark card, because an unlisted type gets the browser's
   own styling and nothing else.

   The suite could not see it: every test asserted the fields were THERE, and
   they were. It was found by rendering the live page and looking at it, which
   is the standing rule for anything about how something looks.

   `NoUnstyledBoxOnADoor` now walks both door forms and fails if a widget
   renders a type this rule does not name. */
body.k9-preview .door-card input[type="email"],
body.k9-preview .door-card input[type="password"],
body.k9-preview .door-card input[type="text"],
body.k9-preview .door-card input[type="tel"] {
  width: 100%; padding: 10px 12px; font: inherit;
  border: 1px solid var(--line-2); border-radius: 8px;
  background: var(--surface); color: var(--pk);
}
body.k9-preview .door-go {
  width: 100%; padding: 11px 14px; font: inherit; font-weight: 600;
  border: 0; border-radius: 8px; cursor: pointer;
  background: var(--brand-fill); color: var(--on-fill);
}
body.k9-preview .door-go:hover { filter: brightness(1.08); }

/* The second door's button on the sign-in page. Same shape, less shout --
   it is an alternative, not the thing most people came here to press. */
body.k9-preview .door-go-quiet {
  display: block; text-align: center; text-decoration: none;
  margin-top: 4px; background: transparent; color: var(--accent);
  border: 1px solid var(--accent);
}

/* ⛔ THE FIELD NOBODY SEES, AND WHY IT IS NOT display:none.
   Some robots skip a hidden input and fill one that is merely moved away, so
   this is positioned off the page instead. aria-hidden and tabindex keep it
   away from a screen reader and from anybody working by keyboard, which is
   the difference between a trap for robots and an obstacle for people. */
body.k9-preview .door-card input[name="website"] {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  opacity: 0; pointer-events: none;
}

/* A REFUSAL IS NOT FINE PRINT. The whole reason this page exists is that
   KennelBooker put the useful sentence in "really, really small letters". */
body.k9-preview .door-problem {
  margin: 10px 0 0; padding: 10px 12px; border-radius: 8px;
  font-size: 14px; line-height: 1.45;
  background: var(--red-soft); color: var(--red);
  border: 1px solid var(--red-line);
}
body.k9-preview .door-quiet { opacity: 0.92; }

/* A TAG OR A CODE, at the facility only (Q230, 16 Oct 2026). Under the
   password, the same card; the code box and its button share one line. */
body.k9-preview .door-tap {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-2);
}
body.k9-preview .door-code { display: flex; gap: 8px; align-items: center; }
body.k9-preview .door-code .door-code-box { flex: 1 1 auto; min-width: 0; }
body.k9-preview .door-code .door-go { width: auto; flex: none; }

/* THE WASH OVER THE PHOTOGRAPH. Sep 5, 2026; moved inside the band Sep 6.

   A picture behind the sign-in page was asked for, so it is not so plain --
   and the dogs in it are black Labradors, so the instinct was to lighten the
   photographs themselves: "the pictures would have to be lightened a whole
   bunch." That bakes a choice into the files and cannot be taken back without
   re-editing every one of them.

   ⭐ SO THE WASH IS A LAYER AND NEVER AN EDIT. The file on disk is untouched,
   this value can be tuned in a second, and dark mode reverses over the SAME
   picture rather than needing a second set. It is its own element sitting on
   top of the image -- never a filter on the image -- so either can change
   without the other.

   It moved from the page to the band because the picture did. Same layer,
   same file, same value; it just belongs to the photograph now, which means
   it can never be a different height from the thing it is washing. */
body.k9-preview.my-door .door-band::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(19, 23, 26, 0.28);
}




/* The cards lift off the photograph rather than floating on it. */
body.k9-preview.my-door .door-card { box-shadow: 0 2px 14px rgba(0,0,0,.10); }

/* The facility's copyright, on every client page. Quiet, and readable over
   the photograph on the sign-in door as well as over a plain page. */
body.k9-preview .my-footer {
  padding: 18px 20px 26px; text-align: center;
  font-size: 12.5px; color: var(--pk-3);
}
body.k9-preview.my-door .my-footer { padding: 6px 20px 18px; }


/* ---------------------------------------------------------------------
   REQUEST SENT. Sep 6, 2026.

   ⭐ THE ANSWER HAS TO BE UNMISSABLE, and the reason is operational rather
   than decorative. A client who hits Send on a form that refuses silently
   assumes it did not work and presses it again, maybe ten times. Ten presses
   is ten requests for somebody to sort out at the other end.
   --------------------------------------------------------------------- */
body.k9-preview .sent-card { text-align: center; }
body.k9-preview .sent-tick {
  width: 56px; height: 56px; margin: 4px auto 0;
  border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent);
  font-size: 30px; line-height: 54px;
}
body.k9-preview .sent-card .door-go { margin-top: 16px; }


/* ---------------------------------------------------------------------
   ONE PRESS IS ONE REQUEST. Sep 6, 2026.

   The confirmation page above answers a client who waited. This answers the
   one who did not: between the press and the new page there was nothing at
   all, so the button still looked pressable and a slow connection turned one
   request into several. A pressed button must stop looking like a button.
   --------------------------------------------------------------------- */
body.k9-preview button[disabled],
body.k9-preview input[type="submit"][disabled] {
  opacity: 0.55;
  cursor: default;
  filter: none;
}
body.k9-preview .door-go[disabled]:hover { filter: none; }


/* ---------------------------------------------------------------------
   THE BOOKINGS PAGE. Sep 6, 2026.

   ⭐ This page was asked for in this stylesheet by name, with the layout taken
   from the old software's page that was sent as a reference and nothing else
   taken from it. The standing rule, Sep 4: "I
   don't give a hoot on how they did it ... what I want you to look at is the
   container that everything sits in and how it's laid out."
   --------------------------------------------------------------------- */
body.k9-preview .page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin: 0 0 14px;
}
body.k9-preview .page-head h1 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 34px; line-height: 1; letter-spacing: -.01em; margin: 0;
  color: var(--pk);
}
body.k9-preview .page-head-sub {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 12.5px; color: var(--pk-3);
  margin: 6px 0 0;
}

/* ---- the kind tabs. Links, because each one is its own query ---- */
body.k9-preview .kind-tabs {
  display: flex; flex-wrap: wrap; gap: 0;
  border-bottom: 1px solid var(--line); background: var(--surface-2);
}
body.k9-preview .kind-tab {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13.5px; letter-spacing: .05em; text-transform: uppercase;
  padding: 11px 15px; color: var(--pk-2); text-decoration: none;
  border-right: 1px solid var(--line);
}
body.k9-preview .kind-tab:hover { color: var(--pk); }
body.k9-preview .kind-tab.on {
  background: var(--surface); color: var(--pk);
  box-shadow: inset 0 2px 0 var(--accent);
}

/* ---- and the second strip: which of them, not which kind ---- */
body.k9-preview .view-strip {
  display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 0 14px;
}
body.k9-preview .view-pill {
  font-size: 13px; padding: 5px 12px; border-radius: 999px;
  border: 1px solid var(--line-2); color: var(--pk-2);
  text-decoration: none; background: var(--surface);
}
body.k9-preview .view-pill:hover { border-color: var(--accent); color: var(--pk); }
body.k9-preview .view-pill.on {
  background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-fill);
}

/* ---- the rows ---- */
body.k9-preview .booking-rows td { vertical-align: top; }
body.k9-preview .booking-row { cursor: pointer; }
body.k9-preview .booking-row:hover { background: var(--surface-2); }
body.k9-preview .booking-rows .num { text-align: right; white-space: nowrap; }
body.k9-preview .booking-rows .who a { font-weight: 600; }
body.k9-preview .booking-rows .when-time { color: var(--pk-3); font-size: 12.5px; }
body.k9-preview .booking-rows .due { color: var(--pk-2); }

body.k9-preview .dogs-count {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .06em; font-size: 12px; color: var(--pk-3); margin-bottom: 5px;
}

/* ⭐ ONE GRID, SO THE COLUMNS LINE UP DOWN THE PAGE. Sep 3, 2026, and the
   reason is hers: "The names all need to start from a left justified. The
   canines all need to be from a left justified ... otherwise, my OCD is gonna
   kill me because they're not lined up." Ragged, you have to read every line;
   aligned, you can run your eye down it and check six dogs are in six runs. */
body.k9-preview .dog-row {
  display: grid;
  grid-template-columns: 4px 26px minmax(0, max-content) minmax(0, 1fr)
                         minmax(0, max-content) auto;
  align-items: center; gap: 0 9px; padding: 2px 0;
}
body.k9-preview .dog-row .dog-line-room {
  font-family: "IBM Plex Mono", monospace;
  color: var(--pk-2); font-size: 12px; white-space: nowrap;
}
/* The bar is the dog's temperament color and the color arrives inline,
   because what each of the ten means is the facility's to write down. */
body.k9-preview .temp-bar {
  width: 4px; align-self: stretch; min-height: 20px; border-radius: 2px;
}
body.k9-preview .temp-bar.untinted { background: var(--line-2); }
body.k9-preview .dog-row .dog-photo img {
  width: 26px; height: 26px; border-radius: 50%; object-fit: cover;
  display: block; border: 1px solid var(--line);
}
body.k9-preview .dog-row .pet-chip-noimg {
  width: 26px; height: 26px; border-radius: 50%; display: block;
  background: var(--surface-2); border: 1px solid var(--line);
  text-align: center; line-height: 24px; font-size: 13px;
}
body.k9-preview .dog-row .dog-name { font-weight: 600; }
body.k9-preview .dog-row .dog-line-breed {
  color: var(--pk-3); font-size: 13px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
body.k9-preview .dog-row .dog-codes {
  display: flex; gap: 5px; align-items: center; flex-wrap: wrap;
  min-width: 0; justify-content: flex-end;
}

/*  ⛔ 28 Sep 2026. A CODE BADGE WAS DRAWN OVER A DOG'S NAME. Found live on
    the bookings list: "there's something on top of Clementine's name that I
    can't read." The row is a grid whose name and room columns may shrink
    below their content, and a badge is an OPAQUE box in the last column — so
    a tight row overflowed its text and the badge painted on top of it.
    Nothing here may overflow its own column. */
body.k9-preview .dog-row > * { min-width: 0; }
body.k9-preview .dog-row .dog-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body.k9-preview .dog-row .code-badge-sm,
body.k9-preview .dog-row .hand-mark {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}

/*  ⛔ 29 Sep 2026, the same fault one column over. The room was the one
    text in the row with nowrap and nothing clipping it, so it ran past its
    own column and the opaque badge beside it painted on top. Every text in
    this row is now cut off at its own edge. */
body.k9-preview .dog-row .dog-line-room {
  overflow: hidden; text-overflow: ellipsis;
}

/*  Training reads its place in its own column, so the row has one less. */
body.k9-preview .dog-row.no-room {
  grid-template-columns: 4px 26px minmax(0, max-content) minmax(0, 1fr) auto;
}
body.k9-preview .where-col { white-space: normal; }

/*  Buttons in a card heading are one group at the right, not scattered. */
body.k9-preview .head-doors {
  margin-left: auto; display: inline-flex; gap: 6px; align-items: center;
}

/*  The week: seven days across, the facility's hours down. */
body.k9-preview .hour-grid { width: 100%; table-layout: fixed; }
body.k9-preview .hour-grid th {
  font-size: 11.5px; color: var(--pk-2); font-weight: 600;
  padding: 5px 4px; text-align: left; border-bottom: 1px solid var(--line);
}
body.k9-preview .hour-grid th.today a { color: var(--accent); }
body.k9-preview .hour-grid .hour-col {
  width: 62px; font-family: "IBM Plex Mono", monospace; font-size: 11px;
  color: var(--pk-3); font-weight: 400; vertical-align: top;
  border-bottom: 0; border-right: 1px solid var(--line);
}
body.k9-preview .hour-grid td {
  border-bottom: 1px solid var(--line); border-right: 1px solid var(--line);
  height: 34px; vertical-align: top; padding: 2px 3px;
}
body.k9-preview .hour-grid td.today { background: var(--surface-2); }
/*  The band only draws when something is in it -- she does not schedule
    without a time, and an empty band would be furniture on her page. */
body.k9-preview .hour-grid .loose-band td { background: var(--surface-2); }
/*  A block that spans hours is one cell, filled, labelled once. */
body.k9-preview .hour-grid td.taken { padding: 0; }
body.k9-preview .hour-grid td.taken .hour-item {
  height: 100%; white-space: normal; border-radius: 0; margin: 0;
  padding: 3px 5px; background: var(--surface-2);
}
body.k9-preview .hour-when {
  display: block; font-family: "IBM Plex Mono", monospace;
  font-size: 10.5px; color: var(--pk-3);
}

body.k9-preview .hour-item {
  display: block; font-size: 11.5px; line-height: 1.3; margin-bottom: 2px;
  padding: 1px 4px; border-radius: 3px; background: var(--surface);
  border-left: 2px solid var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/*  A month is a grid. Seven columns, weeks down, the days either side of
    the month drawn quietly so the shape of the month is readable. */
body.k9-preview .month-grid { width: 100%; table-layout: fixed; }
body.k9-preview .month-grid th {
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--pk-3); padding: 6px 4px; text-align: left;
}
body.k9-preview .month-grid td {
  border: 1px solid var(--line); vertical-align: top; height: 92px;
  padding: 4px 5px; overflow: hidden;
}
/*  One week gets the room a month cannot spare. */
body.k9-preview .month-grid.one-week td { height: 260px; }
body.k9-preview .month-grid td.outside { background: var(--surface-2); }
body.k9-preview .month-grid td.outside .month-day { color: var(--pk-3); }
body.k9-preview .month-grid td.today { border-color: var(--accent); }
body.k9-preview .month-day {
  display: inline-block; font-family: "IBM Plex Mono", monospace;
  font-size: 12px; text-decoration: none; margin-bottom: 3px;
}
body.k9-preview .month-item {
  display: block; font-size: 11.5px; line-height: 1.3; margin-bottom: 2px;
  padding: 1px 4px; border-radius: 3px; background: var(--surface-2);
  border-left: 2px solid var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body.k9-preview .month-at {
  font-family: "IBM Plex Mono", monospace; color: var(--pk-3);
}
/*  Each item is the door to changing it (13 Oct 2026). */
body.k9-preview a.hour-item, body.k9-preview a.month-item {
  color: inherit; text-decoration: none; cursor: pointer;
}
body.k9-preview a.hour-item:hover, body.k9-preview a.month-item:hover,
body.k9-preview a.hour-item:focus-visible, body.k9-preview a.month-item:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px;
}

/*  Past ten people the ticks become the dog field's type-ahead. */
body.k9-preview .who-pick { position: relative; display: block; }
body.k9-preview .who-chips {
  display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px;
}
body.k9-preview .who-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 6px 2px 10px; font-size: 13px;
}
body.k9-preview .who-off {
  background: none; border: 0; color: var(--pk-3); cursor: pointer;
  font-size: 15px; line-height: 1; padding: 0 3px;
}
body.k9-preview .who-off:hover { color: var(--ink); }

body.k9-preview .who-ticks {
  display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center;
}
body.k9-preview .who-ticks label { font-weight: normal; white-space: nowrap; }

/*  The second container on Upcoming: booked, nobody has set the days. */
body.k9-preview .undated-rows {
  margin-top: 26px; padding-top: 18px; border-top: 2px solid var(--line);
}
body.k9-preview .undated-rows h3 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--pk-2); margin: 0 0 4px;
}
body.k9-preview .undated-rows h3 .n {
  font-family: "IBM Plex Mono", monospace; font-size: 12px;
  letter-spacing: 0; color: var(--pk-3);
}

body.k9-preview .rows-note { margin: 12px 0 2px; }

@media (max-width: 800px) {
  body.k9-preview .dog-row,
  body.k9-preview .dog-row.no-room {
    grid-template-columns: 4px 26px 1fr auto;
  }
  body.k9-preview .dog-row .dog-line-breed { display: none; }
  /*  The codes take a line of their own rather than fight the name for one. */
  body.k9-preview .dog-row .dog-codes {
    grid-column: 3 / -1; justify-content: flex-start;
  }
}


/* ---- what a search turns up, when it is not one thing ---- */
body.k9-preview .found-rows tr { cursor: pointer; }
body.k9-preview .found-rows tr:hover { background: var(--surface-2); }
body.k9-preview .found-rows a { font-weight: 600; }
body.k9-preview .found-rows tr.only-dog { cursor: default; }
body.k9-preview .found-rows tr.only-dog:hover { background: none; }
body.k9-preview .found-rows tr.only-dog .cl-face { vertical-align: middle; margin-right: 8px; }
body.k9-preview .put-away {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .06em; font-size: 11px; color: var(--pk-3);
  border: 1px solid var(--line-2); border-radius: 3px; padding: 1px 5px;
  margin-left: 6px;
}


/* =========================================================================
   ⭐⭐ THE PAINT LAYER — Sep 6, 2026.

   On the pages staff open every morning: "we need to get it in our
   style sheet or at least our colors and stuff." And on the calendar
   specifically: "you've already worked the calendar exactly how I want it. It
   really doesn't need to change other than the colors."

   ⭐ A PAINT JOB IS NOT A REDESIGN, and this block is what makes that true.
   The old look is drawn with app.css's variable names -- --ink, --muted,
   --bg, --card, --border, --warn-bg. The new look defines its own -- --pk,
   --pk-3, --ground, --surface, --line, --amber-soft -- and never touched the
   old ones. So a page that got the new shell kept app.css's LIGHT values on
   the new dark ground: black text on a black card, which is exactly the
   failure named on the very first preview -- "a dark record under a blue
   bar is two products stitched together."

   ⭐ SO THE OLD NAMES ARE POINTED AT THE NEW PALETTE, once, here. A page joins
   the design language by adding two lines -- the body class and the head
   include -- and every card, border, muted line and warning box on it follows
   the theme, in light and dark, without touching its markup.

   ⚠️ THIS IS A BRIDGE, NOT A DESTINATION. A page that has been properly
   redrawn uses the new names directly and needs none of this. What it buys is
   that a page nobody has redrawn yet stops looking like a different product
   the moment it is asked to.
   ========================================================================= */
body.k9-preview {
  --ink: var(--pk);
  --muted: var(--pk-3);
  --bg: var(--ground);
  --card: var(--surface);
  --border: var(--line);
  --warn-bg: var(--amber-soft);
  --warn-text: var(--amber);
  /* The brand family. The bar keeps its own treatment; everything else that
     reached for green now reaches for the accent, which is theme-aware. */
  --green-dark: var(--accent);
  --green: var(--accent);
  --green-light: var(--accent-soft);
  --on-brand: var(--on-fill);
}

/* ---------------------------------------------------------------------------
   ⛔⛔ THE BUTTONS WITH NO WORDS ON THEM. Sep 8, 2026.

   Hunting for the control that finishes a booking: "I had no idea how to
   finish the booking to get me to the next page... I can't read either the two
   green buttons that I pushed. So I pushed the first one. Not even sure what
   it was for."

   Measured on the live page rather than reasoned about:

       a.btn  ->  background rgb(127,192,162)   color rgb(127,192,162)

   THE SAME COLOR. The text was there the whole time, painted exactly the shade
   of the button under it.

   ⭐ TWO CORRECT RULES, MULTIPLIED. The shim above maps --green-dark onto the
   accent so a page nobody has redrawn stops looking like a different product.
   `body.k9-preview a { color: var(--accent) }` colors links with that same
   accent. app.css says `.btn { background: var(--green-dark); color: #fff }`
   -- and `body.k9-preview a` (0,1,2) outranks `.btn` (0,1,0), so the white
   lost and the label became the background.

   ⚠️ AND IT ONLY EVER HIT LINKS. A <button> is not an <a>, so Save changes,
   Move and Apply stayed perfectly readable on the same screen -- which is why
   this reads as "some buttons are broken" rather than as a color bug, and why
   nobody looking at the CSS would have found it. A test cannot see it either:
   the markup is correct, the text is in the DOM, and the page returns 200.

   ⭐ `a.btn` here is (0,2,2), which beats the link rule without touching it.
   --------------------------------------------------------------------------- */
body.k9-preview a.btn,
body.k9-preview a.btn:hover,
body.k9-preview a.btn:visited { color: var(--on-brand); }

/* The quiet one, which app.css only ever wrote for <button> — so a link
   wearing .secondary took the SOLID fill and the same invisible label. */
body.k9-preview .btn.secondary,
body.k9-preview a.btn.secondary,
body.k9-preview button.secondary {
  background: var(--surface);
  color: var(--accent);
  border: 1px solid var(--line-2);
}

/* ===========================================================================
   ⭐⭐ THE BOARD — 06 Sep 2026. The dashboard, redrawn from the sandbox that
   was worked through card by card and approved.

   Everything here is scoped to `.board`, which only the preview dashboard
   draws, so the live board staff open at seven in the morning is untouched
   until she says to swap it.

   THE BRIEF, in her words: "when I'm talking about the style sheet, yes, I'm
   talking about the colors and everybody being able to change their colors
   from light to dark. But I'm talking about the cards and the boxes. I really
   like that look. It keeps it so clean."
   =========================================================================== */
body.k9-preview .board {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; align-items: start;
}
/* A card carrying a table takes the whole width. Half a column is not enough
   for nine columns of booking, and a table that has to scroll sideways to
   show the money is the defect the bookings page was fixed for. */
body.k9-preview .board > .wide { grid-column: 1 / -1; }
@media (max-width: 900px) {
  body.k9-preview .board { grid-template-columns: 1fr; }
}

/* Two cards, one cell. Staged stacks directly beneath Quick Checkin instead
   of spanning the page — they each have their own card. */
body.k9-preview .cell {
  display: flex; flex-direction: column; gap: 14px; min-width: 0;
}

body.k9-preview .board .card {
  margin: 0; padding: 14px 16px; border-radius: 0;
}
body.k9-preview .board .card > h3 {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--pk-2); margin: -14px -16px 14px; padding: 12px 16px;
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
body.k9-preview .board .card > h3 .n {
  font-family: "IBM Plex Mono", monospace; font-size: 12px;
  letter-spacing: 0; color: var(--pk-3); font-variant-numeric: tabular-nums;
}
/* Amber, not red: a request waiting and a dog staged are both somebody's
   turn to act, and neither one is a fault. */
body.k9-preview .board .card.attn { border-color: var(--amber); }
body.k9-preview .board .card.attn > h3 {
  background: var(--amber-soft); color: var(--amber);
  border-bottom-color: var(--amber);
}
body.k9-preview .board .card.attn > h3 .n { color: var(--amber); }

/* Things that run to the card's own edges: the tile grids, and any table
   that is a direct child of the card. */
body.k9-preview .board .card > .occ,
body.k9-preview .board .card > .tiles-top,
body.k9-preview .board .card > .slot-cards,
body.k9-preview .board .card > .table-scroll { margin-left: -16px; margin-right: -16px; }
body.k9-preview .board .card > .occ,
body.k9-preview .board .card > .slot-cards { margin-bottom: -14px; }
body.k9-preview .board .card > .tiles-top { margin-bottom: 14px; }

/* ---- the tiles. One headline, then the kinds in rows of three ---- */
body.k9-preview .occ { display: grid; gap: 1px; background: var(--line); }
body.k9-preview .occ-rows { display: grid; gap: 1px; background: var(--line); }
body.k9-preview .occ-rows.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
body.k9-preview .tile { background: var(--surface); padding: 12px 14px; }
body.k9-preview .tile .v {
  font-family: "IBM Plex Mono", monospace; font-size: 23px; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--pk);
}
body.k9-preview .tile .k {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 10.5px; color: var(--pk-3); margin-top: 5px;
}
body.k9-preview .tile.lead .v { color: var(--accent); font-size: 29px; }
/* ⭐ THE WAITLIST NUMBER IS THE LARGEST THING ON THE CARD: the word waitlisted
   and a large number, staring at you every time the dashboard opens. */
body.k9-preview .tile.hot { background: var(--amber-soft); }
body.k9-preview .tile.hot .v { color: var(--amber); font-size: 34px; }
body.k9-preview .tile.hot .k { color: var(--amber); }

/* ---- feeding and medications: a box per dog, edge to edge ---- */
body.k9-preview .board .slot-cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 1px; background: var(--line);
}
body.k9-preview .board .slot-card {
  border: 0; border-radius: 0; background: var(--surface); padding: 11px 14px 13px;
}
body.k9-preview .board .slot-card-room {
  border-radius: 0; border-color: var(--line-2); color: var(--pk-3);
  font-family: "IBM Plex Mono", monospace; font-size: 11.5px;
}
body.k9-preview .board .slot-card-slots .slot { border-top-color: var(--line-2); }

/* ---- which way the dog is going ---- */
body.k9-preview .dir { font-size: 15px; line-height: 1; font-weight: 600; }
body.k9-preview .dir.up { color: var(--ok); }
body.k9-preview .dir.down { color: var(--red); }
body.k9-preview .dir.same,
body.k9-preview .dir.none { color: var(--pk-3); }

/* ---- the find bar, on the top bar, in this skin's own ink ---- */
/* Q112, 01 Oct 2026. It moved off the dashboard's page head and onto the bar
   of every staff page, so these rules follow it. Square corners and the
   rail's line, like everything else wearing this skin. */
body.k9-preview .topbar-find input[type="search"] {
  padding: 6px 10px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--line-2); border-radius: 0;
  background: var(--surface); color: var(--pk);
}
body.k9-preview .topbar-find input[type="search"]::placeholder { color: var(--pk-3); }
body.k9-preview .topbar-find button {
  border: 1px solid var(--line-2); border-radius: 0;
  color: var(--rail-ink); font-size: 13.5px;
}
body.k9-preview .topbar-find button:hover { background: var(--rail-2); color: var(--rail-hover); }

/* The weighing header — date, occasion, who held the scale — laid out as a
   row that wraps rather than three stacked fields. Sep 6, 2026: Weights sits
   beside Medications now, so the room it does not need is room the card does
   not take. */
body.k9-preview .board .card > form > .inline {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
}
body.k9-preview .board .card > form > .inline .field { flex: 1 1 120px; min-width: 0; }
body.k9-preview .board .card > form > .inline .field select,
body.k9-preview .board .card > form > .inline .field input { width: 100%; }

/* ---------------------------------------------------------------------------
   ⭐ THE WAITING ROOM — 06 Sep 2026. Waitlisted requests, above Pending on the
   bookings page, drawn deliberately UNLIKE the table beneath them.

   The rule: "it sits under pending as a request. It does not convert until a
   booking unless we convert it." A row in that table is a booking and holds a
   run; nothing here does. If the two ever look alike, somebody will read one
   as the other on a busy morning — so this is a list of asks, not rows.
   --------------------------------------------------------------------------- */
body.k9-preview .waiting-room {
  border: 1px solid var(--amber); background: var(--amber-soft);
  margin: 0 0 16px;
}
body.k9-preview .waiting-room-head {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 12.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--amber); margin: 0; padding: 10px 14px;
  border-bottom: 1px solid var(--amber);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
body.k9-preview .waiting-room-head .n {
  font-family: "IBM Plex Mono", monospace; font-size: 12px; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
body.k9-preview .waiting-ask { padding: 11px 14px; border-top: 1px solid var(--note-line); }
body.k9-preview .waiting-ask:first-of-type { border-top: 0; }
body.k9-preview .waiting-who {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
}
body.k9-preview .waiting-who a { font-weight: 600; }
body.k9-preview .waiting-when {
  font-family: "IBM Plex Mono", monospace; font-size: 13px; color: var(--pk-2);
  font-variant-numeric: tabular-nums;
}
body.k9-preview .waiting-dogs { font-size: 13.5px; color: var(--pk-2); }
body.k9-preview .waiting-said { font-size: 13.5px; color: var(--pk-2); margin-top: 3px; }
body.k9-preview .waiting-doors {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 8px;
}
body.k9-preview .waiting-doors form { margin: 0; }
body.k9-preview .waiting-doors details > summary {
  cursor: pointer; font-size: 13px; color: var(--pk-2); list-style: none;
}
body.k9-preview .waiting-doors details > summary::-webkit-details-marker { display: none; }
body.k9-preview .waiting-doors details > summary::before { content: "\25B8 "; }
body.k9-preview .waiting-doors details[open] > summary::before { content: "\25BE "; }
body.k9-preview .waiting-doors details form {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 7px;
}
body.k9-preview .waiting-doors details input[type="text"] {
  min-width: 240px; padding: 6px 10px; font: inherit; font-size: 14px;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--pk);
}
body.k9-preview .waiting-room .rows-note { margin: 0; padding: 0 14px 12px; }

/* ===========================================================================
   ⭐⭐ EVERY BOX INSIDE THE PORTAL, DRESSED ONCE, ON THE SHELL — 07 Sep 2026.

   Walking the live portal as a client: "those white lines scroll all
   the way across the page, and on a dark theme, it looks horrible."

   ⛔ THIS IS THE SAME DEFECT FOR THE SECOND TIME, BY THE SAME MECHANISM.
   The door's boxes shipped undressed on Sep 6 and were fixed by widening the
   DOOR's selector. That fix dressed the doors and not the shell, so the two
   pages built hours later -- /my/details/ and the dog page -- arrived white
   and bare in exactly the same way.

   ⭐ SO THE RULE GOES ON THE SHELL, NOT ON A PAGE. `.my-portal` is on every
   signed-in client page, so a page built next month is dressed by existing
   rather than by somebody remembering. A third per-page fix would have been
   the third instance of one mistake.

   ⭐ AND WIDTH IS ITS OWN HALF OF HER COMPLAINT. A field at 100% is fine on a
   phone and a bar straight across a laptop. It gets a MAXIMUM instead: the
   box stops at a readable width and the page stops looking like a form
   somebody forgot to lay out.

   ⛔ THE HONEYPOT IS EXCLUDED BY NAME. `input[name="website"]` is positioned
   off the page on purpose, and this rule is specific enough to have dragged
   it back into view -- which would have handed every robot the field it is
   there to catch. See the block above it.
   =========================================================================== */
body.k9-preview.my-portal input[type="text"]:not([name="website"]),
body.k9-preview.my-portal input[type="email"]:not([name="website"]),
body.k9-preview.my-portal input[type="tel"]:not([name="website"]),
body.k9-preview.my-portal input[type="password"]:not([name="website"]),
body.k9-preview.my-portal input[type="url"]:not([name="website"]),
body.k9-preview.my-portal input[type="search"]:not([name="website"]),
body.k9-preview.my-portal input[type="number"]:not([name="website"]),
body.k9-preview.my-portal input[type="date"]:not([name="website"]),
body.k9-preview.my-portal input[type="time"]:not([name="website"]),
body.k9-preview.my-portal select,
body.k9-preview.my-portal textarea {
  width: 100%; max-width: 26rem; padding: 10px 12px; font: inherit;
  border: 1px solid var(--line-2); border-radius: 8px;
  background: var(--surface); color: var(--pk);
}
/* Somebody telling us about their dog needs room to write. */
body.k9-preview.my-portal textarea {
  max-width: 40rem; min-height: 96px; resize: vertical; line-height: 1.5;
}
/* A tick is not a text box and must not be stretched into one. */
body.k9-preview.my-portal input[type="checkbox"],
body.k9-preview.my-portal input[type="radio"] {
  width: auto; max-width: none; accent-color: var(--accent);
}
/* The door card sets its own width and it is already narrow. */
body.k9-preview.my-portal .door-card input { max-width: none; }

body.k9-preview.my-portal input:focus-visible,
body.k9-preview.my-portal select:focus-visible,
body.k9-preview.my-portal textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
  border-color: var(--accent);
}

/* The label above the box, and air between one field and the next. A form
   with no spacing reads as one block of controls rather than as questions. */
body.k9-preview.my-portal .field { margin-bottom: 16px; }
body.k9-preview.my-portal .field > label {
  display: block; margin-bottom: 5px;
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 12.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--pk-2);
}
body.k9-preview.my-portal .field .note { margin: 5px 0 0; }

/* ===========================================================================
   ⭐⭐ THE CLIENT'S LANDING PAGE — 07 Sep 2026, from the sandbox walked
   through card by card and approved.

   "Front page when they land -- boarding or appointments, what they've got
    coming up, that should be the primary focus of the landing page, and the
    request a booking. That's your landing page. And then details, dog
    information, and all that other stuff gets put into a card."

   The shapes here are the staff pages' shapes on purpose: she asked for the
   portal to look like the dog page and the client page, not like a stack of
   prompts. → the-house-page-pattern-sep-4-2026.md
   =========================================================================== */

/* ---- who this is, without scrolling (pattern §1) ---- */
body.k9-preview.my-portal .ident {
  background: var(--surface); border: 1px solid var(--line); border-top: 0; padding: 20px 22px;
}
body.k9-preview.my-portal .ident .who {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 30px; line-height: 1; margin: 0; color: var(--pk);
}
body.k9-preview.my-portal .ident .under { font-size: 13.5px; color: var(--pk-3); margin: 7px 0 0; }
body.k9-preview.my-portal .ident .under a { color: var(--accent); }

/* ---- the appointment band: the thing that is never hidden (pattern §2) ---- */
body.k9-preview.my-portal .never {
  border: 1px solid var(--accent); border-top: 0; background: var(--accent-soft); padding: 15px 20px;
}
body.k9-preview.my-portal .never.quiet { border-color: var(--line); background: var(--surface); }
body.k9-preview.my-portal .never .k {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .08em; font-size: 11.5px; color: var(--accent); margin-bottom: 8px;
}
body.k9-preview.my-portal .never.quiet .k { color: var(--pk-3); }
body.k9-preview.my-portal .never .big {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700;
  font-size: 25px; line-height: 1.1; color: var(--pk);
}
body.k9-preview.my-portal .never .line { font-size: 14.5px; margin-top: 5px; }
body.k9-preview.my-portal .never .sub { font-size: 13.5px; color: var(--pk-2); margin-top: 3px; }

/* "After that" belongs INSIDE the band. It was a card of its own for one
   draft and was taken back out: the band was already doing that job. */
body.k9-preview.my-portal .after { margin-top: 14px; border-top: 1px solid var(--line-2); padding-top: 11px; }
body.k9-preview.my-portal .after .ak {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .08em; font-size: 11px; color: var(--accent); margin-bottom: 6px;
}
body.k9-preview.my-portal .arow {
  display: flex; gap: 11px; align-items: baseline; padding: 5px 0; font-size: 14px; flex-wrap: wrap;
}
body.k9-preview.my-portal .arow .when {
  font-family: "IBM Plex Mono", monospace; font-size: 12.5px; color: var(--pk-2);
  white-space: nowrap; min-width: 62px;
}
body.k9-preview.my-portal .arow .what { min-width: 0; }
/* The clock on an After that row -- same monospace treatment as the date. */
body.k9-preview.my-portal .arow .at {
  font-family: "IBM Plex Mono", monospace; font-size: 12.5px; color: var(--pk-2);
  white-space: nowrap;
}
/* The heading is a link and still reads as a heading. */
body.k9-preview.my-portal .never .big a.opens {
  color: inherit; text-decoration: none;
  border-bottom: 2px solid var(--accent); padding-bottom: 1px;
}
body.k9-preview.my-portal .seeall {
  display: inline-block; margin-top: 10px; text-decoration: none;
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  text-transform: uppercase; letter-spacing: .07em; font-size: 12px;
  color: var(--accent); border-bottom: 1px solid var(--accent); padding-bottom: 2px;
}

/* ---- the doors under it ---- */
body.k9-preview.my-portal .grid {
  display: grid; gap: 12px; margin-top: 16px; grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 700px) { body.k9-preview.my-portal .grid { grid-template-columns: 1fr; } }
body.k9-preview.my-portal .door {
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
  padding: 15px 17px 16px; display: flex; flex-direction: column; gap: 5px; min-width: 0;
}
body.k9-preview.my-portal .door.wide { grid-column: 1 / -1; }
body.k9-preview.my-portal .door.lead { border-color: var(--accent); }
body.k9-preview.my-portal .door .t,
body.k9-preview.my-portal .half .t {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600; font-size: 17px;
}
body.k9-preview.my-portal .door .d,
body.k9-preview.my-portal .half .d { font-size: 13.5px; color: var(--pk-2); line-height: 1.45; }
body.k9-preview.my-portal .go {
  margin-top: 10px; align-self: flex-start; text-decoration: none;
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 12px; font-weight: 600;
  background: var(--brand-fill); color: var(--on-fill); padding: 9px 14px;
}
body.k9-preview.my-portal .quiet {
  margin-top: 10px; align-self: flex-start; text-decoration: none;
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 12px; font-weight: 600; color: var(--accent);
  border-bottom: 1px solid var(--accent); padding-bottom: 2px;
}
/* ⭐ The ask, and it only exists while something is actually missing. */
body.k9-preview.my-portal .ask {
  align-self: flex-start; font-family: "Barlow Semi Condensed", sans-serif;
  text-transform: uppercase; letter-spacing: .07em; font-size: 11px;
  color: var(--amber); border: 1px solid var(--amber); background: var(--amber-soft); padding: 2px 7px;
}
body.k9-preview.my-portal .list {
  margin: 7px 0 0; padding: 0; list-style: none; font-size: 14.5px;
  display: flex; flex-direction: column; gap: 6px;
}
body.k9-preview.my-portal .list a { color: var(--accent); font-weight: 600; }
body.k9-preview.my-portal .meta { color: var(--pk-3); font-size: 13px; }

/* one card holding everything that is not an appointment */
body.k9-preview.my-portal .booking-card {
  grid-column: 1 / -1; background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
}
body.k9-preview.my-portal .cardhead {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600; font-size: 13px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--pk-2);
  margin: 0; padding: 12px 16px; border-bottom: 1px solid var(--line);
}
body.k9-preview.my-portal .two-up {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line);
}
@media (max-width: 700px) { body.k9-preview.my-portal .two-up { grid-template-columns: 1fr; } }
body.k9-preview.my-portal .half {
  background: var(--surface); padding: 15px 17px 17px;
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
}

/* ---- ⭐ a person, one press away, on the page they land on ---- */
body.k9-preview.my-portal .reach {
  grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--line); border: 1px solid var(--line); box-shadow: var(--shadow);
}
@media (max-width: 700px) { body.k9-preview.my-portal .reach { grid-template-columns: 1fr; } }
body.k9-preview.my-portal .reach a {
  background: var(--surface); padding: 16px 18px; text-decoration: none; color: var(--pk);
  display: flex; flex-direction: column; gap: 3px;
}
body.k9-preview.my-portal .reach a:hover { background: var(--accent-soft); }
body.k9-preview.my-portal .reach .rk {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .08em; font-size: 11px; color: var(--accent);
}
body.k9-preview.my-portal .reach .rv {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: 22px; line-height: 1.15;
  overflow-wrap: anywhere;
}
body.k9-preview.my-portal .reach .rd { font-size: 13px; color: var(--pk-3); }

/* ⭐ THE SAME TILE, NOT YET A DOOR. Sep 7, 2026. It sits in the row so a
   client can see that writing to us is coming, and it is deliberately NOT an
   anchor: no hover lift, no pointer, nothing that promises a click. A button
   that looks live and does nothing is the exact defect this project keeps
   finding in other people's software. */
body.k9-preview.my-portal .reach .soon {
  background: var(--surface); padding: 16px 18px;
  display: flex; flex-direction: column; gap: 3px;
}
body.k9-preview.my-portal .reach .soon .rv { color: var(--pk-3); font-size: 19px; }

/* ---------------------------------------------------------------------------
   ⭐ THE CLIENT'S DOG PAGE AND CLIENT PAGE — 07 Sep 2026, the house pattern
   inside the portal: the client's dog page looks like the staff dog page, and
   the client page looks like the staff client details page.
   --------------------------------------------------------------------------- */

/* The way back. Sep 6: "once you fill out your pet details and hit save,
   there's no way back to the previous page ... we might wanna help the lowest
   common denominator with that." The logo works and is not discoverable. */
body.k9-preview.my-portal .back {
  display: block; background: var(--surface-2); border: 1px solid var(--line);
  padding: 9px 16px; text-decoration: none;
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 12px; font-weight: 600; color: var(--accent);
}
body.k9-preview.my-portal .back + .ident { border-top: 0; }

/* the summary strip under the identity header (pattern §1) */
body.k9-preview.my-portal .strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line); border-top: 0;
}
body.k9-preview.my-portal .strip .t { background: var(--surface); padding: 11px 13px; }
body.k9-preview.my-portal .strip .v {
  font-family: "IBM Plex Mono", monospace; font-size: 19px; line-height: 1; color: var(--pk);
}
body.k9-preview.my-portal .strip .k {
  font-family: "Barlow Semi Condensed", sans-serif; text-transform: uppercase;
  letter-spacing: .07em; font-size: 10.5px; color: var(--pk-3); margin-top: 5px;
}

/* the amber never-hidden block, when something is actually outstanding */
body.k9-preview.my-portal .never.warn { border-color: var(--amber); background: var(--amber-soft); }
body.k9-preview.my-portal .never.warn .k { color: var(--amber); }
body.k9-preview.my-portal .never ul { margin: 6px 0 0; padding-left: 18px; font-size: 14.5px; }
body.k9-preview.my-portal .never li { margin: 3px 0; }

/* the write doors, in one row at the top and never inside a list (pattern §4) */
body.k9-preview.my-portal .doors {
  display: flex; flex-wrap: wrap; gap: 8px; border: 1px solid var(--line); border-top: 0;
  background: var(--surface-2); padding: 11px 16px;
}
body.k9-preview.my-portal .doors a {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600; font-size: 12.5px;
  letter-spacing: .06em; text-transform: uppercase; text-decoration: none; color: var(--pk-2);
  background: var(--surface); border: 1px solid var(--line-2); padding: 7px 12px;
}
body.k9-preview.my-portal .doors a.primary { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-fill); }

/* tabs as LINKS -- a client's page works with no JavaScript, and a link is
   somewhere they can be sent to. The landing page relies on that. */
body.k9-preview.my-portal .tabbtn {
  flex: 0 0 auto; white-space: nowrap; text-decoration: none;
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600; font-size: 12.5px;
  letter-spacing: .07em; text-transform: uppercase; border-right: 1px solid var(--line);
  /* 13px a side, not 15: 15 Oct 2026, Q195 -- with Handler's information
     on the row, the last tab wrapped on its own under the first. */
  padding: 11px 13px; color: var(--pk-3);
}
body.k9-preview.my-portal .tabbtn.on {
  background: var(--surface); color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent);
}

/* ⭐⭐ THE LONG ROW, AND IT IS ALLOWED TO WRAP. Sep 7, 2026, the facility's
   layout: one long row where all those tabs live, double-stacked inside the
   box when they need to be.

   Nine tabs do not fit one line on a laptop and never will on a phone, so the
   strip wraps into a second row rather than scrolling sideways -- a tab a
   client cannot see is a tab they will not press, and horizontal scroll inside
   a card is the thing nobody discovers. */
/* ⛔⛔ EVERY STRIP, NOT ONLY THE WIDE ONE. 07 Sep 2026, from a phone
   screenshot: "phone app looks good, just bunched right here."

   `.tabstrip.wide` -- added the same evening for Your details -- was the only
   strip with any container styling at all. The dog page's plain `.tabstrip`
   had none, so its buttons flowed as inline text and piled onto each other the
   moment they wrapped: "Clay's stays" sitting on top of "About Clay". The
   `flex: 0 0 auto` on .tabbtn was doing nothing, because nothing above it was
   a flex container.

   ⭐ It wraps rather than scrolling sideways. A tab a client cannot see is a
   tab they will not press, and horizontal scroll inside a card is the thing
   nobody discovers. */
body.k9-preview.my-portal .tabstrip {
  display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--line);
}
body.k9-preview.my-portal .tabstrip .tabbtn {
  border-bottom: 1px solid transparent;
}
/* A card drawn INSIDE a tab has no edges of its own -- the tab is the edge. */
body.k9-preview.my-portal .card.bare {
  border: 0; background: none; margin: 0;
}
body.k9-preview.my-portal .card.bare > h2 {
  border-bottom: 1px solid var(--line);
}
/* One document open for correcting, under the vaccination table. */
body.k9-preview .paper-edit { padding: 4px 16px 16px; }

/* The door a family puts another dog through. Under the dogs when there are
   any, on its own when there are none. 26 Sep 2026. */
body.k9-preview.my-portal .add-a-dog { padding: 14px 16px 16px; }
body.k9-preview.my-portal .rows + .add-a-dog { border-top: 1px solid var(--line); }
body.k9-preview.my-portal .add-a-dog + .empty { border-top: 1px solid var(--line); }
/* ⏱️ 8 Oct 2026: one button that opens a card, and Save adds the dog. */
body.k9-preview.my-portal .add-a-dog form { margin: 0; }
body.k9-preview.my-portal .add-a-dog-card > summary {
  display: inline-block; list-style: none; cursor: pointer;
}
body.k9-preview.my-portal .add-a-dog-card > summary::-webkit-details-marker { display: none; }
body.k9-preview.my-portal .add-a-dog-card[open] > summary { display: none; }
body.k9-preview.my-portal .add-a-dog-card[open] > form {
  border: 1px solid var(--line-2); padding: 14px 16px; max-width: 36rem;
}
body.k9-preview.my-portal .add-a-dog-fields {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px;
}
body.k9-preview.my-portal .add-a-dog-fields .wide { grid-column: 1 / -1; }
@media (max-width: 520px) {
  body.k9-preview.my-portal .add-a-dog-fields { grid-template-columns: 1fr; }
}
body.k9-preview.my-portal .add-a-dog .field { margin-bottom: 0; }
body.k9-preview.my-portal .add-a-dog .field input,
body.k9-preview.my-portal .add-a-dog .field select { width: 100%; }
body.k9-preview.my-portal .add-a-dog-do { display: flex; gap: 8px; margin-top: 14px; }

body.k9-preview.my-portal .rows { display: flex; flex-direction: column; }
body.k9-preview.my-portal .row {
  display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--line); font-size: 14.5px;
}
body.k9-preview.my-portal .row:last-child { border-bottom: 0; }
body.k9-preview.my-portal .row .when {
  font-family: "IBM Plex Mono", monospace; font-size: 12.5px; color: var(--pk-2);
  white-space: nowrap; min-width: 92px;
}
body.k9-preview.my-portal .miss { color: var(--amber); }

/* ⭐ STILL BEING BUILT — the client-facing cousin of the `not built` marker on
   a staff door. Sep 7, 2026, and it exists because a real stranger was about
   to walk this portal while half of it was unfinished.

   Quiet on purpose. It is a courtesy, not a warning: loud enough to answer
   "is this broken?" and quiet enough that a finished-looking page does not
   read as a building site. */
body.k9-preview .building {
  display: inline-block; margin-left: 8px;
  font-size: 11.5px; font-weight: 500; letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line-2);
  border-radius: 2px; padding: 1px 6px; vertical-align: middle;
  white-space: nowrap;
}

/* ⭐⭐ THE DOG PAGE'S HEADER, ON THE OWNER'S SIDE. Sep 7, 2026.

   The staff dog page's header was sent as a screenshot: every dog page gets
   that header, the client portal included. So: picture left, name, facts
   under it, room on the right.

   ⛔ NOT CROPPED -- cropping ruins the picture. Sized by HEIGHT with the width
   left to follow, so a tall dog and a wide dog both survive whole.

   ⚠️ AND IT DOES NOT TAKE THE PAGE. The first attempt was a 132px square and
   she read it back at once — a picture that owns half the screen pushes the
   thing they came for below the fold. A header photograph, not a poster. */
body.k9-preview.my-portal .ident-top {
  display: flex; flex-wrap: wrap; gap: 14px 26px;
  align-items: flex-end; justify-content: space-between;
}
body.k9-preview.my-portal .ident-who {
  display: flex; align-items: flex-end; gap: 16px;
}
body.k9-preview.my-portal .ident-photo {
  height: 92px; width: auto; max-width: 150px;
  object-fit: contain; object-position: bottom;
  display: block; border: 1px solid var(--line-2); background: var(--surface-2);
}
body.k9-preview.my-portal span.ident-photo.none {
  width: 92px; display: flex; align-items: center; justify-content: center;
  border-style: dashed; color: var(--pk-3); font-size: 30px;
}

/* The write door, under the header rather than in it — house pattern §4c. */
body.k9-preview.my-portal .dogpic-door {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
}
body.k9-preview.my-portal .dogpic-door .say {
  font-size: 13px; color: var(--pk-2); flex: 1 1 100%;
}

/* ⭐⭐ LOOKING AT THE PRACTICE PORTAL. Sep 7, 2026.

   Loud on purpose, and the same reasoning as View-as-a-role's amber bar on
   Sep 3: everything below it is drawn exactly as a client would get it, which
   is the point and also the danger. A page that looks like a client's page and
   is not one is the most confusing screen this application can produce. */
.looking-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  background: var(--looking); color: #fff;
  padding: 9px 18px; font-size: 14px;
}
.looking-bar strong { color: #fff; }
.looking-bar form { margin: 0; }
.looking-bar button {
  background: #fff; color: var(--looking-ink); border: 0; border-radius: 2px;
  padding: 5px 12px; font-size: 13px; font-weight: 600; cursor: pointer;
}

/* ⛔⛔ AND A DIFFERENT COLOR WHEN IT IS A REAL PERSON'S PAGE. 18 Sep 2026.
   The practice bar says "nothing here is real". This one is standing on a
   client's own record, so it must not read as the practice bar at a glance.
   Deeper and warmer, and the button keeps its contrast against it. */
.looking-bar.real { background: var(--looking-real); }
.looking-bar.real button { color: var(--looking-real-ink); }

/* ⭐⭐ MESSAGE US — Sep 7, 2026. The third tile in the row that already answers
   "how do I reach you", and the line that carries a reply above the fold.

   ⭐ COUNT AND HIGHLIGHT BOTH. The box has to be highlighted somehow to let
   them know there is a reply. A bare number on a quiet tile is
   missable; a lit tile with no number does not say whether it is one thing or
   five. */
body.k9-preview.my-portal .reach a.waiting {
  background: var(--note-bg); border-left: 3px solid var(--note);
}
body.k9-preview.my-portal .reach .count {
  display: inline-block; background: var(--note); color: #fff;
  border-radius: 9px; padding: 0 7px; font-size: 11px; margin-left: 4px;
}
body.k9-preview.my-portal .waiting-line {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  background: var(--note-bg); border: 1px solid var(--note-line);
  color: var(--note); text-decoration: none;
  padding: 12px 18px; margin-bottom: 14px; font-size: 15px;
}
body.k9-preview.my-portal .waiting-line .go { font-weight: 600; }

/* The thread itself. Ours on the left, theirs indented — the same shape a
   person expects from every conversation they have ever read. */
body.k9-preview.my-portal .thread { display: grid; gap: 14px; margin-bottom: 20px; }
body.k9-preview.my-portal .thread .said {
  border-left: 3px solid var(--line-2); padding-left: 12px;
}
body.k9-preview.my-portal .thread .said.mine {
  border-left-color: var(--accent); margin-left: 28px;
}
body.k9-preview.my-portal .thread .words { margin-top: 3px; }
body.k9-preview.my-portal .answer-here {
  border-top: 1px solid var(--line); margin-top: 18px; padding-top: 16px;
}
body.k9-preview.my-portal .answer-here textarea { width: 100%; max-width: 46rem; }

/* ⭐⭐⭐ GREEN STOPS MEANING REMOVE. 12 Sep 2026.

   Asked where the eye is drawn on four screenshots of her own dog's health
   tab, the answer was the green buttons -- "Take it off" three times, brighter
   than the dog's own medication. The destructive action was styled as the
   primary one, and the record itself was the dimmest thing on the page.

   ⛔ ONE PRIMARY PER PANEL, and it is the thing the panel is for. Correcting
   and taking off are quiet: a bordered button in the text color, no fill. They
   are still perfectly pressable; they simply stop shouting. */
body.k9-preview.my-portal button.quiet {
  background: transparent; color: var(--text);
  border: 1px solid var(--line-2); font-weight: 500;
}
body.k9-preview.my-portal button.quiet:hover {
  border-color: var(--muted); background: var(--surface);
}

/* ⭐ THE LITTLE LINK. Adding or removing gets its own little link. It is a
   link, not a button -- nothing on a reading page should look
   like the primary act. */
body.k9-preview.my-portal .door-line { margin: 14px 0 2px; }
body.k9-preview.my-portal a.quietdoor {
  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 13.5px; letter-spacing: .02em;
  color: var(--accent); text-decoration: underline;
  text-underline-offset: 3px;
}
body.k9-preview.my-portal a.quietdoor:hover { color: var(--text); }
body.k9-preview.my-portal .answer-here a.cancel {
  margin-left: 10px; font-size: 13.5px; color: var(--muted);
}

/* ⭐ THE RECORD IS THE LOUD THING. A dog's medication, allergy or condition is
   what somebody came to this page to read; it was set in the quietest type on
   it while the controls were the brightest. */
body.k9-preview.my-portal .facts dt {
  color: var(--text); font-weight: 600;
}
body.k9-preview.my-portal .facts dd { color: var(--text); }
body.k9-preview.my-portal .facts dd .meta { color: var(--muted); }

/* The breakout strip inside a tab -- smaller than the tabs above it, so the
   two levels do not compete. */
body.k9-preview.my-portal .tabstrip.sub .tabbtn { font-size: 13px; }

/* ⭐⭐ 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. */
body.k9-preview .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(--amber); color: #fff;
  border-radius: 3px; padding: 1px 6px; margin-left: 6px;
}

/* ⛔ THE STEP RAIL WAS PAINTING ITSELF WHITE. Sep 8, 2026.
   Found on the live wizard: step 2's chip was unreadable while 1 and
   3 read fine. `.step-chip` in app.css hardcodes `background:#fff`, so on the
   themed page the chip stayed white while `.now` set its text from --text --
   light text on a white chip. The chips take their colors from the theme
   here, like every other control on this scope. */
body.k9-preview .step-chip {
  background: var(--surface); color: var(--muted); border-color: var(--line-2);
}
body.k9-preview .step-chip.now {
  background: var(--surface); color: var(--pk);
  border-color: var(--accent); box-shadow: inset 0 -3px 0 var(--accent);
}
body.k9-preview button.step-chip:hover {
  border-color: var(--accent); color: var(--pk);
}

/* ⛔ CARDS BUILT THE OLD WAY HAD NO PADDING AT ALL. Sep 9, 2026.
   On the booking page, everything on the left-hand side looked about to be
   cut off.

   She is describing `.card { padding: 0 }`, which is correct for the pattern
   this stylesheet was written around -- a padded `> h2` above a padded
   `.card-body`. Every card built the older way (an `h3` and rows straight
   inside) therefore sits flush against its own border.

   ⭐ SCOPED WITH :has() SO IT TOUCHES ONLY THOSE. A card that carries the
   newer pattern is left exactly as it was, which is why this is one rule
   rather than an edit to forty templates. */
body.k9-preview .card:not(:has(> h2)):not(:has(> .card-body)) {
  padding: 14px 16px;
}

/* Coursework on the client's own dog page. Read only -- every door into it is
   on the facility's side. 09 Sep 2026. */
body.k9-preview .cwline { display: flex; align-items: baseline; flex-wrap: wrap;
                          gap: 4px 14px; padding: 5px 0; margin: 0;
                          border-bottom: 1px solid var(--line); }
body.k9-preview .cwline:last-child { border-bottom: 0; }
body.k9-preview .cwline .when { color: var(--pk-3); font-size: .85rem;
                                font-family: "IBM Plex Mono", monospace; }

/* ⭐⭐ THE COURSE ITSELF, ON THE OWNER'S SIDE. 18 Sep 2026, after a client
   telephoned to say she could not see her dog's training at all. A week is a
   block; the sessions inside it are indented under it; the task box is the
   build page's own partial and brings its own styling. No new color is
   introduced here -- it is the same line and the same muted ink the rest of
   this panel uses. */
body.k9-preview .cwweek { padding: 10px 0; border-bottom: 1px solid var(--line); }
body.k9-preview .cwweek:last-child { border-bottom: 0; }
/* A family's activity folds inside each other -- years, months, days.
   8 Oct 2026. Each level steps in so the reader can see which fold it is in. */
body.k9-preview details.cwweek.act-in { margin-left: 14px; padding: 6px 0; }
body.k9-preview .cwweekhead { display: flex; align-items: baseline;
                              flex-wrap: wrap; gap: 4px 12px; margin: 0 0 6px;
                              font-weight: 600; }
body.k9-preview .cwsession { margin: 8px 0 0 18px;
                             border-left: 2px solid var(--line);
                             padding-left: 12px; }
body.k9-preview .cwsessionhead { display: flex; align-items: baseline;
                                 flex-wrap: wrap; gap: 4px 12px;
                                 margin: 0 0 4px; }
body.k9-preview .cwweekhead .when,
body.k9-preview .cwsessionhead .when { color: var(--pk-3); font-size: .85rem;
                                       font-weight: 400;
                                       font-family: "IBM Plex Mono", monospace; }

/* ⭐ The Coursework jump is a LABEL pointed at that tab's own radio, because
   the tab strip lives in the page rather than in the address. It has to look
   and behave like the link it replaced. 10 Sep 2026. */
body.k9-preview .cwmore label,
body.k9-preview .cwprog label,
body.k9-preview .cwname label {
  color: var(--accent); cursor: pointer; text-decoration: underline;
}
body.k9-preview .cwmore label:hover,
body.k9-preview .cwprog label:hover,
body.k9-preview .cwname label:hover { text-decoration: none; }

/* ---------------------------------------------------------------------------
   THE BOOKING PAGE, REDRAWN. 11 Sep 2026.

   The layout of the booking page was too much -- too many things, too many
   moving parts, too many wheels. And the reason it matters past one person's
   comfort: if somebody who helped build it cannot stand it, people who are
   not computer literate will hate it and not use us.

   The dogs become the middle of the page on a stay instead of a line in a
   table, and the booking's own details become one card with one save.
   --------------------------------------------------------------------------- */

body.k9-preview .bk-dog {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 15px 0; border-top: 1px solid var(--line);
}
body.k9-preview .bk-dog:first-of-type { border-top: 0; padding-top: 4px; }

body.k9-preview .bk-dog-face {
  width: 52px; height: 52px; border-radius: 50%; overflow: hidden;
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  background: var(--panel, rgba(127,127,127,.08));
  border: 1px solid var(--line); text-decoration: none; font-size: 22px;
}
body.k9-preview .bk-dog-face img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

body.k9-preview .bk-dog-mid { flex: 1 1 auto; min-width: 0; }
body.k9-preview .bk-dog-name { margin: 0; font-size: 18px; font-weight: 700; }
body.k9-preview .bk-dog-name a { color: inherit; text-decoration: none; }
body.k9-preview .bk-dog-name a:hover { text-decoration: underline; }
body.k9-preview .bk-dog-breed {
  margin: 1px 0 6px; font-size: 14px; color: var(--muted);
}
body.k9-preview .bk-dog-line { margin: 6px 0 0; font-size: 14.5px; }

body.k9-preview .bk-dog-run { flex: 0 0 auto; width: 260px; max-width: 100%; }

/* THE KENNEL, BIG. 21 Sep 2026 -- the kennel a dog is in was a line of small
   gray text beside the move box, and two dogs sharing one run went unseen until
   somebody said so. Now it is a box the eye lands on. */
body.k9-preview .bk-kennel {
  border: 2px solid var(--accent); border-radius: 8px;
  padding: 6px 10px; margin-bottom: 8px; text-align: center;
}
body.k9-preview .bk-kennel-k {
  display: block; font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
body.k9-preview .bk-kennel-n {
  display: block; font-size: 22px; font-weight: 700; line-height: 1.15;
  color: var(--accent);
}

/* Folded at the bottom of a stay: weights, run cards, activity, moves. */
body.k9-preview details.bk-fold > summary { cursor: pointer; font-size: 15px; }
body.k9-preview details.bk-fold[open] > summary { margin-bottom: 10px; }

/* The price, a dog to a line, with the Total lines under it. */
body.k9-preview .bk-price-line {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 4px 0; border-top: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
body.k9-preview .bk-price-line:first-child { border-top: 0; }
body.k9-preview .bk-price-total { font-weight: 700; border-top: 2px solid var(--line); }

/* One card, one save. The grid wraps to one column on a phone. */
body.k9-preview .bk-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
body.k9-preview .bk-grid .bk-wide { grid-column: 1 / -1; }
body.k9-preview .bk-grid .field { margin: 0; }
body.k9-preview .bk-grid textarea { width: 100%; }

body.k9-preview .bk-savebar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
}

@media (max-width: 620px) {
  body.k9-preview .bk-dog { flex-wrap: wrap; }
  body.k9-preview .bk-dog-run { width: 100%; }
}
body.k9-preview .bk-standing { margin: 0 0 6px; font-size: 15px; }

/* Each dog's notes, under that dog. 11 Sep 2026 -- each dog's note sits
   directly under that dog. Indented to the
   dog's name rather than the card edge, so it reads as belonging to the row
   above it and not as a new section. */
body.k9-preview .bk-dog-notes {
  margin: -4px 0 4px 66px; padding: 0 0 12px;
  border-bottom: 1px solid var(--line);
}
body.k9-preview .bk-dog + .bk-dog-notes { border-top: 0; }
body.k9-preview .bk-dog-notes .bk-note { margin: 0 0 8px; font-size: 15px; }
body.k9-preview .bk-note-add > summary {
  cursor: pointer; color: var(--accent); font-size: 14px; padding: 2px 0;
}
@media (max-width: 620px) {
  body.k9-preview .bk-dog-notes { margin-left: 0; }
}

/* The client's portal: an invoice hanging off its stay, and the roll-up.
   11 Sep 2026 -- "stays need a roll up, especially the long ones ... they
   should show, like, ten, and then they should roll up." */
.billlink {
  font-size: 13.5px; font-weight: 650; text-decoration: none;
  border: 1px solid currentColor; border-radius: 100px; padding: 2px 9px;
  white-space: nowrap;
}
.rollup > summary {
  cursor: pointer; padding: 9px 0; font-weight: 650;
  list-style: none;
}
.rollup > summary::-webkit-details-marker { display: none; }
.rollup > summary::before { content: "+ "; }
.rollup[open] > summary::before { content: "– "; }
.rowlink { text-decoration: none; color: inherit; }
/* The wallet's four cards. 11 Sep 2026 -- "underneath the wallet, four tabs,
   just like in the picture." Outstanding balance carries the invoices still
   owed; the other three are figures with a sentence saying what they are. */
.wallet-cards { display: grid; gap: 14px; margin: 4px 0 6px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.wallet-cards .wcard { border: 1px solid rgba(127,127,127,.28);
  border-radius: 12px; padding: 14px 16px; }
.wallet-cards .wcard .k { font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .06em; opacity: .7; }
.wallet-cards .wcard .v { font-size: 26px; font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums; margin-top: 2px; }
.wallet-cards .wcard .v .meta { font-size: 14px; font-weight: 500; }
.wallet-cards .wcard .meta { display: block; margin-top: 6px; font-size: 13.5px; }
.wallet-cards .wcard .rows { margin-top: 10px; }
/* The outstanding-balance card carries a list, so it spans wider when it can. */
.wallet-cards .wcard:first-child { grid-column: span 2; }
@media (max-width: 560px) {
  .wallet-cards .wcard:first-child { grid-column: auto; }
}

/* One invoice, drawn for the person paying it. */
.inv-head { display: flex; justify-content: space-between; gap: 14px;
  flex-wrap: wrap; align-items: flex-start; }
.inv-head .big { font-size: 24px; font-weight: 700; }
.inv-for { margin: 10px 0 14px; }
table.inv-lines { width: 100%; border-collapse: collapse; margin-top: 6px;
  font-variant-numeric: tabular-nums; }
table.inv-lines td { padding: 8px 0; border-bottom: 1px solid rgba(127,127,127,.22); }
table.inv-lines td.num { text-align: right; white-space: nowrap; }
table.inv-lines tr.off td { opacity: .85; }
table.inv-lines tfoot tr.tot td { font-weight: 700; border-top: 2px solid currentColor; }
table.inv-lines tfoot tr.bal td { font-weight: 700; }
.owed-head { margin: 2px 0 14px; }
.owed-head .k { font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .06em; opacity: .7; }
.owed-head .big { font-size: 30px; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.1; }


/* ==========================================================================
   THE TRAINING BUILD PAGE.  13 Sep 2026.
   Two columns: the course being built, and the gallery it is built from.
   The gallery never empties, because it is her material, not this course's.
   ========================================================================== */
body.k9-preview .tb-cols {
  display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start;
}
body.k9-preview .tb-main { flex: 1 1 520px; min-width: 0; }
body.k9-preview .tb-side { flex: 1 1 320px; min-width: 0; }

/* ⭐⭐ THE GALLERY TRAVELS WITH HER. 14 Sep 2026, building week three of a
   six-week course:

       "Can the task gallery on the right side float down the page as I am
        building... While I'm way down at the bottom at week four or five?"

   It sticks to the top of the window and scrolls inside itself, so the
   material is beside week five exactly as it is beside week one, however long
   the course gets.

   ⛔ ONLY WHERE THERE ARE TWO COLUMNS. Below the wrap point the columns stack
   and a stuck panel would sit on top of what she is reading, so the float
   stops and the page just scrolls -- which is also why the white paper says
   to build the structure on a laptop. */
@media (min-width: 860px) {
  body.k9-preview .tb-side {
    position: sticky;
    top: 12px;
    align-self: flex-start;
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    /* Room for the scrollbar so it never sits on top of a button. */
    padding-right: 4px;
    /* ⚠️ A sticky box with its own scrollbar hides the fact that it scrolls.
       A thin rule at the bottom edge is the cheapest honest hint. */
    scrollbar-width: thin;
  }
}

body.k9-preview .tb-row {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-top: 10px;
}
body.k9-preview .tb-row input[type="text"],
body.k9-preview .tb-row input[type="search"],
body.k9-preview .tb-row select { flex: 1 1 12rem; min-width: 0; }

body.k9-preview .tb-inline { display: inline; }

/* A quiet control is still a control: it underlines, it has a pointer, and
   it never looks like body text. The rule -- a thing that does something has
   to look like it. */
body.k9-preview .tb-quiet {
  background: none; border: 0; padding: 0 2px; cursor: pointer;
  color: var(--pk-3); font: inherit; font-size: 12.5px;
  text-decoration: underline;
}
body.k9-preview .tb-quiet:hover { color: var(--accent); }

body.k9-preview .tb-count {
  font-size: 12px; color: var(--pk-3); background: var(--surface-2);
  border-radius: 999px; padding: 1px 8px; white-space: nowrap;
}

body.k9-preview .tb-found {
  font-size: 13px; color: var(--pk-2); margin: 8px 0 0;
}

/* ---- the gallery tree ---- */
body.k9-preview .tb-tree { margin-top: 12px; }
body.k9-preview .tb-type { margin-bottom: 14px; }
body.k9-preview .tb-depth-2 {
  /* ⚠️ 14 Sep 2026: this was 14px + 10px, and those 24px were enough to push
     the buttons off the end of every row in a sub-type -- so Crate and Door
     drew two lines per task where Impulse Control drew one. The nesting only
     has to be READABLE, not wide. */
  margin-left: 8px; padding-left: 8px;
  border-left: 2px solid var(--line);
}
body.k9-preview .tb-type-head {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); padding-bottom: 5px; margin-bottom: 6px;
  cursor: pointer; list-style: none;
}
body.k9-preview .tb-type-head::-webkit-details-marker { display: none; }
body.k9-preview .tb-type-head::before {
  content: "\25B8"; color: var(--pk-3); font-size: 11px; flex: 0 0 auto;
}
body.k9-preview details.tb-type[open] > .tb-type-head::before { content: "\25BE"; }
body.k9-preview .tb-type-head:hover .tb-type-name { color: var(--accent); }
body.k9-preview .tb-type-name { font-weight: 600; }
body.k9-preview .tb-type-head .tb-quiet { margin-left: auto; }

body.k9-preview .tb-task { padding: 2px 0; font-size: 13.5px; }
body.k9-preview .tb-task-line {
  /* ⛔ NO WRAP ON THE ROW. Her words, on the indented sub-types: "I don't
     want them so spread out." The controls stay pinned on the line and a long
     name wraps under itself instead, because the name is the thing that can
     take the squeeze. */
  display: flex; gap: 8px; align-items: baseline; flex-wrap: nowrap;
  padding: 4px 0; cursor: pointer; list-style: none;
}
body.k9-preview .tb-task-line::-webkit-details-marker { display: none; }
body.k9-preview .tb-task-line::before {
  content: "\25B8"; color: var(--pk-3); font-size: 11px; flex: 0 0 auto;
}
body.k9-preview details[open] > .tb-task-line::before { content: "\25BE"; }
body.k9-preview .tb-task-line:hover .tb-task-name { color: var(--accent); }
body.k9-preview .tb-task-name { flex: 1 1 auto; min-width: 0; }
body.k9-preview .tb-task-do {
  display: flex; gap: 8px; align-items: baseline; flex-wrap: nowrap;
  margin-left: auto; flex: 0 0 auto; white-space: nowrap;
}
/* ⭐ THE LINE ABOVE IS HERS, 14 Sep 2026 -- "I don't want them so spread
   out" -- and it was NOT the fault on 24 Sep. It holds on one assumption:
   that the controls are SMALL. The day a button carried a session name
   somebody typed, the controls stopped being small and this rule did
   exactly what it says, squeezing the name to one word per line. The cure
   was the label. Loosening this instead would let the row wrap again, which
   is the thing she asked to be rid of. → `_the_gallery_branch.html`. */
body.k9-preview .tb-adding-to {
  color: var(--pk-2); font-size: 13px; margin: 0 0 10px;
}
/* Two adds on New task, the same size side by side; the ways back the same. */
body.k9-preview .tb-twoadds,
body.k9-preview .tb-wayback {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px; max-width: 520px; margin: 10px 0 0;
}
body.k9-preview .tb-twoadds .btn,
body.k9-preview .tb-wayback .btn {
  width: 100%; text-align: center; justify-content: center;
}
/* Switched off, never deleted. Struck through and still legible. */
body.k9-preview .tb-off .tb-task-name {
  text-decoration: line-through; color: var(--pk-3);
}
body.k9-preview .tb-plus {
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent); border-radius: 6px;
  padding: 2px 8px; font: inherit; font-size: 12px; cursor: pointer;
  white-space: nowrap;
}
body.k9-preview .tb-plus:hover { background: var(--brand-fill); color: var(--on-fill); }

/* Already on the week she is working in: a plain statement where the button
   would have been, so it reads as settled rather than as a control that has
   been switched off. 19 Sep 2026. */
body.k9-preview .tb-already {
  color: var(--pk-3); font-size: 12px; white-space: nowrap;
  padding: 2px 0;
}

/* ---- the weeks ---- */
body.k9-preview .tb-week-head {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  cursor: pointer; list-style: none; padding: 15px 17px;
}
body.k9-preview .tb-week-head::-webkit-details-marker { display: none; }
body.k9-preview .tb-week-head::before {
  content: "\25B8"; color: var(--pk-3); font-size: 12px; flex: 0 0 auto;
}
body.k9-preview details.tb-week[open] > .tb-week-head::before { content: "\25BE"; }
body.k9-preview details.tb-week > .card-body { padding-top: 0; }
body.k9-preview .tb-week-head h3 { margin: 0; }
body.k9-preview .tb-week-on { border-color: var(--accent); }

/* WHOSE COPY IS OPEN. It is a card like the others, and the rail is the only
   thing that makes it read as a bar over the page rather than the first item
   on it. 19 Sep 2026. */
body.k9-preview .tb-whose { border-left: 3px solid var(--accent); }

/* HOW LONG: what it is set to, then the two boxes that change it. They sit on
   one line with real spacing rather than running together. 19 Sep 2026. */
body.k9-preview .bk-howlong {
  display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap;
}
body.k9-preview .bk-len { margin-right: 6px; }
body.k9-preview .tb-adding {
  margin-left: auto; font-size: 12px; font-weight: 600;
  color: var(--accent); background: var(--accent-soft);
  border-radius: 999px; padding: 2px 9px;
}
body.k9-preview .tb-week-head .tb-quiet { margin-left: auto; }
body.k9-preview .tb-week-tasks { margin: 10px 0 0; padding-left: 22px; }
body.k9-preview .tb-week-tasks li {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  padding: 4px 0; border-bottom: 1px solid var(--line);
}
body.k9-preview .tb-week-tasks li:last-child { border-bottom: 0; }
body.k9-preview .tb-task-type { font-size: 12px; color: var(--pk-3); }
body.k9-preview .tb-weekbits { margin-top: 10px; }
body.k9-preview .tb-weekbits > summary { cursor: pointer; }

body.k9-preview .tb-load > summary,
body.k9-preview .tb-add > summary {
  cursor: pointer; padding: 13px 16px;
}
body.k9-preview .tb-load label,
body.k9-preview .tb-add label,
body.k9-preview .tb-main label {
  display: block; margin-top: 10px; font-size: 13px; color: var(--pk-2);
}
body.k9-preview .tb-add input[type="text"],
body.k9-preview .tb-add select,
body.k9-preview .tb-add textarea,
body.k9-preview .tb-main input[type="text"],
body.k9-preview .tb-main textarea { width: 100%; }

/* ---- the whole inventory, 13 Sep 2026 ---- */
body.k9-preview .tb-counts {
  display: flex; flex-wrap: wrap; gap: 7px; margin: 12px 0 0;
}
body.k9-preview .tb-countchip {
  display: inline-flex; gap: 6px; align-items: center;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 11px; font-size: 12.5px;
  color: var(--pk-2); text-decoration: none;
}
body.k9-preview .tb-countchip:hover { border-color: var(--accent); color: var(--accent); }
body.k9-preview .tb-countchip-on {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
body.k9-preview .tb-table { width: 100%; border-collapse: collapse; margin-top: 6px; }
body.k9-preview .tb-table th {
  text-align: left; font-size: 11.5px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--pk-3); font-weight: 700;
  padding: 0 12px 7px 0; border-bottom: 1px solid var(--line-2);
  white-space: nowrap;
}
body.k9-preview .tb-table td {
  padding: 8px 12px 8px 0; border-bottom: 1px solid var(--line);
  vertical-align: top; font-size: 13.5px;
}
body.k9-preview .tb-table tr.tb-off .tb-task-name {
  text-decoration: line-through; color: var(--pk-3);
}
/* ⭐⭐ THE GROUP HEADING. 15 Sep 2026. The inventory sorted parent-first from
   the day it was built and drew no line between one group and the next, so the
   ordering was invisible -- "the only thing offered is A to Z, which really
   doesn't allow you to group by type."

   ⚠️ IT IS A `th` INSIDE THE BODY, not a styled `td`, because it labels the
   rows under it. Which means it has to undo the head's own `th` rules. */
body.k9-preview .tb-table tr.tb-grouprow > th.tb-grouphead {
  text-transform: none; letter-spacing: 0; white-space: normal;
  font-size: 13.5px; color: var(--pk); font-weight: 700;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-2);
  border-top: 1px solid var(--line-2);
  padding: 9px 12px 9px 10px;
}
body.k9-preview .tb-table tr.tb-grouprow:first-child > th.tb-grouphead {
  border-top: 0;
}
body.k9-preview .tb-groupname { color: var(--accent); }
body.k9-preview .tb-groupcount {
  font-weight: 400; color: var(--pk-3); font-size: 12px;
  margin-left: 9px; font-variant-numeric: tabular-nums;
}

body.k9-preview .tb-num { font-variant-numeric: tabular-nums; color: var(--pk-2); }
body.k9-preview .tb-rowdo { white-space: nowrap; }
body.k9-preview .tb-amend { display: inline-block; min-width: 16rem; }
body.k9-preview .tb-amend > summary { cursor: pointer; }
body.k9-preview .tb-amend input[type="text"],
body.k9-preview .tb-amend select,
body.k9-preview .tb-amend textarea { width: 100%; }

/* ---- move, reorder, delete, and a task's own page. 13 Sep 2026 ---- */
body.k9-preview .tb-danger {
  background: none; border: 0; padding: 0 2px; cursor: pointer;
  color: var(--red); font: inherit; font-size: 12.5px; text-decoration: underline;
}
body.k9-preview .tb-danger:hover { color: #fff; background: var(--red);
  border-radius: 4px; text-decoration: none; }
body.k9-preview .tb-typebits { margin: 0 0 8px; }
body.k9-preview .tb-typebits > summary { cursor: pointer; }
body.k9-preview .tb-typebits .tb-row { margin-top: 8px; }
body.k9-preview .tb-task-open { color: var(--pk); text-decoration: none;
  border-bottom: 1px solid transparent; }
body.k9-preview .tb-task-open:hover { color: var(--accent);
  border-bottom-color: var(--accent); }
body.k9-preview .tb-used { margin: 6px 0 0; padding-left: 20px; font-size: 13.5px; }
body.k9-preview .tb-used li { margin-bottom: 4px; }

body.k9-preview .tb-tickcol { width: 2.2rem; }
body.k9-preview .tb-tickhead { font-size: 10.5px; }
body.k9-preview .tb-bulkbar {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--line-2);
}
body.k9-preview .tb-tickall { font-size: 13px; color: var(--pk-2);
  display: inline-flex; gap: 6px; align-items: center; }
body.k9-preview .tb-bulksep { color: var(--pk-3); font-size: 12.5px; }

/* ---- a task's card, opened where it sits. 13 Sep 2026 ---- */
body.k9-preview .tb-card {
  background: var(--surface-2); border: 1px solid var(--line-2);
  border-radius: 9px; padding: 13px 14px; margin: 4px 0 12px;
}
body.k9-preview .tb-card label {
  display: block; margin-top: 10px; font-size: 13px; color: var(--pk-2);
}
body.k9-preview .tb-card label:first-of-type { margin-top: 0; }
body.k9-preview .tb-card input[type="text"],
body.k9-preview .tb-card select,
body.k9-preview .tb-card textarea { width: 100%; }
body.k9-preview .tb-card .tb-row { margin-top: 12px; }

body.k9-preview .tb-cardrow > td { padding-top: 0; border-bottom: 0; }
body.k9-preview .tb-rowfold > summary { cursor: pointer; }
body.k9-preview .tb-written {
  font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  font-weight: 700; color: var(--accent); background: var(--accent-soft);
  border-radius: 4px; padding: 1px 6px; text-decoration: none;
  display: inline-block;
}

/* ---- dragging. 13 Sep 2026: "Please make sure we can drag." ----
   The grip is the only draggable thing, and it looks like one. Everything a
   drag does, a button on the same row also does. */
body.k9-preview .tb-grip {
  cursor: grab; color: var(--pk-3); letter-spacing: -3px; flex: 0 0 auto;
  padding: 0 3px; user-select: none; font-size: 15px; line-height: 1;
}
body.k9-preview .tb-grip:active { cursor: grabbing; }
body.k9-preview .tb-grip:hover { color: var(--accent); }

/* While something is in the air, say where it can land. */
body.k9-preview.tb-dragging .tb-week,
body.k9-preview.tb-dragging .tb-type-head {
  outline: 1px dashed var(--line-2); outline-offset: 2px;
}
body.k9-preview .tb-lit {
  outline: 2px solid var(--accent) !important; outline-offset: 2px;
  background: var(--accent-soft);
}
body.k9-preview .tb-week-tasks li.tb-lit {
  border-top: 2px solid var(--accent); outline: 0 !important;
  background: var(--accent-soft);
}
body.k9-preview .tb-said {
  position: fixed; left: 16px; bottom: 16px; z-index: 60;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent); border-radius: 8px;
  padding: 8px 13px; font-size: 13px; box-shadow: var(--shadow);
}
@media (prefers-reduced-motion: reduce) {
  body.k9-preview .tb-lit { transition: none; }
}

/* The line that says a task belongs to the type itself rather than to one of
   its sub-types. 14 Sep 2026. */
body.k9-preview .tb-directly {
  margin: 10px 0 4px; font-size: 11px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--pk-3); font-weight: 700;
}

/* Switching which week the gallery adds to. 14 Sep 2026 — a control that
   does something has to look like it. */
body.k9-preview .tb-pickweek {
  margin-left: auto; font-size: 12.5px; padding: 3px 11px;
  text-decoration: none; white-space: nowrap;
}

/* ⭐ A CORRECTION SAYS SO, QUIETLY. 14 Sep 2026.
   A misspelling has to be editable. The stamp is
   the record half of that -- it must be readable and it must not compete
   with the account it sits under. */
.inc-fixed {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--pk-3);
  font-style: italic;
}
.inc-fix-entry {
  grid-column: 1 / -1;
  margin-top: 4px;
}
.inc-fix-entry > summary {
  font-size: 12px;
}

/* ⭐⭐ THE WHOLE REPORT ON ONE CARD. 14 Sep 2026.
   Going in, clicking it and editing it should not need a second button. Edit
   is a link in the card head, not a fold, and
   the card becomes the form in place. */
body.k9-preview .inc-edit {
  margin-left: auto;
  color: var(--accent);
  font-weight: 600;
  font-size: 13px;
  padding: 5px 11px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 6px;
  text-decoration: none;
  white-space: nowrap;
}
body.k9-preview .inc-edit:hover {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
body.k9-preview .inc-cancel {
  margin-left: 14px; color: var(--pk-3); font-size: 13px;
}
body.k9-preview .inc-editing { margin-top: 12px; }

/* ⛔ A SECTION WITH NOTHING IN IT SAYS SO AND STAYS ON THE CARD.
   The internal half drew nothing at all when blank, and that read as the
   record being closed, with no way left to add the internal notes. An absent
   section is a page lying by omission. */
body.k9-preview .inc-none {
  color: var(--pk-3);
  font-style: italic;
}

/* The release control, and the quieter one that takes it back off. */
body.k9-preview .inc-inline { margin: 8px 0 2px; }
body.k9-preview .btn-quiet {
  background: transparent;
  color: var(--amber);
  border: 1px solid color-mix(in srgb, var(--amber) 55%, transparent);
}
body.k9-preview .btn-quiet:hover {
  background: color-mix(in srgb, var(--amber) 14%, transparent);
}

/* ⭐ THE THREE KINDS, AND THE COLOR IS THE KEY RATHER THAN THE WORD.
   A facility renames "Needs addressing" to whatever it says out loud; the key
   is fixed, so the weight on the page stays true to the meaning. */
body.k9-preview .note-kind {
  font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; padding: 3px 9px; border-radius: 99px;
  border: 1px solid; white-space: nowrap;
}
body.k9-preview .kind-well {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
body.k9-preview .kind-addressing {
  color: var(--red);
  border-color: color-mix(in srgb, var(--red) 55%, transparent);
  background: color-mix(in srgb, var(--red) 12%, transparent);
}
body.k9-preview .kind-noted {
  color: var(--amber);
  border-color: color-mix(in srgb, var(--amber) 55%, transparent);
  background: color-mix(in srgb, var(--amber) 12%, transparent);
}

/* ⛔⛔ TYPE A NAME AND PICK -- NEVER A LIST OF EVERY DOG. 14 Sep 2026.
   Hers, on finding a multi-select of the whole kennel on the incident report:
   "instead of me just typing a name in and picking. We have already discussed
   that that is not appropriate. We have killed that in every design model."
   The rule was written on 31 Aug in her words and is why `pet_search` exists.
   ⭐ And every dog picked carries its own way back off. */
body.k9-preview .dog-picker { position: relative; }
body.k9-preview .dog-chips {
  display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 8px;
}
body.k9-preview .dog-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--pk); border-radius: 99px; padding: 4px 6px 4px 12px;
  font-size: 13px; font-weight: 600;
}
body.k9-preview .chip-off {
  background: none; border: 0; color: var(--pk-3); cursor: pointer;
  font-size: 16px; line-height: 1; padding: 0 5px; border-radius: 99px;
}
body.k9-preview .chip-off:hover { color: var(--red); }
body.k9-preview .dog-typed { width: 100%; max-width: 340px; }
body.k9-preview .typeahead-hits {
  position: absolute; z-index: 20; left: 0; right: 0; max-width: 340px;
  background: var(--surface); border: 1px solid var(--edge);
  border-radius: 8px; overflow: hidden; margin-top: 3px;
  box-shadow: 0 10px 26px rgba(0,0,0,.42);
}
body.k9-preview .typeahead-hit {
  display: block; width: 100%; text-align: left; background: none;
  border: 0; border-bottom: 1px solid var(--edge); color: var(--pk);
  padding: 9px 12px; font: inherit; font-size: 14px; cursor: pointer;
}
body.k9-preview .typeahead-hit:last-child { border-bottom: 0; }
body.k9-preview .typeahead-hit:hover {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
body.k9-preview .typeahead-none {
  padding: 9px 12px; color: var(--pk-3); font-size: 14px; font-style: italic;
}

/* ⛔ VOID -- MARKED, NOT DESTROYED. 14 Sep 2026. It has to read as struck
   out at a glance and still be readable, because the record staying legible
   is the whole difference between this and a delete. */
body.k9-preview .inc-record.inc-void { opacity: .72; }
body.k9-preview .inc-record.inc-void .inc-said,
body.k9-preview .inc-record.inc-void .inc-head h3 {
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--red) 70%, transparent);
}
body.k9-preview .void-flag {
  margin: 0 0 12px;
  padding: 9px 12px;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--red) 55%, transparent);
  background: color-mix(in srgb, var(--red) 12%, transparent);
  color: var(--pk);
  font-size: 14px;
}
body.k9-preview .void-flag .void-by {
  display: block; margin-top: 4px; font-size: 12px; color: var(--pk-3);
  font-family: "IBM Plex Mono", monospace;
}

/* ⭐⭐ A REPORT FOLDS. 14 Sep 2026. Hers, on three cards stacked open: "makes
   it look like it wasn't done." The head has to say enough to pick one out
   without opening it -- the day, the clock, and the opening words.
   ⚠️ FOLD IS THE SCREEN. Closing a report is a different thing entirely. */
body.k9-preview details.inc-record { padding-top: 12px; }
body.k9-preview .inc-fold {
  display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap;
  cursor: pointer; list-style: none; padding: 2px 0;
}
body.k9-preview .inc-fold::-webkit-details-marker { display: none; }
body.k9-preview .inc-fold::before {
  content: "\25B8"; color: var(--pk-3); font-size: 12px;
  transition: transform .12s ease;
}
body.k9-preview details[open] > .inc-fold::before { transform: rotate(90deg); }
body.k9-preview .fold-when {
  font-weight: 700; font-size: 15px; white-space: nowrap;
}
body.k9-preview .fold-said {
  color: var(--pk-3); font-size: 13px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1;
}
body.k9-preview .fold-void {
  font-size: 10px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--red); padding: 2px 8px;
  border: 1px solid color-mix(in srgb, var(--red) 55%, transparent);
  border-radius: 99px;
}
body.k9-preview details[open] > .inc-fold { margin-bottom: 10px; }

/* The writing form, folded away when she came to read rather than to file. */
body.k9-preview details.inc-write > summary {
  cursor: pointer; list-style: none;
}
body.k9-preview details.inc-write > summary::-webkit-details-marker { display: none; }
body.k9-preview details.inc-write > summary h3 {
  display: inline; margin: 0; font-size: 17px;
}
body.k9-preview details.inc-write > summary::before {
  content: "\002B  "; color: var(--accent); font-weight: 700;
}
body.k9-preview details.inc-write[open] > summary { margin-bottom: 12px; }

/* ⭐⭐ CLOSED AND FILED -- a finished record, not a warning. Green, because
   it is the good end state: everybody was told and the report is done. */
body.k9-preview .closed-flag {
  margin: 0 0 12px; padding: 9px 12px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--pk); font-size: 14px;
}
body.k9-preview .closed-reopen { margin-left: 8px; }
body.k9-preview .linkish {
  background: none; border: 0; padding: 0; font: inherit; font-size: 13px;
  color: var(--amber); text-decoration: underline; cursor: pointer;
}
body.k9-preview .inc-close-door > summary { color: var(--amber); }
body.k9-preview .inc-close-door > summary {
  border-color: color-mix(in srgb, var(--amber) 55%, transparent);
}

/* ===========================================================================
   ⭐⭐ WHAT A FAMILY SEES OF AN INCIDENT REPORT. 14 Sep 2026.

   Seen on the practice client within the hour of the panel going live: the
   client view looked unprofessional.

   She was right and the reason was flat: the panel was raw h3/h4/p with no
   class on any of it, so it inherited nothing and "What we did" read as stray
   bold text in a wall. The staff side of the same report was styled. A family
   reading about their dog vomiting cloth got the worse-looking page.

   ⛔ NO NEW VOCABULARY. Everything below dresses the shapes the portal already
   has -- `facts`, `card-body`, `empty`, `note` -- and adds only the frame: the
   date, the standing, and the rule between one report and the next.
   =========================================================================== */
body.k9-preview.my-portal .inc-client.later {
  border-top: 1px solid var(--line); padding-top: 20px; margin-top: 20px;
}
body.k9-preview.my-portal .inc-client-head {
  display: flex; align-items: baseline; gap: 12px;
  flex-wrap: wrap; margin: 0 0 12px;
}
body.k9-preview.my-portal .inc-client-when {
  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 18px; font-weight: 600; letter-spacing: .01em; color: var(--text);
}
/* ⭐ HER TWO WORDS, AND THEY ARE NOT THE SAME WEIGHT OF NEWS. Complete is the
   calm one; still open is the one she wants a client to notice, and amber is
   already this application's word for "somebody has to pick up the phone". */
body.k9-preview.my-portal .inc-client-state {
  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; white-space: nowrap;
  border-radius: 999px; padding: 2px 10px; border: 1px solid;
}
body.k9-preview.my-portal .inc-client-state.done {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
body.k9-preview.my-portal .inc-client-state.still {
  color: var(--amber); border-color: color-mix(in srgb, var(--amber) 50%, transparent);
  background: color-mix(in srgb, var(--amber) 12%, transparent);
}
/* The additions since, against a rail -- the same device the staff side uses
   for a follow-up, so the two sides read as one record seen twice. */
body.k9-preview.my-portal .inc-client-since {
  margin-top: 14px; border-left: 2px solid var(--line-2); padding-left: 14px;
}
body.k9-preview.my-portal .inc-client-since p {
  margin: 0 0 8px; font-size: 14.5px; color: var(--text);
}
body.k9-preview.my-portal .inc-client-since p:last-child { margin-bottom: 0; }
body.k9-preview.my-portal .inc-client-since .when {
  display: inline-block; min-width: 92px;
  font-family: "IBM Plex Mono", monospace; font-size: 12px;
  color: var(--muted); white-space: nowrap;
}
body.k9-preview.my-portal .inc-client-foot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
}
body.k9-preview.my-portal .inc-client-foot .note { margin: 0; }

/* The controls above the paper. `.actions-row` is a flex row in app.css with
   no wrap on it, which puts the sentence explaining the button off the side of
   a phone. A family reads this page on a phone. */
body.k9-preview.my-portal .actions-row {
  flex-wrap: wrap; align-items: center; gap: 10px 14px;
}
body.k9-preview.my-portal .actions-row .cal-resource-meta {
  flex: 1 1 260px; font-size: 13px; line-height: 1.45;
}

/* ===========================================================================
   ⭐⭐ THE TASKS ON A DOG'S SESSION. 15 Sep 2026.

   On the first version -- a bare bulleted list under the session label: it
   looked smashed together, and nothing like the build page.

   ⭐ SO IT BORROWS THE BUILD PAGE'S OWN CLASSES rather than growing a second
   idea of what a task looks like. `tb-task-line`, `tb-task-name` and
   `tb-task-type` are already defined above and are reused untouched; the only
   new rules are the ones the build page has no need for -- the body that opens
   underneath, and a list that is not inside an `ol`.

   ⛔ ONE PARTIAL, TWO SIDES. The same rules dress the client's copy, because
   the client's page reads the same file. Her reason: "when a client calls us
   and says they don't understand, then we can open it to see exactly what
   they're looking at."
   =========================================================================== */
/* ===========================================================================
   ⭐⭐ THE TASKS GET THE WIDTH OF THE TABLE, NOT THE WIDTH OF A COLUMN.
   16 Sep 2026. She asked for a card on 13 Sep and the card shipped inside the
   What column, about 190px wide, so a nine-step write-up ran down a ribbon for
   a screen and a half. The session and its tasks are now two rows reading as
   one: the session row drops its rule, the task row carries it.
   =========================================================================== */
/* ===========================================================================
   ⭐⭐ THE BOOKING CARD FOLDS ON THE TEACHING PAGE. 16 Sep 2026.
   Hers: "You've made the booking screen part of the training package." Shut,
   it is one line that still says what was bought; open, it is what it always
   was.
   =========================================================================== */
/* B7. The overwrite tick sits with the button it changes, not in the prose. */
/* Every [3] [weeks] reads as one control, not two. */
body.k9-preview .lay-every { display: flex; gap: 4px; align-items: center; }
body.k9-preview .lay-every input { width: 3.2rem; }

body.k9-preview .lay-over { margin: 8px 0 0; }
body.k9-preview .lay-over label {
  display: inline-flex; gap: 7px; align-items: baseline;
  font-size: 13px; color: var(--pk-2); cursor: pointer;
}
body.k9-preview .lay-over input { accent-color: var(--accent); }

body.k9-preview details.bought-fold > .bought-sum {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  cursor: pointer; list-style: none;
  font-size: 15px; font-weight: 600; color: var(--pk);
}
body.k9-preview details.bought-fold > .bought-sum::-webkit-details-marker { display: none; }
/* 13 Oct 2026: no arrow -- the line itself opens and shuts the box -- and
   the facts under it are not gray, so the box is not overlooked. */
body.k9-preview details.bought-fold > .bought-sum::marker { content: ""; }
body.k9-preview details.bought-fold > .bought-sum { flex-direction: column; gap: 3px; align-items: flex-start; }
body.k9-preview details.bought-fold > .bought-sum:hover .bought-ask { color: var(--accent); }
body.k9-preview .bought-what { font-size: 13.5px; font-weight: 400; color: var(--pk); }
body.k9-preview .bought-how { font-size: 13.5px; color: var(--pk); margin: 0 0 12px; }
body.k9-preview .bought-how p { margin: 0 0 6px; }
body.k9-preview details.bought-fold[open] > .bought-sum { margin-bottom: 12px; }

body.k9-preview tr.ses-hastasks > td { border-bottom: 0; padding-bottom: 4px; }
body.k9-preview tr.ses-taskrow > td { padding-top: 0; }
body.k9-preview tr.ses-taskrow > td:first-child { padding: 0; }

/* ⛔ THE GROUP STAYS WITH THE NAME. On the build page the gallery is a
   narrow column, so a name that grows to fill it leaves the group a few
   pixels away. Across a whole table that same rule strands the group a
   thousand pixels off. The name stops growing here and they read together. */
body.k9-preview tr.ses-taskrow .tb-task-name { flex: 0 1 auto; }

/* ⛔⛔ THE WRITE-UP GETS THE WIDTH OF THE PAGE ON A COMPUTER. 19 Sep 2026.
   This said `max-width: 74ch`, a reading-measure convention meant for prose.
   Measured on a real card: the row had 1020px, the write-up used 549 of them
   and ran 411px tall -- an eleven-step numbered list drawn as a pole with
   470px of empty space beside it. On a computer the box should be wider, so
   it is not so long.
   ⭐ IT IS ALSO WHAT `TheWriteUpGetsTheWidthOfThePageTests` EXISTS FOR. A
   write-up that could not be a card in a table column got the full row, and
   then the stylesheet handed half of it back. */
body.k9-preview tr.ses-taskrow .ses-task-body { max-width: none; }

body.k9-preview .ses-tasks { margin: 6px 0 0; }
body.k9-preview details.ses-task { border-bottom: 1px solid var(--line); }
body.k9-preview details.ses-task:last-child { border-bottom: 0; }
body.k9-preview details.ses-task > .tb-task-line { padding: 6px 0; }

/* ⭐ The write-up sits against a rail rather than in a box, so a long one
   reads as prose and a short one does not look like an empty card. */
body.k9-preview .ses-task-body {
  background: var(--surface-2); border-left: 2px solid var(--accent);
  border-radius: 0 7px 7px 0;
  margin: 0 0 7px 14px; padding: 10px 14px;
}
body.k9-preview .ses-task-k {
  margin: 0 0 4px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--pk-3);
}
body.k9-preview .ses-task-said {
  margin: 0; font-size: 13.5px; color: var(--pk-2);
}

/* ⭐⭐ THE TWO SPOTS, ON THE ROW. 19 Sep 2026. Out of the fold on purpose --
   see the template. It reads as a line she acts on, not as a card. */
body.k9-preview .hw-pick {
  display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap;
  margin: 0 0 8px 14px; padding: 0 0 2px;
}
body.k9-preview .hw-pick-open { padding: 7px 0 9px; }

/* ⭐⭐ HER TEACHING ORDER. 20 Sep 2026. Up and down sit on the card's own
   line, left of the measure row and indented with it, so a task reads as one
   block: what it is, how it moves, how it is measured. → §BX.3.

   ⛔ QUIET ON PURPOSE. Ordering a week is something she does once; it must
   not compete with the measure, which is the thing she presses with a client
   in front of her. */
body.k9-preview .ses-move {
  display: flex; gap: 8px; align-items: center;
  margin: 2px 0 6px 14px;
}
body.k9-preview .hw-picked { font-weight: 700; color: var(--pk); }
body.k9-preview .ses-task-said.none { color: var(--pk-3); font-style: italic; }

/* ⭐⭐⭐ THE HOMEWORK CARD. 18 Sep 2026. Designed out loud over eight
   mockups, every element corrected by her, and the same card on both sides:
   "instead of the client filling it out, I fill it out."

   The day boxes wrap rather than scroll, because the number of them is
   DERIVED -- a moved appointment makes the row shorter and she wants that
   loss visible: "a card that starts on Thursday shows them that they only
   have four days of training before their next appointment." */
/* ⭐⭐⭐ A WEEK FOLDS. 19 Sep 2026. Every week has to be able to collapse on
   itself, so all you see is week one, week two, week three...

   ⭐⭐ AND SO DOES A SESSION INSIDE ONE. 01 Oct 2026. The session fold has
   worked since 22 Sep, but it was never added to this rule -- and because its
   line is `display: flex`, the browser's own triangle is suppressed too. So
   the line opened and closed and had nothing on it that said so.

   Hers (paraphrased): a little dropdown like the one next to week nine, so a
   session can be closed back up, or left open to compare two of them.

   ⛔ THE TRIANGLE IS THE ONLY THING ADDED. The folded line still holds words
   and nothing pressable, and every control still lives in the body -- her
   22 Sep rule, unchanged. A disclosure marker is not a control on the line;
   it is the line saying what the line already does.

   ⛔ ONE CONVENTION, NOT A SECOND ONE BESIDE IT. This is the week's own
   rule with a selector added, not a copy. The training build has a different
   marker (`.tb-task-line`, glyph swap rather than rotate); the session
   matches the WEEK because that is the one she pointed at. */
body.k9-preview details.cwweek > summary,
body.k9-preview details.ses-fold > summary,
body.k9-preview details.mv-grp > summary,
body.k9-preview details.wk > summary { cursor: pointer; list-style: none; }
body.k9-preview details.cwweek > summary::-webkit-details-marker,
body.k9-preview details.ses-fold > summary::-webkit-details-marker,
body.k9-preview details.mv-grp > summary::-webkit-details-marker,
body.k9-preview details.wk > summary::-webkit-details-marker { display: none; }
body.k9-preview details.cwweek > summary::before,
body.k9-preview details.ses-fold > summary::before,
body.k9-preview details.mv-grp > summary::before,
body.k9-preview details.wk > summary::before {
  content: "\25B8"; display: inline-block; width: 1em;
  color: var(--pk-3); transition: transform .12s ease;
}
body.k9-preview details.cwweek[open] > summary::before,
body.k9-preview details.ses-fold[open] > summary::before,
body.k9-preview details.mv-grp[open] > summary::before,
body.k9-preview details.wk[open] > summary::before { transform: rotate(90deg); }
body.k9-preview details.cwweek > summary:hover,
body.k9-preview details.ses-fold > summary:hover,
body.k9-preview details.mv-grp > summary:hover,
body.k9-preview details.wk > summary:hover { color: var(--accent); }

/* ⚠ The session line aligns on the baseline, not the center like a week
   line, so the marker needs pinning or it drops below the words. */
body.k9-preview details.ses-fold > summary::before {
  align-self: center; flex: 0 0 auto;
}
body.k9-preview .wk-plan-door { margin: 0; }

body.k9-preview .hw-tag {
  margin-left: 8px; padding: 1px 7px; border-radius: 9px;
  font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; white-space: nowrap;
}
body.k9-preview .hw-ratio { background: var(--accent-soft); color: var(--accent); }
body.k9-preview .hw-rate { background: var(--note-bg); color: var(--note); }

body.k9-preview .hw { margin: 10px 0 0; }
body.k9-preview .hw-asks {
  margin: 0 0 7px; font-size: 12.5px; color: var(--pk-2);
}
/* ⭐ THE AIM IS PRINTED AND NEVER ENFORCED: "that way it's right there for
   them to see, but it's not forcing them to do 20." */
body.k9-preview .hw-aim { color: var(--ok); font-weight: 600; }

body.k9-preview .hw-days {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px;
}
body.k9-preview .hw-day {
  flex: 0 0 auto; min-width: 84px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 7px; padding: 6px 8px 7px;
}
/* ⭐ DAY ONE IS THE SESSION ITSELF -- "the first day that they do it is going
   to be during their training session with me." */
body.k9-preview .hw-day.hw-first { border-color: var(--accent); }
body.k9-preview .hw-when {
  display: block; font-size: 11px; font-weight: 700; color: var(--pk);
}
body.k9-preview .hw-withus {
  display: block; font-size: 9.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 3px;
}
body.k9-preview .hw-spacer { display: block; height: 13px; }
body.k9-preview .hw-cell { display: block; margin-top: 3px; }
body.k9-preview .hw-lab {
  display: block; font-size: 9.5px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--pk-3);
}
body.k9-preview .hw-in {
  width: 100%; box-sizing: border-box; padding: 3px 5px;
  border: 1px solid var(--line-2); border-radius: 5px;
  background: var(--surface); color: var(--pk);
  font-size: 13px; font-variant-numeric: tabular-nums; text-align: center;
}
body.k9-preview .hw-pair { display: flex; align-items: center; gap: 2px; }
body.k9-preview .hw-pair span { color: var(--pk-3); font-size: 12px; }

body.k9-preview .hw-note { margin: 0 0 7px; }
body.k9-preview .hw-nin {
  width: 100%; box-sizing: border-box; padding: 5px 8px;
  border: 1px solid var(--line-2); border-radius: 6px;
  background: var(--surface); color: var(--pk); font-size: 13px;
}
body.k9-preview .hw-save {
  margin: 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}

/* ⭐⭐ SETS IN A DAY, her side of a board & train. 21 Sep 2026, section CI.
   Each set is its own box in a row, and Add a set is its own dashed box at
   the end -- so adding one does not read as part of the set above it. */
body.k9-preview .hw-days-sets { display: block; }
/* ⭐⭐⭐ THE DAY SHE WAS WITH THEM IS OPEN; THE DAYS AT HOME FOLD.
   25 Sep 2026, her design. Seven days of set rows laid out flat is the three
   thousand pixels she caught on 19 Sep, so every day but the first is a
   summary until it is pressed. The marker is drawn rather than left to the
   browser, because the default triangle is the gray her eye skips. */
body.k9-preview .hw-setday {
  margin: 0 0 6px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface); padding: 5px 8px 6px;
}
body.k9-preview .hw-setday[open] { padding-bottom: 8px; }
body.k9-preview .hw-setday > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center;
  gap: 6px;
}
body.k9-preview .hw-setday > summary::-webkit-details-marker { display: none; }
body.k9-preview .hw-setday > summary::before {
  content: "\25B8"; color: var(--accent); font-size: 11px;
  transition: transform .12s ease; display: inline-block;
}
body.k9-preview .hw-setday[open] > summary::before { transform: rotate(90deg); }
body.k9-preview .hw-withus.hw-inline { display: inline; margin-left: 6px; }
body.k9-preview .hw-setrow {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: stretch; margin-top: 4px;
}
body.k9-preview .hw-setno {
  display: block; font-size: 11px; font-weight: 700; color: var(--pk);
  margin-bottom: 2px;
}
body.k9-preview .hw-addset {
  flex: 0 0 auto; min-width: 84px; padding: 6px 10px; cursor: pointer;
  border: 1px dashed var(--accent); border-radius: 7px;
  background: transparent; color: var(--accent);
  font-size: 13px; font-weight: 600;
}
/* ⭐ The week so far, set apart from the card's own figure. */
body.k9-preview .hw-week {
  border: 1px solid var(--line-2); border-radius: 6px; padding: 4px 8px;
}
body.k9-preview .hw-weeklab {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--pk-3);
}
/* ⭐ The note box wraps and grows with what she types. */
body.k9-preview .hw-nin-grow {
  display: block; min-height: 4.2em; resize: vertical;
  field-sizing: content; font-family: inherit; line-height: 1.4;
}

/* ⛔⛔ STAFF ONLY, AND BY ABSENCE. The client's view never fetches the
   figures: "that would be on my view so that somebody can't manipulate the
   figures." */
body.k9-preview .hw-figures {
  margin: 0 0 8px; display: flex; align-items: baseline;
  gap: 10px; flex-wrap: wrap;
}
body.k9-preview .hw-big {
  font-size: 19px; font-weight: 700; color: var(--pk);
  font-variant-numeric: tabular-nums;
}
body.k9-preview .hw-small { font-size: 12px; color: var(--pk-2); }
body.k9-preview .hw-days-worked {
  font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--pk-3);
}

body.k9-preview .hw-set { margin: 8px 0; }
body.k9-preview .hw-set > summary {
  cursor: pointer; font-size: 11.5px; color: var(--pk-2);
}
body.k9-preview .hw-setline {
  margin: 6px 0; display: flex; align-items: center;
  gap: 8px; flex-wrap: wrap; font-size: 12.5px; color: var(--pk-2);
}
body.k9-preview .hw-setline .hw-lab { display: inline; }
body.k9-preview .hw-setline input[type="text"] {
  width: 52px; padding: 3px 5px; border: 1px solid var(--line-2);
  border-radius: 5px; background: var(--surface); color: var(--pk);
  font-size: 13px; text-align: center;
}

/* THE THREE DOORS ON THE BUILD PAGE. 16 Sep 2026.
   Sending is the ordinary one and looks it. Clearing is behind a fold and
   its button is the only red thing on the page, because green meaning
   "remove" is a defect she has already caught once. */
/* The three sit apart from building the weeks, with a rule above them, so
   "Add a week" cannot read as part of sending the course to a dog. */
body.k9-preview .tb-send {
  margin-top: 26px; border-top: 1px solid var(--line);
  padding-top: 0;
}
body.k9-preview .tb-send .tb-row { margin-top: 10px; }
body.k9-preview .tb-send label,
body.k9-preview .tb-clear label { white-space: nowrap; }
body.k9-preview .tb-send input[type="date"],
body.k9-preview .tb-send input[type="time"] { flex: 0 0 auto; }
body.k9-preview .tb-clear > summary { cursor: pointer; }
body.k9-preview .tb-danger {
  background: transparent; border: 1px solid var(--red);
  color: var(--red); border-radius: 6px; padding: 8px 15px;
  font: inherit; font-weight: 600;
}
body.k9-preview .tb-danger:hover { background: rgba(224, 131, 117, 0.12); }
body.k9-preview .tb-retire .tb-row { align-items: baseline; }
body.k9-preview .tb-retire .sub { margin: 0; }

/* WHAT A SESSION IS CALLED, in the row's own Save. 16 Sep 2026. Wide enough
   for a real name and not so wide it pushes the date off the row. */
body.k9-preview .ses-name { min-width: 14rem; flex: 1 1 14rem; }

/* ⭐⭐⭐ WEEKS HOLD SESSIONS, ON THE DOG'S OWN PAGE. 17 Sep 2026.

   A one-week board and train can hold fourteen sessions inside that week. The
   container needs to read as a
   container -- one block, its name on top, what happens inside it below --
   or the page is a flat list again with indentation pretending otherwise. */
body.k9-preview .wk {
  border: 1px solid var(--line); border-radius: 8px;
  margin: 0 0 14px; background: var(--card-2, transparent);
}
body.k9-preview .wk-on { border-color: var(--accent); }
body.k9-preview .wk-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--line);
}
body.k9-preview .wk-no { font-size: 15px; font-weight: 600; color: var(--pk); }
body.k9-preview .wk-count { font-size: 12px; color: var(--pk-3); }
body.k9-preview .wk-right { margin-left: auto; }
body.k9-preview .wk-plan { padding: 10px 14px; border-bottom: 1px dashed var(--line); }

/* ⭐ EVERY SESSION INSIDE A WEEK FOLDS. 22 Sep 2026. The folded line reads
   what the session is, when, where and with whom; only the line opens it. */
body.k9-preview .ses-folds { padding: 8px 10px 2px; }
body.k9-preview .ses-fold {
  border: 1px solid var(--line); border-radius: 6px; margin: 0 0 8px;
}
body.k9-preview .ses-fold[open] { border-color: var(--accent); }
body.k9-preview .ses-fold-head {
  display: flex; align-items: baseline; gap: 6px 14px; flex-wrap: wrap;
  padding: 8px 12px; cursor: pointer;
}
body.k9-preview .ses-fold-name { font-weight: 600; color: var(--pk); }
/* Q169: the folded line is the only place a session's date, time, place and
   trainer are said, so it reads at full strength. */
body.k9-preview .ses-fold-when { font-size: 13.5px; color: var(--pk); font-weight: 500; }
body.k9-preview .ses-fold > .table-scroll { border-top: 1px solid var(--line); }
body.k9-preview .ses-copy { padding: 0; margin: 0; }
body.k9-preview .wk .table-scroll { padding: 0 6px; }
body.k9-preview tr.wk-namerow > td { border-bottom: 1px solid var(--line); }
body.k9-preview .wk-add {
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 0;
}
body.k9-preview .tb-weeksessions {
  margin: 6px 0 0; padding-left: 20px; color: var(--pk-3); font-size: 13px;
}

/* ⭐ THE NUMBER, TYPEABLE. 17 Sep 2026. Narrow -- it holds 1 to 99, not a
   sentence -- and it sits first because that is where it reads on the row. */
body.k9-preview .ses-no { width: 4.5rem; flex: 0 0 auto; }

/* The controls on a Training Today row. 18 Sep 2026.

   The session was visible and nothing could be done to it -- there was no way
   to check the dog in. Three things live in a row now -- who
   is teaching it, the time she arrived, and the two buttons -- and they have
   to sit on one line without turning the card into a form. */
body.k9-preview .inline-form { display: inline-flex; align-items: center; gap: 4px; }
body.k9-preview .inline-form input[type="text"] {
  width: 4.6em; padding: 3px 5px; font-size: 13px; text-align: center;
}
body.k9-preview .trainer-pick select { font-size: 13px; padding: 2px 4px; }
body.k9-preview button.small { font-size: 12.5px; padding: 3px 9px; }
body.k9-preview button.ghost {
  background: none; border: 1px solid var(--line); color: var(--pk-3);
}
body.k9-preview button.ghost:hover { color: var(--accent); border-color: var(--accent); }


/* Quick check-in's one question, right under the bar. 21 Sep 2026. */
body.k9-preview .qc-ask {
  border: 2px solid var(--accent); border-radius: 8px;
  padding: 12px 14px; margin-top: 12px;
}
body.k9-preview .qc-ask-q { margin: 0 0 10px; font-size: 16px; font-weight: 600; }
body.k9-preview .qc-ask-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

/* ⭐⭐ THE CUSTOMERS LIST, IN THE NEW LOOK. 22 Sep 2026.
   Cards about a third of their old size -- six or seven across a laptop -- with
   a square photo, the name, the dogs and the phone; or one customer to a row. */
body.k9-preview .cl-switch { margin: 0; }
body.k9-preview .cl-search { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
body.k9-preview .cl-search input[type="text"] { width: 280px; max-width: 100%; }
body.k9-preview .cl-arch { display: inline-flex; align-items: center; gap: 6px; color: var(--pk-2); font-size: 13px; }
body.k9-preview .cl-az { margin: 10px 0 0; flex-wrap: wrap; }
body.k9-preview .cl-az .view-pill { min-width: 26px; text-align: center; padding-left: 6px; padding-right: 6px; }
body.k9-preview .cl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px; margin-top: 14px;
}
body.k9-preview .cl-card {
  display: block; background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; overflow: hidden; color: inherit; text-decoration: none;
}
body.k9-preview .cl-card:hover { border-color: var(--accent); }
body.k9-preview .cl-only-dog:hover { border-color: var(--line); }
body.k9-preview .cl-only-dog .cl-name { color: inherit; }
body.k9-preview .cl-photo { aspect-ratio: 1 / 1; overflow: hidden; background: var(--surface-2); }
body.k9-preview .cl-strip { display: flex; height: 100%; transition: transform .12s ease-out; }
body.k9-preview .cl-slot { flex: 0 0 100%; height: 100%; }
body.k9-preview .cl-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
body.k9-preview .cl-body { padding: 7px 9px 9px; }
body.k9-preview .cl-name { font-weight: 600; color: var(--accent); font-size: 14px; }
body.k9-preview .cl-card .cl-name { font-size: 13px; }
body.k9-preview .cl-k {
  font-size: 9.5px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--pk-3); margin-top: 5px;
}
body.k9-preview .cl-v { font-size: 12.5px; }
body.k9-preview .cl-pill {
  display: inline-block; border: 1px solid var(--line-2); border-radius: 10px;
  padding: 0 7px; margin: 0 3px 3px 0; font-size: 12px;
}
body.k9-preview .cl-dogs { display: flex; flex-wrap: wrap; gap: 4px 12px; max-width: 440px; }
body.k9-preview .cl-dog { display: inline-flex; align-items: center; gap: 6px; }
body.k9-preview .cl-face {
  width: 26px; height: 26px; border-radius: 50%; object-fit: cover;
  background: var(--surface-2); border: 1px solid var(--line-2); display: inline-block;
}
body.k9-preview .cl-mail { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { body.k9-preview .cl-strip { transition: none; } }

/* ⭐⭐ NEW CLIENT, IN THE NEW LOOK. 22 Sep 2026. Same two steps and the same
   boxes; the old page's layout classes, dressed in this palette. */
body.k9-preview .nc-steps { margin: 8px 0 0; }
body.k9-preview .nc-steps .view-pill { cursor: default; }
body.k9-preview .nc .form-grid,
body.k9-preview .nc .staged-fields {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px 14px; margin-top: 6px;
}
body.k9-preview .nc .staged-fields + .staged-fields { margin-top: 14px; }
body.k9-preview .nc .field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
body.k9-preview .nc .field.full { grid-column: 1 / -1; }
body.k9-preview .nc .field > label {
  font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--pk-3); font-weight: 500;
}
body.k9-preview .nc .field input,
body.k9-preview .nc .field select,
body.k9-preview .nc .field textarea { width: 100%; }
body.k9-preview .nc .cal-resource-meta { color: var(--pk-3); font-size: 13px; margin: 0 0 12px; }
body.k9-preview .nc .field .cal-resource-meta { font-size: 12px; margin: 2px 0 0; }
body.k9-preview .nc .staged-row {
  border: 1px solid var(--line); background: var(--ground);
  padding: 12px 14px; margin: 0 0 12px;
}
body.k9-preview .nc .staged-head { font-weight: 600; color: var(--accent); margin-bottom: 8px; }
body.k9-preview .nc .q-answers { display: flex; gap: 14px; flex-wrap: wrap; color: var(--pk-2); }
body.k9-preview .nc .q-pick { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; }
body.k9-preview .nc .actions-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* ⏱️ 22 Sep 2026, seen live: the boxes line up along the top, and an answer's
   words stay on one line with its button. */
body.k9-preview .nc .form-grid,
body.k9-preview .nc .staged-fields { align-items: start; }
body.k9-preview .nc .field select.q-answer { width: auto; min-width: 12rem; max-width: 100%; }

/* ⭐ EVERY PROGRAM RUNNING, in Bookings. 22 Sep 2026. The count reads first,
   because what she wants at a glance is how many are running and on how many
   dogs. */
body.k9-preview .pr-head {
  font-family: "Barlow Semi Condensed", sans-serif; font-weight: 600;
  font-size: 13px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--pk-2); margin: 0 0 6px;
}
body.k9-preview .pr-count { margin: 0 0 12px; font-size: 15px; color: var(--pk-2); }
body.k9-preview .pr-count b { color: var(--accent); font-size: 20px; }
body.k9-preview .pr-who { color: var(--accent); font-weight: 600; text-decoration: none; }
body.k9-preview .pr-dog { display: block; color: var(--pk); margin-top: 2px; text-decoration: none; }
body.k9-preview .pr-dog:hover { color: var(--accent); }

/* ⭐ AN INVOICE'S PAGE. 22 Sep 2026. The state reads beside the number, and
   the three figures sit under the table with the balance first. */
body.k9-preview .inv-state { margin: 0; }
body.k9-preview .pchip.paid { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
body.k9-preview .pchip.owed { background: var(--amber-soft); border-color: var(--amber); color: var(--amber); }
body.k9-preview .pchip.off { background: var(--lock-soft); border-color: transparent; color: var(--lock); }
body.k9-preview .inv-doors { margin: 14px 0 0; border: 1px solid var(--line); border-top: 1px solid var(--line); background: var(--surface); }
body.k9-preview .inv-doors form.inline { display: inline-flex; }
body.k9-preview .inv-doors button.door { background: transparent; border: 0; cursor: pointer; font: inherit; font-size: 14.5px; }
body.k9-preview .door.danger { color: var(--red); }
body.k9-preview .inv-figures {
  display: flex; gap: 30px; flex-wrap: wrap; margin: 12px 0 0;
  padding-top: 12px; border-top: 1px solid var(--line);
}
body.k9-preview .inv-figures .k {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--pk-3);
}
body.k9-preview .inv-figures .v { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
body.k9-preview .inv-figures .v.owed { color: var(--amber); }
body.k9-preview tr.inv-total td { border-top: 1px solid var(--line-2); }

/* ⭐ THE GALLERY IS THE OUTER FOLD. 29 Sep 2026. Ten galleries are ten
   lines; two can be open at once. */
.tb-gallery { border-top: 1px solid var(--line); }
.tb-gallery:first-child { border-top: 0; }
.tb-gallery > summary {
  list-style: none; cursor: pointer; padding: 10px 2px;
  display: flex; align-items: baseline; gap: 8px;
}
.tb-gallery > summary::-webkit-details-marker { display: none; }
.tb-gallery > summary::before {
  content: "\25b8"; font-size: 10px; opacity: .55; width: 9px;
}
.tb-gallery[open] > summary::before { content: "\25be"; }
.tb-gallery-name { font-weight: 700; font-size: 14.5px; }
.tb-gallery-n {
  margin-left: auto; font-size: 11.5px; opacity: .55;
  font-variant-numeric: tabular-nums;
}
.tb-gallery-body {
  padding-left: 13px; margin-left: 4px;
  border-left: 2px solid var(--accent-soft, rgba(127, 192, 162, .3));
}

/* The bar on the gallery build page: which body of material she is in. */
.tb-gallerybar .card-body {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
}
.tb-gallerybar-label {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  opacity: .6;
}
.tb-gallerychip {
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 13px;
  font-size: 13px; text-decoration: none;
}
.tb-gallerychip .n { font-size: 11px; opacity: .7; margin-left: 4px; }
.tb-gallerychip.on {
  background: var(--btn-bg, var(--brand-fill)); border-color: transparent;
  color: var(--on-fill); font-weight: 600;
}

/* ⛔ THE GROUPS ON THE WHOLE LIST FOLD. Asked for and never built. */
.tb-grouphead { cursor: pointer; }
.tb-grouphead::before {
  content: "\25be"; font-size: 10px; opacity: .55; margin-right: 6px;
}
.tb-grouprow.shut .tb-grouphead::before { content: "\25b8"; }

/* ⭐ HER GRID: a behavior on the left, its tasks across. 29 Sep 2026. */
.tb-gridwrap { overflow-x: auto; }
.tb-grid { border-collapse: collapse; width: 100%; }
.tb-grid th, .tb-grid td { border: 1px solid var(--line); padding: 0; }
.tb-grid thead th {
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  opacity: .6; padding: 5px 8px; text-align: left; font-weight: 600;
}
.tb-grid tbody th { min-width: 10rem; position: sticky; left: 0;
  background: var(--surface); z-index: 1; }
.tb-grid thead th:first-child { position: sticky; left: 0;
  background: var(--surface); z-index: 1; }
.tb-grid tbody td { min-width: 10rem; }
.tb-grid input {
  border: 0; background: transparent; width: 100%; padding: 6px 8px;
  font: inherit; font-size: 13px; color: inherit; border-radius: 0;
}
.tb-grid input:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.tb-grid tbody th input { font-weight: 600; }

/* ---------------------------------------------------------------------------
   ⭐⭐⭐ MOVING AND COPYING BETWEEN GALLERIES. 30 Sep 2026.

   Two galleries up at once, because her rule for this screen is that it has to
   be easily identifiable that something is being moved. Everything here reads
   her own tokens, so it holds in both themes rather than only the one it was
   drawn in.
   --------------------------------------------------------------------------- */
.mv-head { padding: 14px 16px; margin-bottom: 14px; }
.mv-pickers {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 0;
}
.mv-pickers .lab {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--pk-3);
}
.mv-pickers select {
  background: var(--ground); color: var(--pk);
  border: 1px solid var(--line-2); padding: 7px 10px; font: inherit;
  font-size: 14px;
}
.mv-arrow { color: var(--accent); font-size: 18px; padding: 0 2px; }

/* ⛔ A SWITCH, NEVER A HELD-DOWN KEY. The only difference between these two is
   whether the original survives, and that can never depend on something a
   person cannot see. */
.mv-seg { display: inline-flex; border: 1px solid var(--line-2); }
.mv-seg button {
  background: var(--ground); color: var(--pk-2); border: 0;
  padding: 7px 16px; font: inherit; font-size: 14px; cursor: pointer;
}
.mv-seg button + button { border-left: 1px solid var(--line-2); }
.mv-seg button.on {
  background: var(--btn-bg, var(--brand-fill)); color: var(--on-fill); font-weight: 600;
}
.mv-note { margin: 11px 0 0; font-size: 13px; color: var(--pk-2); }
.mv-note b { color: var(--pk); }

.mv-banner {
  background: var(--accent-soft); border: 1px solid var(--accent);
  padding: 9px 14px; font-size: 13.5px; margin-bottom: 12px;
  display: flex; justify-content: space-between; align-items: center;
}
/* ⛔⛔ THE BANNER NEVER CHANGES THE LAYOUT, AND THAT IS NOT A STYLE CHOICE.
   30 Sep 2026, third push on one feature. It used to appear when a drag
   started, which pushed the whole page down UNDER THE POINTER, and Chrome
   cancels a drag the moment the ground moves beneath it: dragstart fired and
   dragend followed instantly, with no drag and no dragover between them. The
   drag was never broken -- it was being aborted by this element arriving.

   So it holds its space always and only its visibility changes. Nothing
   reflows, and the gesture survives.

   ⚠️ A render that reads the HTML cannot catch this. The markup was correct
   every time. */
.mv-banner { visibility: hidden; }
.mv-banner.on { visibility: visible; }
/* ⛔ AND ITS HEIGHT CANNOT DEPEND ON ITS CONTENTS EITHER. Holding its place
   was not enough: empty it collapsed, and filling it with the sentence at
   dragstart grew it by three pixels, which moved the row under the pointer
   just as surely. Measured, not assumed -- the page still shifted after the
   first fix. A fixed height and one line that cannot wrap. */
.mv-banner {
  min-height: 40px; box-sizing: border-box; align-items: center;
}
.mv-banner > span:first-child {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mv-banner b { color: var(--accent); }
.mv-banner .mv-esc { color: var(--pk-3); font-size: 12px; }

.mv-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 860px) { .mv-cols { grid-template-columns: 1fr; } }

.mv-col { background: var(--surface); border: 1px solid var(--line); display: flex; flex-direction: column; }
/* ⭐ EACH SIDE SCROLLS ON ITS OWN. 8 Oct 2026: a behavior near the top of one
   gallery and near the bottom of the other can be on screen together. */
.mv-colbody { overflow: auto; max-height: calc(100vh - 260px); min-height: 360px; }
@media (max-width: 860px) { .mv-colbody { max-height: none; min-height: 0; } }
.mv-coltools { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 14px; border-bottom: 1px solid var(--line); }
.mv-cols > .mv-col { min-width: 0; }
.mv-coltools .mv-find { flex: 1; min-width: 0; }
.mv-coltools button {
  font: inherit; font-size: 12.5px; padding: 4px 10px; cursor: pointer;
  background: var(--surface-2); color: var(--pk); border: 1px solid var(--line-2);
}
.mv-colhead {
  padding: 10px 14px; border-bottom: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: baseline;
}
.mv-colhead b { font-size: 15px; }
.mv-colhead .n { font-size: 12px; color: var(--pk-3); }
.mv-colhead .tag {
  font-size: 11px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--accent);
}

.mv-grp { border-bottom: 1px solid var(--line); }
.mv-grp:last-child { border-bottom: 0; }
.mv-grphead {
  padding: 8px 14px; font-size: 13px; color: var(--pk);
  background: var(--surface-2);
  display: flex; align-items: center; gap: 8px;
}
.mv-grphead .mv-name { flex: 1 1 8em; min-width: 0; font-weight: 600; }
.mv-grphead { flex-wrap: wrap; }
.mv-depth-2 > .mv-grphead { padding-left: 28px; background: var(--surface); }
.mv-depth-2 > .mv-grphead .mv-name { font-weight: 500; }
.mv-depth-3 > .mv-grphead { padding-left: 42px; background: var(--surface); }
.mv-depth-4 > .mv-grphead { padding-left: 56px; background: var(--surface); }
.mv-depth-2 > .mv-t { padding-left: 46px; }
.mv-depth-3 > .mv-t { padding-left: 60px; }
.mv-depth-4 > .mv-t { padding-left: 74px; }
.mv-grphead .mv-both {
  font-size: 11px; color: var(--accent); border: 1px solid var(--accent);
  border-radius: 999px; padding: 0 7px; white-space: nowrap;
}
.mv-t .mv-tname { flex: 1; }
.mv-t .mv-tboth {
  font-size: 11px; color: var(--pk-3); border: 1px solid var(--line-2);
  border-radius: 999px; padding: 0 7px; white-space: nowrap;
}
/* ⭐ what she has highlighted, and where a drop will land: color and an
   inset line only, so nothing moves under the pointer */
.mv-t { cursor: pointer; user-select: none; -webkit-user-select: none; }
.mv-t:hover { background: var(--surface-2); }
.mv-t.mv-sel { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.mv-t.mv-above { box-shadow: inset 0 2px 0 var(--accent); }
.mv-t.mv-fresh { animation: mv-fresh 1.8s ease-out; }
@keyframes mv-fresh { from { background: var(--amber-soft); } to { background: transparent; } }
@media (prefers-reduced-motion: reduce) { .mv-t.mv-fresh { animation: none; background: var(--amber-soft); } }
.mv-toast {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 40;
  background: var(--rail); color: var(--rail-ink); padding: 10px 14px;
  display: flex; gap: 12px; align-items: center; font-size: 13.5px; max-width: 90vw;
  visibility: hidden;
}
.mv-toast.on { visibility: visible; }
.mv-toast button {
  font: inherit; font-size: 12.5px; background: transparent; color: var(--rail-ink);
  border: 1px solid var(--rail-line); padding: 3px 10px; cursor: pointer;
}
.mv-toast button[hidden] { display: none; }
.mv-grphead .c { color: var(--pk-3); font-size: 12px; white-space: nowrap; }
/* ⭐ THE SAME NAME ON BOTH SIDES IS THE WHOLE POINT OF TWO COLUMNS. */
.mv-grp.match > .mv-grphead { box-shadow: inset 3px 0 0 var(--accent); }

.mv-t {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 14px; font-size: 14px; border-top: 1px solid var(--line);
}
/* ⛔ NO SECOND GRIP. `.tb-grip` already exists and already works; the move
   page uses it rather than defining its own. 30 Sep 2026. */
.mv-sub { border-top: 1px solid var(--line); }
.mv-subhead {
  padding: 6px 14px 6px 24px; font-size: 12.5px; color: var(--pk-2);
  letter-spacing: .02em;
}
.mv-sub .mv-t { padding-left: 30px; }
.mv-none { padding: 9px 14px; font-size: 13px; color: var(--pk-3); margin: 0; }
.mv-foot { margin-top: 12px; font-size: 13px; color: var(--pk-2); }

/* While something is in the air, say where it can land -- the same shape the
   build page uses, so the two pages behave alike. `.tb-lit` is the existing
   class and is reused rather than reinvented. */
body.k9-preview.mv-dragging [data-drop-type],
body.k9-preview.mv-dragging [data-drop-gallery] {
  outline: 1px dashed var(--line-2); outline-offset: -1px;
}
body.k9-preview.mv-dragging .mv-col.to { background: var(--accent-soft); }
/* the way between two galleries, on the bar that names them */
.tb-gallerymove {
  margin-left: auto; font-size: 13px; text-decoration: none;
  border: 1px solid var(--line-2); border-radius: 999px; padding: 4px 13px;
  color: var(--pk);
}
.tb-gallerymove:hover { border-color: var(--accent); color: var(--accent); }

/* ---------------------------------------------------------------------------
   ⭐⭐⭐ HER MATERIAL IN BLOCKS, AND THE WRITE-UP UNDER IT. 30 Sep 2026.

   Measured before it was changed: 361 rows, 3.3 screens, `In courses` taking
   475 of 1106 pixels to print a dash. Her reading: they all go down the page,
   so she cannot look at them at the same time.
   --------------------------------------------------------------------------- */
.tb-material { column-count: 3; column-gap: 16px; margin-top: 4px; }
@media (max-width: 1100px) { .tb-material { column-count: 2; } }
@media (max-width: 700px)  { .tb-material { column-count: 1; } }

.tb-block {
  break-inside: avoid; page-break-inside: avoid;
  background: var(--surface); border: 1px solid var(--line); margin: 0 0 12px;
}
.tb-blockhead {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px; padding: 7px 11px;
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  cursor: pointer; list-style: none;
}
.tb-blockhead::-webkit-details-marker { display: none; }
/* ⭐ a caret, so the block says it folds rather than leaving her to find out */
.tb-blockhead b::before {
  content: "\25be"; font-size: 9px; opacity: .55; margin-right: 6px;
  display: inline-block; transition: transform .12s;
}
.tb-block:not([open]) .tb-blockhead b::before { transform: rotate(-90deg); }
.tb-block:not([open]) .tb-blockhead { border-bottom: 0; }
.tb-blockhead:hover { background: var(--line); }
.tb-blockhead b { font-size: 13.5px; font-weight: 600; }
.tb-blockhead .c { font-size: 11.5px; color: var(--pk-3); white-space: nowrap; }

.tb-taskrow {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 11px; font-size: 13px; border-top: 1px solid var(--line);
}
.tb-block > .tb-taskrow:first-child { border-top: 0; }
.tb-taskrow:hover { background: var(--surface-2); }
/* ⭐ Where a dragged task will land on Build your gallery: a line above or
   below the row it is over. 4 Oct 2026. */
.tb-taskrow.tb-drop-above { box-shadow: inset 0 2px 0 var(--accent); background: var(--accent-soft); }
.tb-taskrow.tb-drop-below { box-shadow: inset 0 -2px 0 var(--accent); background: var(--accent-soft); }
.tb-taskrow .tb-grip { cursor: grab; }
/* A behavior hidden by a chip, and the Show them all again chip when nothing
   is picked. The blocks set their own display, so hidden has to be said. */
.tb-material details.tb-type[hidden] { display: none; }
body.k9-preview .tb-countchip[hidden] { display: none; }
.tb-taskrowname { flex: 1; }
.tb-taskrow .tb-tick { margin: 0; flex: 0 0 auto; }
.tb-taskrow .tb-written {
  font-size: 10.5px; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 999px; padding: 0 5px;
}
.tb-taskrow .tb-open {
  font-size: 11px; color: var(--pk-3); background: none; border: 0;
  cursor: pointer; padding: 0 2px;
}
.tb-taskrow .tb-open:hover { color: var(--accent); }
/* ⭐ the one whose write-up is open says so, so she never loses her place */
.tb-taskrow.on { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }

/* ⭐ THE WRITE-UP, FULL WIDTH UNDER THE COLUMNS. Hers, shown both ways first:
   "A, so I have more room to read what I'm typing." */
.tb-cardpane {
  background: var(--surface); border: 1px solid var(--accent); margin-top: 8px;
}
.tb-cardpane[hidden] { display: none; }
.tb-cardpanehead {
  display: flex; justify-content: space-between; align-items: center;
  padding: 9px 13px; border-bottom: 1px solid var(--line);
}
.tb-cardpanehead b { font-size: 14px; }
.tb-cardclose {
  background: none; border: 0; color: var(--pk-3); font: inherit;
  font-size: 12px; cursor: pointer;
}
.tb-cardclose:hover { color: var(--accent); }
.tb-cardpanebody { padding: 13px; }
.tb-cardstore[hidden] { display: none; }
/* ⭐ how many courses name a task: a marker, not a column. It only draws when
   there is a number, which is what makes it affordable. */
.tb-taskrow .tb-incourses {
  font-size: 10.5px; color: var(--pk-2); border: 1px solid var(--line-2);
  border-radius: 999px; padding: 0 5px; cursor: help;
}
/* ⭐ the six tools, as a chip row above her material. They carry no label:
   "those six chips up there are fine... we'll just teach them that that's
   where it is." 30 Sep 2026. */
.tb-tools { display: flex; gap: 8px; flex-wrap: wrap; margin: 14px 0 16px; }
.tb-tool {
  border: 1px solid var(--line-2); border-radius: 999px; padding: 5px 14px;
  font: inherit; font-size: 13px; color: var(--pk);
  background: var(--surface); cursor: pointer;
}
.tb-tool:hover { border-color: var(--accent); color: var(--accent); }
.tb-toolbench { margin-top: 22px; }
/* ⛔ ONE CONTROL FOR THE SPREADSHEET. 30 Sep 2026. The browser's own file box
   is tiny next to a button, so she pressed the button first with nothing
   chosen. The label IS the control now; the input still carries the file.

   ⚠️ NOT `display:none` and NOT `visibility:hidden`, because both take the
   input out of the tab order and the label alone cannot be tabbed to -- the
   control would be unreachable from a keyboard. It is clipped instead, and
   the LABEL takes the focus ring when the input has focus, so the thing that
   lights up is the thing a person can see. */
.tb-sheetfile {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.tb-sheetpick { cursor: pointer; }
/* A label dressed as a button reads on the button, not as a field label. */
body.k9-preview label.btn:not(.secondary) { color: var(--on-fill); }
.tb-sheetfile:focus-visible + .tb-sheetpick,
.tb-sheetfile:focus + .tb-sheetpick {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* the second press only goes away once the script that replaces it is running */
body.tb-onecontrol .tb-sheetgo { display: none; }
/* ⭐ open all / close all, beside the page's own name. Hers, 30 Sep 2026. */
.tb-allfolds { margin: 6px 0 0; display: flex; gap: 8px; }
.tb-allfolds[hidden] { display: none; }
.tb-foldall {
  border: 1px solid var(--line-2); border-radius: 999px; padding: 3px 12px;
  font: inherit; font-size: 12.5px; color: var(--pk-2);
  background: var(--surface); cursor: pointer;
}
.tb-foldall:hover { border-color: var(--accent); color: var(--accent); }

/*  ⭐ ONE QUESTION, TWO ANSWERS. 30 Sep 2026. The radios sit on the shape the
    class build page already uses; this only gives the question room to breathe
    and keeps the two answers on one line on a narrow screen. */
.tb-typeway { margin: 14px 0 6px; }
.tb-typeway .tb-inline { margin-right: 18px; }

/*  ⛔⛔ HER BLOCKS, ON THE TREE. 30 Sep 2026.

    The gallery page's material became the nested behavior tree, and the tree
    partial carries the BUILD PAGE'S rail classes -- so her three-column blocks
    came out as rail rows. Hers, seeing it: "And you change the look."

    ⭐ The layout she approved is unchanged: a top-level behavior is a card, the
    cards flow in three columns, about eleven visible at once. What is new is
    only what was missing -- the behaviors inside one, indented within its card
    rather than given cards of their own, because they belong to it. */
.tb-material > details.tb-type {
  break-inside: avoid; page-break-inside: avoid;
  background: var(--surface); border: 1px solid var(--line); margin: 0 0 12px;
  display: block; padding: 0;
}
.tb-material details.tb-type > .tb-type-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px; padding: 7px 11px;
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  cursor: pointer; list-style: none;
}
.tb-material .tb-type-head::-webkit-details-marker { display: none; }
/*  ⭐ the same caret her blocks have, so a fold says it folds */
.tb-material .tb-type-head .tb-type-name::before {
  content: "\25be"; font-size: 9px; opacity: .55; margin-right: 6px;
  display: inline-block; transition: transform .12s;
}
.tb-material details.tb-type:not([open]) > .tb-type-head .tb-type-name::before {
  transform: rotate(-90deg);
}
.tb-material details.tb-type:not([open]) > .tb-type-head { border-bottom: 0; }
.tb-material .tb-type-head:hover { background: var(--line); }
.tb-material .tb-type-head .tb-type-name { font-size: 13.5px; font-weight: 600; }
.tb-material .tb-type-head .tb-count {
  font-size: 11.5px; color: var(--pk-3); white-space: nowrap;
}
/*  ⭐ A behavior inside another is indented within its parent's card, not given
    a card of its own -- the nesting is the point and a second border would
    make it read as a sibling. */
.tb-material details.tb-type details.tb-type {
  margin: 0 0 0 11px; border-left: 1px solid var(--line); background: none;
}
.tb-material details.tb-type details.tb-type > .tb-type-head {
  background: none; padding: 5px 11px; border-bottom: 0;
}
.tb-material details.tb-type details.tb-type > .tb-type-head .tb-type-name {
  font-size: 12.5px; font-weight: 500;
}
/*  ⭐ THE SHAPING SITS QUIET UNTIL SHE WANTS IT. Rename, move, reorder, switch
    off and delete are one fold inside the behavior's own fold, so the page
    still reads as her material rather than as a control panel. */
.tb-material .tb-typebits > summary {
  font-size: 11px; color: var(--pk-3); padding: 3px 11px; cursor: pointer;
  list-style: none;
}
.tb-material .tb-typebits > summary::-webkit-details-marker { display: none; }
.tb-material .tb-typebits > summary:hover { color: var(--accent); }
.tb-material .tb-typebits[open] { padding-bottom: 6px; }
.tb-material .tb-directly {
  font-size: 11px; color: var(--pk-3); margin: 6px 0 0; padding: 0 11px;
}

/* ===========================================================================
   ⭐ THE PAGES THAT MOVED ONTO THIS STYLESHEET TOGETHER, 4 Oct 2026. Hers
   (paraphrased; verbatim in 10-THE-CONVERSATION.md): only the stylesheet
   changes. These rules are what those pages needed beyond the shell: the
   room grid's booking colors in both themes.
   =========================================================================== */
body.k9-preview .cal-pill { color: var(--pk); }
body.k9-preview .cal-boarding { background: var(--cal-boarding); }
body.k9-preview .cal-board_train { background: var(--cal-bt); }
body.k9-preview .cal-day_academy { background: var(--cal-day); }
body.k9-preview .cal-grooming { background: var(--cal-groom); }
body.k9-preview .cal-training { background: var(--cal-train); }
body.k9-preview .cal-over { background: var(--cal-over); }
body.k9-preview .cal-over-label { color: var(--cal-over-ink); }
body.k9-preview .cal-legend .cal-over-swatch {
  background: var(--cal-over); border-color: var(--cal-over-line);
}
/* A long program name in a dropdown must not push the form past a phone's
   edge: grid items shrink to the column. */
body.k9-preview .form-grid > * { min-width: 0; }
body.k9-preview .form-grid select,
body.k9-preview .form-grid input { max-width: 100%; }

/* ==========================================================================
   Q164 + Q165, 07 Oct 2026. THE WEEK NARROW, THE GALLERY WIDE.
   Hers, on the mockup: the week thinner, the gallery wider, "because that's
   where we build... We need to see more of the gallery." Behaviors sit in
   columns, each opening and closing on its own, and the week card takes a
   dropped task on its list or on any of its sessions.
   ========================================================================== */
body.k9-preview .tb-main { flex: 0 1 400px; }
body.k9-preview .tb-side { flex: 1 1 560px; }
@media (min-width: 1000px) {
  body.k9-preview .tb-cols { flex-wrap: nowrap; }
}
body.k9-preview .tb-side .tb-gallery-body { columns: 4 200px; column-gap: 12px; }
/* Rows are dragged, not opened, so they carry no arrow; and the empty
   paragraph a form leaves behind (a form cannot sit in a <p>) takes no room. */
body.k9-preview .tb-side .tb-task-line::before,
body.k9-preview .tb-side details[open] > .tb-task-line::before { content: none; }
body.k9-preview .tb-side .tb-tree p:empty { display: none; margin: 0; }
body.k9-preview.tb-js .tb-side .tb-task-line { cursor: grab; }
body.k9-preview .tb-side .tb-gallery-body > details.tb-type.tb-depth-1 {
  break-inside: avoid; border: 1px solid var(--line); border-radius: 7px;
  padding: 5px 8px; margin: 0 0 8px; background: var(--surface);
}
body.k9-preview .tb-side .tb-task-line { padding-top: 1px; padding-bottom: 1px; margin: 0; font-size: 12.5px; }
/* The Add form is a sibling of its line (a form cannot sit inside a <p>). */
body.k9-preview.tb-js .tb-side .tb-tree form.tb-inline { display: none; }
body.k9-preview .tb-side .tb-task-line.tb-landed-on .tb-task-name::after {
  content: " \2713"; color: var(--accent);
}

body.k9-preview .tb-weekpanel .tb-wp-head { font-size: 15px; margin: 0 0 2px; }
body.k9-preview .tb-weekpanel .tb-wp-sub { font-weight: 400; font-size: 12px; opacity: .7; }
body.k9-preview .tb-weekpanel .tb-dropzone {
  border: 1px dashed var(--line-2); border-radius: 8px; padding: 8px 10px; margin: 8px 0;
}
body.k9-preview .tb-weekpanel .tb-dropzone.tb-lit {
  outline: 2px dashed var(--accent); outline-offset: 2px;
}
body.k9-preview .tb-weekpanel .tb-wp-on { border-style: solid; border-color: var(--accent); }
body.k9-preview .tb-weekpanel .tb-wp-list { margin: 4px 0 0; padding-left: 0; list-style: none; }
body.k9-preview .tb-weekpanel .tb-wp-list li {
  display: flex; gap: 6px; align-items: baseline; padding: 2px 0;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
body.k9-preview .tb-weekpanel .tb-wp-list li .tb-task-type { font-size: 11px; opacity: .65; margin-left: auto; }
body.k9-preview .tb-weekpanel .tb-wp-list li form { margin-left: auto; }
body.k9-preview .tb-weekpanel .tb-wp-list li .tb-task-type + form { margin-left: 6px; }
body.k9-preview .tb-weekpanel .tb-wp-shead { display: flex; gap: 8px; align-items: baseline; }
body.k9-preview .tb-weekpanel .tb-wp-shead .tb-count { margin-left: auto; }
body.k9-preview .tb-weekpanel .tb-wp-sessions { margin: 14px 0 0; font-size: 14px; }
body.k9-preview .tb-weekpanel .tb-howmany { width: 4.5em; }
body.k9-preview .tb-weekpanel .tb-wp-said { font-size: 12.5px; color: var(--accent); min-height: 1em; margin: 6px 0 0; }
/* The week's list, shut once the week has sessions (12 Oct 2026). */
body.k9-preview .tb-weekpanel .tb-wp-fold {
  border: 1px dashed var(--line-2); border-radius: 8px; padding: 8px 10px; margin: 8px 0 4px;
}
body.k9-preview .tb-weekpanel .tb-wp-foldhead {
  display: flex; gap: 8px; align-items: baseline; cursor: pointer; list-style: none;
}
body.k9-preview .tb-weekpanel .tb-wp-foldhead::-webkit-details-marker { display: none; }
body.k9-preview .tb-weekpanel .tb-wp-foldhead::before {
  content: "\25B8"; color: var(--pk-3); font-size: 12px; flex: 0 0 auto;
}
body.k9-preview .tb-weekpanel .tb-wp-fold[open] > .tb-wp-foldhead::before { content: "\25BE"; }
body.k9-preview .tb-weekpanel .tb-wp-foldhead .tb-count { margin-left: auto; }
body.k9-preview .tb-weekpanel .tb-wp-foldhead.tb-lit { outline: 2px dashed var(--accent); outline-offset: 2px; }
body.k9-preview .tb-weekpanel .tb-wp-fold > .tb-dropzone { margin-top: 4px; }
body.k9-preview .tb-weekpanel .tb-wp-hint { margin: 0 0 6px; }
body.k9-preview .tb-jsonly { display: none; }
body.k9-preview.tb-js .tb-jsonly { display: block; }
body.k9-preview.tb-js .tb-nojs { display: none; }
/* ⭐ Q165: the build page is the one place that uses the whole screen -- the
   gallery is what she builds from, and more of it on screen is less
   scrolling. Every other page keeps its reading width. */
body.k9-preview .container:has(> .tb-cols),
body.k9-preview .container:has(.tb-cols) { max-width: 1680px; }

/* ==========================================================================
   07 Oct 2026. ONE LINE PER TASK ON HER SIDE OF A PROGRAM.
   Hers: the measure on the task's own line, Take it off at the end of it, Up
   and Down gone for dragging, and the name a color that says it opens. Each
   task took four lines; nine of them ran a screen.
   ========================================================================== */
body.k9-preview .ses-row { position: relative; border-bottom: 1px solid var(--line); }
body.k9-preview .ses-row:last-child { border-bottom: 0; }
body.k9-preview .ses-row > details.ses-task { border-bottom: 0; }
body.k9-preview .ses-row-staff .tb-task-name { color: var(--accent); font-weight: 600; }
body.k9-preview .ses-grip {
  cursor: grab; color: var(--pk-3); letter-spacing: -2px; padding: 0 4px 0 0;
  user-select: none;
}
body.k9-preview .ses-row.ses-carried { opacity: .5; }
body.k9-preview .ses-row.ses-unsaved { outline: 2px solid var(--red); }
body.k9-preview.ses-js .ses-row-staff > .ses-updown { display: none; }
/* A fill is the facility's color, never the word color (it is lightened in
   dark mode and would leave pale letters on a pale button). */
body.k9-preview .hw-pick .btn.hw-on {
  background: var(--rail); color: var(--rail-ink); border-color: var(--rail);
}
@media (min-width: 900px) {
  /* The measure and Take it off sit on the summary's line, at its right. */
  body.k9-preview .ses-row-staff > details.ses-task > .tb-task-line { padding-right: 560px; }
  body.k9-preview .ses-row-staff > .hw-pick {
    position: absolute; top: 3px; right: 96px; margin: 0; padding: 0;
    flex-wrap: nowrap;
  }
  body.k9-preview .ses-row-staff > .ses-off {
    position: absolute; top: 3px; right: 0; margin: 0;
  }
}
/* The program page is wide enough to hold that line. */
body.k9-preview .container:has(.ses-row-staff) { max-width: 1440px; }
body.k9-preview .ses-row-staff .tb-task-line .tb-task-name { flex: 0 1 auto; }

/* ⭐⭐ Q169, 07 Oct 2026. THE TOP OF A WEEK AND THE TOP OF A SESSION.
   Everything that adds to or changes a week sits in one row at its top; a
   session opens on one row of buttons, and its date, time, place and trainer
   are changed in a small card behind one of them. */
body.k9-preview .wk-tools {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 10px 14px 6px;
}
body.k9-preview .wk-tools > form { display: inline-flex; gap: 6px; align-items: center; margin: 0; flex-wrap: wrap; }
body.k9-preview .wk-add .wk-add-name { width: 13em; }
body.k9-preview .wk-add input[name="at_time"] { width: 5em; }
body.k9-preview .wk-tools-gap { width: 1px; align-self: stretch; background: var(--line); }
body.k9-preview .wk-tools > form.wk-tools-end { margin-left: auto; }
body.k9-preview .wk-tools-said { padding: 0 14px; margin: 0 0 6px; }
body.k9-preview .wk-change,
body.k9-preview .ses-change {
  border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px;
}
body.k9-preview .wk-change { margin: 2px 14px 8px; }
body.k9-preview .ses-change { margin: 2px 12px 8px; }
body.k9-preview .wk-change form,
body.k9-preview .ses-change form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
body.k9-preview .ses-change .small { display: block; margin-top: 6px; }
body.k9-preview .ses-bar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 8px 12px 6px; border-top: 1px solid var(--line);
}
body.k9-preview .ses-bar > form { margin: 0; }
/* A press comes back to `#session-N` on this row; leave room above it so the
   folded line -- the one place the date and place are said -- is in view. */
body.k9-preview .ses-bar { scroll-margin-top: 56px; }
body.k9-preview .ses-bar > form.ses-bar-end { margin-left: auto; }
body.k9-preview .ses-taskbox { padding: 0 12px 6px; }
body.k9-preview .ses-taskbox .ses-task-body { max-width: none; }
body.k9-preview .ses-taskbox .tb-task-name { flex: 0 1 auto; }
/* Without a script the buttons are not drawn and every card stays open. */
body.k9-preview .wk-jsonly { display: none; }
body.k9-preview.wk-js .wk-jsonly { display: inline-block; }
body.k9-preview.wk-js [data-change-card]:not(.is-open) { display: none; }
body.k9-preview [data-change-open].hw-on {
  background: var(--rail); color: var(--rail-ink); border-color: var(--rail);
}

/* ⭐⭐⭐ FLUENCY AND CRITERION / NOTES ON EVERY SET. Q172, 07 Oct 2026, drawn
   to the mockup she approved: each set is a full-width box -- its numbers,
   then a dashed rule, the six dimensions of fluency to tick (one or more),
   and the Criterion / Notes box -- with + Add a set full width under them. */
/* Each set is drawn at the width of a card on the mockup and they sit side
   by side where the page is wide enough, so four sets is not four screens. */
body.k9-preview .hw-setrow > .hw-setbox { flex: 1 1 360px; max-width: 480px; }
body.k9-preview .hw-setrow > .hw-addset { flex: 1 1 100%; padding: 9px 10px; }
body.k9-preview .hw-setbox .hw-in { text-align: left; padding: 5px 8px; }
body.k9-preview .hw-setbox .hw-pair .hw-in { text-align: center; }
body.k9-preview .hw-fl {
  margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line-2);
}
body.k9-preview .hw-notesbox .hw-fl { margin-top: 0; padding-top: 0; border-top: 0; }
body.k9-preview .hw-chips {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 8px;
}
body.k9-preview .hw-chip { position: relative; display: inline-flex; }
body.k9-preview .hw-chip input {
  position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0;
}
body.k9-preview .hw-chip span {
  display: inline-block; padding: 3px 9px; cursor: pointer;
  border: 1px solid var(--line-2); border-radius: 6px;
  font-size: 12.5px; color: var(--accent); background: transparent;
}
/* A fill is the facility's color, never the word color -- the same rule the
   measure buttons follow. */
body.k9-preview .hw-chip input:checked + span {
  background: var(--rail); color: var(--rail-ink); border-color: var(--rail);
}
body.k9-preview .hw-chip input:focus-visible + span {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
body.k9-preview .hw-crit .hw-nin-grow { min-height: 2.4em; }
/* Notes only has one day, the session, so it is not a fold. */
body.k9-preview .hw-setday-one > .hw-when { margin: 0; }
/* A Notes only task on the family's card: a note for each day (12 Oct 2026). */
body.k9-preview .hw-noteday { border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; margin: 0 0 8px; }
body.k9-preview .hw-noteday > .hw-when { margin: 0 0 4px; }
body.k9-preview .hw-noteday .hw-note { margin: 0; }
body.k9-preview .hw-noteday { display: block; }
body.k9-preview .hw-noteday .hw-nin { display: block; width: 100%; box-sizing: border-box; font-size: 16px; }
/* ... and on her side, what the family wrote. */
body.k9-preview .hw-theirs { margin: 8px 0 0; }
body.k9-preview .hw-theirs-day { margin: 2px 0; font-size: 14px; }
body.k9-preview .hw-theirs-day .hw-when { margin-right: 6px; }

/*  The Change door on a schedule row (13 Oct 2026). */
body.k9-preview td a.edit {
  margin-left: 6px; font-size: 12px; white-space: nowrap;
}

/*  Emails logged by hand on the client page (13 Oct 2026). */
body.k9-preview .logged-emails { display: flex; flex-direction: column; gap: 4px; }
body.k9-preview details.logged-email { border: 1px solid var(--line); border-radius: 6px; padding: 6px 10px; }
body.k9-preview details.logged-email.reply { margin-left: 22px; }
body.k9-preview details.logged-email > summary { cursor: pointer; font-size: 13.5px; }

/* The dog's Gallery (Q214, 15 Oct 2026): every picture but the main one, as
   thumbnails that wrap on a phone, each with its two doors under it. */
.gallery-pics { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0 4px; }
.gallery-pic { margin: 0; width: 150px; max-width: 100%; }
.gallery-pic img { width: 150px; height: 150px; object-fit: cover; border-radius: 4px; display: block; }
.gallery-pic figcaption { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; font-size: .8rem; }
.gallery-pic details.ask summary { cursor: pointer; color: var(--muted); }
.gallery-pic details.ask p { margin: 4px 0; }
