.custom-card-shadow{
  box-shadow: 0px 0px 10px 1px #aaaaaa;
}

.custom-icon-fs-30-va-middle{
  font-size:30px; vertical-align: middle;
}

.pac-item{
  background: white;
}

/* Reusable section header — a light tint of the sidebar slate (#1F2937),
   loaded after volt.css so it wins over the default .card-header background. */
.section-header{
  background-color: rgba(31, 41, 55, 0.06);
  color: #1F2937;
  font-weight: 600;
}

/* ── Button palette ───────────────────────────────────────────────────────────
   Two solid button roles, and each one MEANS something everywhere:

     .btn-primary    the action this screen exists for       light slate #C7CBD9
     .btn-secondary  a supporting or way-out action          soft sand  #F7DEB6

   Overridden here rather than in scss/volt/_variables.scss because $primary and
   $secondary also drive links, badges, the sidebar and every *-primary utility;
   recompiling volt.css to restyle two buttons would repaint the whole app. This
   file is loaded after volt.css (includes/site-css-bootstrap-5.3.3.html), so
   these win.

   Both the CSS custom properties AND the plain declarations are restated: volt
   emits a late `.btn-primary:hover { background-color: … }` rule that sets the
   colour directly, which no --bs-btn-hover-bg can reach.

   Direction of travel matters. The old values were mid-tone (#9DA4BE / #F0BC74),
   so volt's generated hover states got LIGHTER. These are light, so hover and
   active go DARKER — a light button that lightens on hover reads as disabling
   itself under the cursor.

   Text stays #1F2937 (the sidebar slate): 8.1:1 on primary, 10.3:1 on secondary. */
.btn-primary {
  --bs-btn-color: #1F2937;
  --bs-btn-bg: #C7CBD9;
  --bs-btn-border-color: #C7CBD9;
  --bs-btn-hover-color: #1F2937;
  --bs-btn-hover-bg: #B4BACB;
  --bs-btn-hover-border-color: #B4BACB;
  --bs-btn-focus-shadow-rgb: 157, 164, 190;
  --bs-btn-active-color: #1F2937;
  --bs-btn-active-bg: #A9B0C3;
  --bs-btn-active-border-color: #A9B0C3;
  --bs-btn-disabled-color: #6B7280;
  --bs-btn-disabled-bg: #E2E4EB;
  --bs-btn-disabled-border-color: #E2E4EB;
}
.btn-primary:hover {
  background-color: #B4BACB;
  border-color: #B4BACB;
  color: #1F2937;
}

/* Secondary is the pair to primary, not a rival to it. It used to be the full
   amber accent (#F0BC74); once every `btn-outline-secondary` on the site became
   a SOLID secondary button, that accent turned rows of Back/Cancel controls into
   the loudest thing on the page. Tinted down so a supporting action reads as
   supporting — the same reason includes/notify.html gives for keeping its Cancel
   button off btn-secondary entirely. */
.btn-secondary {
  --bs-btn-color: #1F2937;
  --bs-btn-bg: #F7DEB6;
  --bs-btn-border-color: #F7DEB6;
  --bs-btn-hover-color: #1F2937;
  --bs-btn-hover-bg: #F0D09B;
  --bs-btn-hover-border-color: #F0D09B;
  --bs-btn-focus-shadow-rgb: 240, 188, 116;
  --bs-btn-active-color: #1F2937;
  --bs-btn-active-bg: #ECC88C;
  --bs-btn-active-border-color: #ECC88C;
  --bs-btn-disabled-color: #6B7280;
  --bs-btn-disabled-bg: #FBF0DE;
  --bs-btn-disabled-border-color: #FBF0DE;
}
.btn-secondary:hover {
  background-color: #F0D09B;
  border-color: #F0D09B;
  color: #1F2937;
}

/* btn-outline-primary is deliberately NOT re-tinted. An outline button paints its
   colour as TEXT on white; #C7CBD9 as body text is roughly 1.6:1 and unreadable.
   It keeps the original mid-slate, which is the same hue family and legible. */

/* ------------------------------------------------------------------------- */
/* The two-box price control (schedule/includes/price_control.html)           */
/*                                                                           */
/* Three screens render it and one file styles it, for the same reason one    */
/* file defines it: a money input that looks different on the screen that     */
/* sets the standard and the screen that makes an exception to it reads as    */
/* two different fields.                                                      */
/* ------------------------------------------------------------------------- */

/* The amount takes the room; the "per" select takes what it needs. Without a
   basis Bootstrap gives every input-group child `width: 1%; flex: 1 1 auto`,
   which splits a 4-character amount and a 10-character select evenly and leaves
   the money looking like the afterthought. */
.price-control .price-amount { flex: 1 1 auto; min-width: 6rem; }
.price-control .price-basis  { flex: 0 0 auto; width: auto; min-width: 8.5rem; }

/* The symbol is a fact about the practice's currency, not an editable part of
   the amount, so it sits outside the box and reads as chrome. */
.price-control .input-group-text { background-color: #F3F4F6; color: #4a4a55; }

/* The help affordance moved out of this file. `.help-pop` was one screen's "?" and
   the app grew four more shapes beside it; there is now a single component —
   assets/css/help-tip.css + assets/js/help-tip.js — which BUILDS its own trigger,
   so no call site can style one differently. UI.md § "Help text — one popup, one
   shape". The rule that put it here still holds: a control that explains rather
   than acts is not one of the screen's actions and wears no .btn. */

/* ------------------------------------------------------------------------- */
/* PUBLIC ALPHA                                                              */
/*                                                                           */
/* Three surfaces say Practiceful is in public alpha: the badge beside the    */
/* logo, the banner under the navbar on the marketing home page, and the      */
/* notice on the register page. They live here rather than in per-page        */
/* <style> blocks for the reason this file exists at all — an override in     */
/* one template is one edit away from two screens describing the same         */
/* release stage differently.                                                 */
/* ------------------------------------------------------------------------- */

/* ── The brand lockup: wordmark + stage badge, as ONE indivisible unit ──────
   The badge rides INSIDE the brand anchor so it stays glued to the logo at
   every breakpoint and is read as part of the name — "Practiceful alpha",
   which is exactly what the product is called right now.

   `min-width: max-content` is load-bearing, and the bug it fixes is worth
   writing down because nothing about it is visible in the markup.

   The anchor is a flex ITEM of `.navbar > .container`, and its next sibling
   `.navbar-collapse` carries `w-100` — it asks that flex row for the container's
   entire 1140px. The row cannot grant that AND the brand, so it shrinks the
   brand; and the anchor's automatic minimum size is no defence, because its only
   in-flow child is an `<img>` with `max-width: 100%`, whose min-content
   contribution resolves to nothing. The anchor was handed 240.6px for 291px of
   content. Two things followed, both of which shipped:

     - the badge, being `white-space: nowrap`, was laid out PAST the anchor's
       right edge, where `.navbar-collapse` — later in DOM order, so painted
       later — covered it. `elementFromPoint` at the badge's centre returned the
       "Features" nav link. The badge was in the DOM, styled, `is_visible()`
       true, and unreadable.
     - the wordmark itself was squeezed to 240.6px when its SVG is 1658x262 and
       so wants 253.2px at the 40px height the navbar draws it. The logo was
       being served distorted on every marketing page.

   Stating the minimum directly is the fix that survives: it says "this lockup is
   never given less room than it needs", which is true whatever the sibling asks
   for. `flex-shrink: 0` does NOT work here — measured, it changes nothing,
   because the anchor's flex BASE size was already collapsing to the image.
   Pinned by qa/specs/test_TA-091_alpha_chrome_geometry.py. */
.brand-lockup {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
}
/* Below `lg` the `.navbar-collapse` is `display: none`, so nothing is competing
   for the row and the lockup already sizes to its content. Claiming max-content
   there instead makes a NEW bug: `min-width` beats `max-width` when the two
   conflict, so the lockup could no longer fit itself into a narrow bar. The app
   shell's own `d-lg-none` navbar (`px-4`, so 48px of padding) overflowed a 320px
   viewport by 7px — a defect that predates this rule, since 253px of wordmark
   plus a 44px badge never fitted 272px, and one this scoping also removes. */
@media (min-width: 992px) {
    .brand-lockup { min-width: max-content; }
}
/* When the lockup DOES have to give way, the wordmark yields and the badge never
   does: "Practiceful alpha" losing a few pixels of logo still reads correctly,
   and losing the badge means the page stops saying what it is. */
.brand-lockup > img { min-width: 0; }
.brand-lockup .brand-alpha-badge { flex-shrink: 0; }

.brand-alpha-badge {
    display: inline-block;
    margin-left: .4rem;
    padding: .15rem .4rem;
    border-radius: .25rem;
    background: #F7DEB6;          /* the sand used for supporting chrome */
    color: #4a4a55;
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: .08em;
    line-height: 1;
    text-transform: lowercase;
}

/* A full-bleed strip, tinted rather than alarming: this is a state of the
   product, not an error. It is a NOTICE, not a dismissible banner — a visitor
   who dismisses it and returns a week later meets a page selling them a product
   they cannot buy. */
.alpha-notice {
    background: #F3F4F6;
    border-bottom: 1px solid #e2e4ea;
    padding: .75rem 0;
    font-size: .875rem;
}

/* `.navbar-main` is `position: absolute`, so whatever comes first in flow is
   drawn UNDERNEATH it. The notice is now that first element on every page which
   extends layouts/landing.html, so it carries the clearance — as a class rather
   than the inline style it used to be, because it is no longer one page's
   problem. index.html's pillar section drops to 2rem when the notice is present
   and keeps the full 6.5rem when the programme is off and it is first again. */
.alpha-notice--clears-navbar { padding-top: 6.5rem; }

/* ONE CENTRED SENTENCE, and the pill and the link are WORDS IN IT — this is
   int_lms's shape and it is copied deliberately, so that the two products
   describe the same release stage in the same words in the same place.

   Two shapes came before it and each failed differently. `d-flex flex-wrap
   justify-content-center` let the message take its CONTENT's width, so with
   HEADLINE + LEAD + GATE (~45 words) in it the row wrapped every time —
   measured 239px tall at 1440px, the pill centred on a row of its own and the
   request link marooned on a third. The three-column grid that replaced it
   (`auto` for the pill, `1fr` for the message, `auto` for the link — written as
   words because `test_the_three_column_grid_is_GONE_from_the_stylesheet` reads
   this file as text) fixed the wrapping and introduced the opposite fault: it
   pins the pill to the left edge and the link to the right one, so at 1440px
   the sentence ended at x=624 and its own call to action sat at x=1129. Five
   hundred and five pixels of nothing between a request and the control that
   grants it, with the message left of centre. int_lms measured 771px.

   A centred flex row would not fix it either: the link is still its own item,
   separated by a gap and free to wrap onto a line of its own while the line
   above is half empty. Inside the paragraph the link is a word — it follows the
   last one by a single space at every width and nothing can separate them. The
   GOV.UK phase banner is the same construction for the same reason.

   No max-width and no stacking breakpoint: centred text is never wider than its
   own content, and the copy is two short lines. Below 576px it simply wraps. */
.alpha-notice-text {
    color: #1b2559;
    line-height: 1.35;
    text-align: center;
}
.alpha-notice-tag {
    /* `inline-block`, so it rides in the sentence's own flow on the text
       baseline instead of occupying a cell of its own. */
    display: inline-block;
    white-space: nowrap;
    margin-inline-end: .15rem;
    padding: .25rem .45rem;
    border-radius: .25rem;
    background: #F7DEB6;
    color: #4a4a55;
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: .08em;
    line-height: 1;
    text-transform: lowercase;
}
/* The strip's ONLY action, and it inherited the theme's muted link colour:
   rgb(157,164,190) on this strip's rgb(243,244,246) is 2.2:1, against a WCAG AA
   minimum of 4.5:1. It was legible as a grey smudge. The body ink is the same
   colour the message beside it uses (12.9:1), and the underline is what keeps it
   reading as a link rather than as bolded prose — load-bearing now that it sits
   INSIDE the sentence in that same ink, where colour alone would be the only
   thing marking it as the control (WCAG 1.4.1). */
.alpha-notice-cta {
    white-space: nowrap;
    font-weight: 600;
    color: #1b2559;
    text-decoration: underline;
}
.alpha-notice-cta:hover,
.alpha-notice-cta:focus { color: #000; }

/* The same notice inside a card, on the register page. No full-bleed band:
   it sits above a form, not under a navbar. */
.alpha-notice-inline {
    border: 1px solid #e2e4ea;
    border-left: 4px solid #F7DEB6;
    border-radius: .35rem;
    background: #F9FAFB;
    padding: .85rem 1rem;
    font-size: .875rem;
    color: #1b2559;
}

/* ── Dashboard: today's briefing ─────────────────────────────────────────────
   One neutral treatment for every callout. These were btn-danger / btn-warning
   / btn-info, which made an overdue invoice shout louder than the client
   arriving at 9am — a ranking the dashboard has no business asserting. The
   colour is now constant and the ICON carries the distinction, in tones muted
   far enough that four of them side by side still read as one row.
   Pinned by tests/test_dashboard_briefing.py. */
/* The card the whole section sits in. This yellow was `.briefing-count`'s and
   was on screen at all times, which made it decoration: a colour that is always
   present describes nothing. It now says exactly one thing — THE BRIEFING IS
   SHOWING — in exactly two places, this card and the bell holding it open. The
   panel is a Bootstrap collapse, so when it is folded the card is display:none
   and there is no yellow on the row at all. */
.briefing-card {
    background: #F7DEB6;
}

.briefing-pill {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem .75rem;
    /* White on sand, warm-bordered. It was #F5F6F8 on a WHITE card, where a pale
       grey read as a chip; on the sand it would read as a smudge. The chip has
       to be lighter than what it sits on or it stops looking like a chip. */
    border: 1px solid #E4D3B0;
    border-radius: 2rem;
    background: #ffffff;
    color: #4a4a55;
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    transition: background-color .15s ease-in-out, border-color .15s ease-in-out;
}
/* Darker on hover, never lighter — a pale control that lightens reads as
   disabling itself. Same rule as the button roles in UI.md. */
.briefing-pill:hover,
.briefing-pill:focus {
    background: #F0EADF;
    border-color: #D3BE93;
    color: #2b2b33;
    text-decoration: none;
}
.briefing-pill:focus-visible {
    outline: 2px solid #4A90D9;
    outline-offset: 2px;
}

.briefing-icon { font-size: .875rem; line-height: 1; }
/* Muted on purpose: enough hue to tell the four rows apart at a glance, not
   enough to reintroduce the severity ranking the pills just removed.

   Darkened 2026-08-16. Only the HSL lightness moved — hue is held to within a
   degree and saturation to within 0.004 — so the row is told apart by exactly
   the hues it was before, and all four now sit at the SAME contrast. That is
   what makes this a fix rather than a change to the "four side by side read as
   one row" decision above: weight was already uneven (3.14 / 3.01 / 2.51 /
   2.91), and solving each hue to one ratio is the only way to clear 3:1 without
   making darkness mean something the pills deliberately stopped saying.

   Solved against the HOVER ground, not the resting one. The reported defect was
   pipeline (2.51:1) and at-risk (2.91:1) on the white pill, but `:hover`/`:focus`
   darkens that pill to #F0EADF, and against it ALL FOUR failed — schedule 2.62,
   billing 2.52, pipeline 2.10, at-risk 2.43. A state is not exempt from WCAG
   1.4.11, and focus is the state a keyboard user reads the row in. Now 3.16:1
   hovered and 3.78:1 at rest. Measured, not estimated; pinned by
   tests/test_briefing_icon_contrast.py and by TA-092 in a real browser. */
.briefing-icon-schedule   { color: #6A85AB; }
.briefing-icon-billing    { color: #A97676; }
.briefing-icon-pipeline   { color: #988056; }
.briefing-icon-at-risk    { color: #867EA7; }
/* Darker than its four siblings because it is the one icon that does NOT sit on
   a white pill — it sits directly on the sand card, where #8FA9A0 measured
   1.93:1 against WCAG's 3:1 for non-text content. Measured, not estimated. */
.briefing-icon-onboarding { color: #5E7A70; }

.briefing-name { font-size: .8125rem; font-weight: 600; }

/* The muted status text — "· invited", "and 4 more". This was `.text-gray-500`,
   rgb(107,114,128): 4.83:1 on the white card the section used to have and
   **3.70:1 on the sand**, so moving the background quietly took it below AA.
   Measured at 5.39:1 here, still visibly secondary to the names it qualifies
   (7.89:1).

   Its own class rather than an override of the utility, for two reasons.
   `.text-gray-500` is declared `!important` twice in volt.css, so a scoped
   override loses outright and looks like it worked — and it is a GLOBAL
   utility, so winning would have repainted muted text across the product to
   suit one card. */
.briefing-muted { color: #5F584A; }

/* The bell. Quiet by default — it is a way back to something the user has
   already seen, not a call to action. */
.btn-briefing-toggle {
    position: relative;
    border: 1px solid #e2e4ea;
    background: #ffffff;
    color: #66686e;
    border-radius: 50rem;
    padding: .4rem .7rem;
    transition: background-color .15s ease-in-out, border-color .15s ease-in-out,
                color .15s ease-in-out;
}
.btn-briefing-toggle:hover,
.btn-briefing-toggle:focus {
    background: #F5F6F8;
    border-color: #cfd3dc;
    color: #2b2b33;
}
/* AFTER the :hover rule on purpose. Both selectors weigh 0,2,0, so source order
   is what decides — placed above, the hover state would repaint the bell grey
   mid-briefing and break the one thing this colour is here to say. */
.btn-briefing-toggle[aria-expanded="true"] {
    background: #F7DEB6;
    border-color: #E4C68C;
    color: #4a4a55;
}
.briefing-count {
    display: inline-block;
    min-width: 1.15rem;
    margin-left: .35rem;
    padding: 0 .3rem;
    border-radius: 50rem;
    /* Neutral at rest. It held the yellow itself until 2026-08-16, so a folded
       briefing and an open one wore the same colour — and the count is the one
       thing that must keep reading while the briefing is CLOSED, which is when
       the yellow is deliberately absent. */
    background: #E8EAEE;
    color: #4a4a55;
    font-size: .6875rem;
    font-weight: 700;
    line-height: 1.15rem;
}
/* On the sand bell the badge inverts, so the count stays a distinct chip
   instead of dissolving into the button it sits on. */
.btn-briefing-toggle[aria-expanded="true"] .briefing-count {
    background: #ffffff;
}

/* The trail: the card's own edge, shrinking into the bell.
   The briefing folds itself away three seconds after the page loads — the one
   place in this app where doing nothing changes what is on screen — and until
   now nothing said where it went. Geometry is set from viewport rects by
   dashboard_briefing.js, so top/left/width/height are the animated properties
   and a scale() is deliberately not used: scaling a 2px border distorts it into
   a smear, and this has to read as an outline.
   `pointer-events: none` because it flies across live controls. */
[data-briefing-trail] {
    position: fixed;
    /* Above the fixed navbar (1030), BELOW the modal backdrop (1050). It is
       transient and pointer-transparent, but a decorative outline drawn over an
       open dialog is still an outline drawn over an open dialog. */
    z-index: 1040;
    background: transparent;
    border: 2px solid #E4C68C;
    border-radius: .75rem;
    pointer-events: none;
    opacity: .9;
    transition: top .45s cubic-bezier(.4, 0, .2, 1),
                left .45s cubic-bezier(.4, 0, .2, 1),
                width .45s cubic-bezier(.4, 0, .2, 1),
                height .45s cubic-bezier(.4, 0, .2, 1),
                border-radius .45s cubic-bezier(.4, 0, .2, 1),
                opacity .45s ease-in;
}

/* ── Service pictures and booking cards (UX finding 6.4) ────────────────────
   In custom.css and not the SCSS, for the reason the button roles are here:
   volt.css is loaded first and recompiling it to add a few rules repaints the
   whole app. */

/* The edit form's preview, and the booking card's fallback, are the SAME chip —
   a service's own colour carrying its initial. Deliberately not a grey
   placeholder: "no picture" is a state this product designs for, and a grey box
   reads as a failed load. */
.service-image-preview,
.bk-service-card-img,
.bk-service-card-chip {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.service-image-preview {
  width: 96px;
  height: 72px;
  flex: 0 0 auto;
  background: #f8f9fa;
}

.service-image-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.service-image-chip,
.bk-service-card-chip {
  width: 100%;
  height: 100%;
  color: #fff;
  font-weight: 600;
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The AI candidate thumbnails. A real radio sits inside each label, so keyboard
   selection and grouping are the browser's rather than ours. */
.service-ai-choice {
  display: block;
  border: 2px solid transparent;
  border-radius: .5rem;
  overflow: hidden;
  cursor: pointer;
  line-height: 0;
}

.service-ai-choice img {
  width: 104px;
  height: 104px;
  object-fit: cover;
}

.service-ai-choice.is-chosen {
  border-color: #6c757d;
}

/* Focus must be visible on a control whose checked state is the only other
   signal — the radio itself is visually-hidden. */
.service-ai-choice:focus-within {
  outline: 2px solid #495057;
  outline-offset: 2px;
}

/* ── The booking card grid ───────────────────────────────────────────────── */
.bk-service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .75rem;
}

.bk-service-card-body {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 2px solid #e9ecef;
  border-radius: .5rem;
  overflow: hidden;
  cursor: pointer;
  background: #fff;
}

.bk-service-card-img,
.bk-service-card-chip {
  width: 100%;
  height: 116px;
  flex: 0 0 auto;
  object-fit: cover;
}

.bk-service-card-name {
  font-weight: 600;
  padding: .625rem .75rem 0;
}

.bk-service-card-meta {
  font-size: .8125rem;
  color: #6c757d;
  padding: 0 .75rem;
}

/* Clamped to three lines. A card grid's value is that the eye can compare
   several at once, which a description of unbounded length destroys. */
.bk-service-card-desc {
  font-size: .8125rem;
  color: #495057;
  padding: .375rem .75rem .75rem;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bk-service-card.is-chosen .bk-service-card-body {
  border-color: #6c757d;
  box-shadow: 0 0 0 .125rem rgba(108, 117, 125, .25);
}

/* The radio is visually-hidden, so :focus-within is the ONLY thing that can
   show a keyboard user where they are. */
.bk-service-card:focus-within .bk-service-card-body {
  outline: 2px solid #495057;
  outline-offset: 2px;
}

/* ── The two-column booking screen (item 12, 2026-08-16) ────────────────────
   Services are a LIST and no longer a grid. The grid was right when the picker
   was the whole width of the page; in a five-column card it produced 220px
   cards two abreast with a 116px picture on top of three lines of clamped
   description, which is a lot of vertical space spent on the one decision the
   client can make fastest. A row — small picture, name, price, description —
   reads like a menu, which is what it is. */
.bk-service-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 30rem;
  overflow-y: auto;
}

/* The card is now the whole clickable row PLUS the slot the options panel moves
   into, so the border lives on the card and not on the label. */
.bk-service-list .bk-service-card-body {
  flex-direction: row;
  align-items: stretch;
  gap: .75rem;
  padding: 0;
}

.bk-service-list .bk-service-card-img,
.bk-service-list .bk-service-card-chip {
  width: 84px;
  height: auto;
  min-height: 84px;
  flex: 0 0 84px;
  font-size: 1.25rem;
}

.bk-service-card-text {
  display: flex;
  flex-direction: column;
  padding: .5rem .75rem .5rem 0;
  min-width: 0;
}

.bk-service-list .bk-service-card-name,
.bk-service-list .bk-service-card-meta,
.bk-service-list .bk-service-card-desc {
  padding: 0;
}

.bk-service-list .bk-service-card-desc {
  -webkit-line-clamp: 2;
  margin-top: .25rem;
}

/* The chosen service is marked twice — border AND a tinted ground. One signal
   is enough for a grid where the cards sit apart; in a tight list the border
   alone is a 2px difference between adjacent rows. */
.bk-service-list .bk-service-card.is-chosen .bk-service-card-body {
  background: #f6f8fb;
}

/* Where the provider and length controls land once a service is chosen. Inset
   from the card's left edge so it reads as belonging to the row above it rather
   than as the next item in the list. */
.bk-service-card-slot:empty { display: none; }

.bk-options {
  border-left: 3px solid #dee2e6;
  padding: .75rem 0 .25rem .75rem;
  margin: .5rem 0 .25rem .75rem;
}

/* The group note (item 10). Icon first, text beside it — not a bare paragraph,
   because a sentence with no mark of what KIND of message it is reads as part
   of the control above it. */
.bk-note {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  font-size: .8125rem;
  color: #475569;
  background: #f1f5f9;
  border-radius: .375rem;
  padding: .5rem .625rem;
  margin-top: .75rem;
}

.bk-note-icon { flex: 0 0 auto; margin-top: .125rem; color: #64748b; }

/* The date button carries the chosen day as its label, so it has to be able to
   hold "Wednesday, 20 August" without the icon and the text wrapping apart. */
.bk-date-btn {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

/* The calendar dialog. Narrow on a desktop — a month grid does not get better
   at 600px — and edge-to-edge on a phone, which is the whole reason the grid
   stopped being an inline panel in a five-column card. */
.bk-cal-dialog { max-width: 22rem; }

#bk-cal .flatpickr-calendar {
  box-shadow: none;
  margin: 0 auto;
  max-width: 100%;
}

@media (max-width: 575.98px) {
  .bk-cal-dialog { margin: .5rem; max-width: none; }
  /* Flatpickr sizes its day cells from a fixed calendar width, so on a narrow
     screen the grid is what has to stretch — otherwise the dialog is
     full-width and the tappable targets are still 36px in the middle of it. */
  #bk-cal .flatpickr-calendar,
  #bk-cal .flatpickr-days,
  #bk-cal .dayContainer {
    width: 100%;
    min-width: 0;
    max-width: none;
  }
  #bk-cal .flatpickr-day { max-width: none; height: 2.75rem; line-height: 2.75rem; }
}

/* The confirm step. Marked off from the times above it because it is a
   different act — choosing and committing — and because what it says about
   money must not read as a caption on the last button that was pressed. */
.bk-confirm {
  border-top: 1px solid #e9ecef;
  margin-top: 1rem;
  padding-top: 1rem;
}
