/* ═══════════════════════════════════════════════════════════════════════════════
   VISIT DETAILS PANEL — shared component
   Used by:  index.html (Routes)            → inside the route sidebar (#rsbVisit)
             voodoo/schedule.html (Schedule) → its own right sidebar (#schVisitSidebar)

   Extracted verbatim from index.html so the two pages cannot drift. The host page owns
   only where the panel SITS (its shell's position, width and open/close transition);
   everything from the back arrow inwards lives here.

   Root hook is .visit-detail — added alongside each host's own shell class. It replaces
   the #rsbVisit id the icon-size rules used to key off, so both pages get them.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════════════════
   iOS-style motion — one spring, shared by the side panel and the dialogs
   ═══════════════════════════════════════════════════════════════════════════════════════
   iOS doesn't animate sheets or alerts with bezier curves; it uses springs. Apple exposes
   them as spring(duration:bounce:), and both the sheet presentation and the alert
   presentation are bounce: 0 — critically damped, so they settle without overshooting.
   SwiftUI ships that as `.smooth` (duration 0.5, bounce 0).

   For bounce: 0 the natural frequency is w = 2pi/duration and the unit-step response is
       x(t) = 1 - (1 + w*t) * e^(-w*t)
   which is what the linear() below samples, 37 stops over 1.2x the perceptual duration
   (x reaches 0.986 at 1.0x, so the tail is what actually lands it). Normalising means one
   curve drives every duration — the shape is identical, only the clock changes.

   Character: ~82% of the distance in the first half, then a long quiet settle. That front-
   loaded start is what makes iOS feel immediate without feeling abrupt.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
:root {
  --ios-spring: linear(0.0000 0.0%, 0.0191 2.8%, 0.0667 5.6%, 0.1313 8.3%, 0.2048 11.1%, 0.2816 13.9%, 0.3577 16.7%, 0.4308 19.4%, 0.4991 22.2%, 0.5620 25.0%, 0.6189 27.8%, 0.6700 30.6%, 0.7154 33.3%, 0.7554 36.1%, 0.7905 38.9%, 0.8210 41.7%, 0.8475 44.4%, 0.8704 47.2%, 0.8900 50.0%, 0.9069 52.8%, 0.9213 55.6%, 0.9336 58.3%, 0.9441 61.1%, 0.9529 63.9%, 0.9605 66.7%, 0.9668 69.4%, 0.9722 72.2%, 0.9767 75.0%, 0.9805 77.8%, 0.9837 80.6%, 0.9864 83.3%, 0.9887 86.1%, 0.9905 88.9%, 0.9921 91.7%, 0.9934 94.4%, 0.9945 97.2%, 1.0000 100.0%);
  --ios-sheet-dur: 220ms;    /* spring(duration: ~0.18, bounce: 0) + its settling tail */
  --ios-dialog-dur: 220ms;   /* dialogs fade only — no travel, so a short clock suits it */
  --ios-dismiss-dur: 200ms;  /* dismissal is a plain fade, and faster than presentation */
}

.visit-detail { --icon-md: 18px; }
/* A handful of SVGs in this zone hardcode width/height="16" as attributes, which the token
   can't reach. Presentation attributes lose to any CSS declaration, so size them here. */
.visit-detail svg[width="16"] { width: var(--icon-md); height: var(--icon-md); }

/* No override left: the visit header IS .pnl-head — 12px 24px around a 32px button, a 56px
   band, buttons at y=28. It used to be a fixed 72px band (Figma 1065:5867) with the buttons
   top-aligned inside it, which left 28px of dead air under them. */
/* Mirrors .rd-close so both header controls share one shape and hover. margin-left:-8px
   keeps the ICON on the 24px gutter while the 32px hover square centres on it. Stays in
   flow — it is what gives .vd-header its height (.rd-close is absolute). */
.vd-back {
  width: 32px; height: 32px; margin-left: -8px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; border-radius: 50%;
  color: var(--fg-primary); cursor: pointer;
}
.vd-back:hover { background: var(--bg-tertiary); color: #100f0f; }
.vd-content { flex: 1; overflow: hidden; display: flex; flex-direction: column; padding: 0 32px 0; }   /* flush under the nav band */
/* Wrapper kills the inline line box, so .vd-content's padding-top is the true gap above */
.vd-head-row { display: flex; align-items: center; gap: 8px; height: 36px; }
/* The badge in the top bar (vdMountHeadBadge). The bar is a 4px-gap flex row and the back
   arrow is an 18px glyph centred in a 32px button (7px inset), so: after the arrow,
   7 + 4 + 5 = 16px from the glyph; with no arrow, 8px lines it up with the 32px content
   gutter under it (the bar has 24px of padding). */
.vd-header > .vd-badge { margin-left: 8px; }
.vd-header > .vd-badge.after-back { margin-left: 5px; }
.vd-head-row .rd-opt-wrap { margin-left: auto; flex-shrink: 0; }
/* Scheduled = same as the map date picker "Today" badge: square 4px, no dot */
.vd-badge {
  display: inline-flex; align-items: center; padding: 0 4px;
  border-radius: var(--radius-control); background: #d8deed; color: #425e93; font-size: var(--text-xs); line-height: 20px; font-weight: 400; white-space: nowrap;
}
/* Completed = constructive static badge: square 4px, 14px/22px */
.vd-badge.done { background: var(--green-tint); color: var(--green); gap: 4px; padding-left: 2px; }   /* same metrics as .vd-badge, plus room for the tick */
.vd-badge.done svg { width: 12px; height: 12px; flex-shrink: 0; }   /* the pill's own text size */
/* line-height 36 (was 32) is what makes the title+sub block the Figma's 60px:
   36 + 4 gap + 20. A long title wraps onto more lines rather than truncating; the circle
   stays centred on the taller block. */
/* Was Figma 1343:14498 (24/32, -0.48px); now the Route details heading. The 48px circle beside it centres on
   the whole block — title and sub line together — rather than on the title's line alone. */
.vd-title { font-size: 28px; line-height: 32px; font-weight: 600; letter-spacing: -0.39px; color: #100f0f;   /* the Route details heading (.rd-title, Text.Heading xl), so every panel title matches */
  overflow-wrap: break-word; }
.vd-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-top: 8px; }
/* The record's own avatar, ahead of the title — the route panel's header layout: a 32px circle,
   then the name. Fill and ink are the calendar's colour for that record, passed inline, so a
   visit panel is the green a visit tile is and a request panel the blue a request tile is. */
.vd-kind-av {
  width: 48px; height: 48px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  margin-right: 4px;          /* + the row's 12px gap = Figma's 16px */
  color: #1A1919;             /* the duotone's strokes */
  align-self: flex-start; margin-top: 4px;   /* pinned where a one-line block (32 title + 4 + 20 sub = 56) centres it; a wrapping title grows down, the icon stays put */
}
.vd-kind-av svg { display: block; }
/* Duotone, white-filled: Phosphor's back layer (the path at opacity 0.2) becomes solid white,
   so the glyph reads as a white shape outlined in black on the tinted circle. */
.vd-kind-av svg path[opacity] { fill: #FFFFFF; opacity: 1; }
/* Grows to fill the row. Without this the title block was a shrink-to-fit middle child of a
   space-between row, so the row's slack opened up BETWEEN the avatar and the title and pushed
   the title into the middle of the panel — and a long one truncated while empty space sat on
   either side of it. */
.vd-titleblock { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto; }
.vd-title-row .rd-opt-wrap { flex-shrink: 0; margin-left: 0; }
.vd-sub { font-size: var(--text-base); line-height: 20px; color: #6E6A68; }   /* 4px gap comes from .vd-titleblock; Figma's hushed */
.vd-sub a { color: #6E6A68; text-decoration: underline; cursor: pointer; }
.vd-reminder-check { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: var(--text-base); color: #100f0f; cursor: pointer; }
.vd-reminder-check input { width: 18px; height: 18px; accent-color: var(--green); cursor: pointer; margin: 0; }
/* Date and time — view-only summary, using the route-detail card typography */
.vd-dt-title { font-size: var(--text-base); line-height: 20px; font-weight: 400; color: #100f0f; }
/* icon + label per detail line; the glyph takes the text colour so it stays secondary to the
   date in the section heading above */
.vd-dt-meta { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-base); line-height: 20px; color: #64605e; margin-top: 2px; }
/* Baseline: every item sits in the 20px line box and the 16px icon is centred on the text
   (2px above and below) rather than on the row, so wrapped or mixed lines stay aligned. */
.vd-dt-meta > svg { flex: none; margin-top: 2px; }
/* ── Meta lines: the shared "·" (metaLine / META_SEP in visit-panel.js) ── */
.meta-sep { margin-inline: 6px; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Team section — view-only overlapping avatar stack */
.vd-team-avatars { display: flex; align-items: center; }
.vd-team-av {
  width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: 12px; font-weight: 400;
  box-shadow: 0 0 0 2px #fff;      /* white ring separates overlapping avatars */
  margin-right: -16px; position: relative; cursor: default;
}
.vd-team-av:last-child { margin-right: 0; }
.vd-team-av.more { background: #f8f7f6; color: #100f0f; box-shadow: inset 0 0 0 1px #D2CECB, 0 0 0 2px #fff; }   /* +N overflow chip: light grey stroke inside the white ring, so the pale chip has an edge */
.vd-team-empty { font-size: var(--text-base); color: #64605e; }
/* The unassigned avatar: the same 32px circle an assignee gets, carrying the dashed-user
   glyph on the neutral fill .vd-cust-av uses. Dark ink, not the white an assignee's coloured
   avatar takes — .vd-team-av.is-none outranks .vd-team-av's colour. */
.vd-team-av.is-none { background: #e5e1de; color: #100f0f; }
.vd-team-av.is-none svg { width: 18px; height: 18px; display: block; }
/* 52px band. The divider is an inset shadow, not a border: a border would add its 1px to the
   fixed height and knock the tabs off the pixel grid. */
/* Figma 1067:7243 (tabs), in Inter. Full-bleed: negative margins cancel .vd-content's
   gutter so the rule reaches both panel edges. Bar padding is 16, not 32 — each tab carries its
   own 16px, so the label still lands on the 32px content line while the active underline runs
   past it on both sides, the way the spec draws it.
   padding-bottom 1px sits the underline one pixel above the divider, matching the spec's pb-px.
   Height stays 52 rather than the spec's 44: that is a min-height there, and 52 is the tab band
   from the header spacing (1065:5867). */
.vd-tabs { display: flex; align-items: stretch; gap: 8px; height: 52px; margin: 16px -32px 0;
  padding: 0 16px 1px; box-shadow: inset 0 -1px 0 #e5e1de; }
.vd-tab {
  display: flex; align-items: center; gap: 8px; padding: 0 16px; height: 100%; min-height: 44px;
  font-size: var(--text-base); line-height: 20px; font-weight: 500; color: #64605e; cursor: pointer; border-bottom: 2px solid transparent;
}
.vd-tab.active { color: #100f0f; border-bottom-color: #100f0f; }
/* Notes count — the same count badge. */
.vd-tab-count {
  min-width: 22px; height: 22px; padding: 0 2px; border-radius: 100px; flex-shrink: 0;
  background: #e5e1de; color: #100f0f; font-size: 12px; line-height: 12px; font-weight: 400;
  display: inline-flex; align-items: center; justify-content: center;
}

/* ── Notes tab ── */
/* Notes composer — Figma 1070:13304. Border is the card stroke (#cecac7), not the #64605e
   subtext grey it used to be; radius 4 rather than 8, matching every other field here (the
   Figma node is square-cornered, which nothing else in the prototype is). 24px clear of the
   tab strip above. */
.vd-notebar { border: 1px solid #cecac7; border-radius: var(--radius-control); background: #fff; padding: 8px 12px 0; margin: 24px 0 16px; }   /* the tools row carries the space below it */
.vd-notebar:focus-within { border-color: #25292E; }
.vd-note-input { width: 100%; border: 0; outline: 0; resize: none; font-family: inherit; font-size: var(--text-md); line-height: 24px; color: #100f0f; background: none; height: 48px; min-height: 48px; display: block; }   /* explicit height — a bare textarea sizes off `rows` and came out 53 */
.vd-note-input::placeholder { color: #64605e; }
/* 8px above the row puts it on the spec's 63px. Below it, 12px rather than the spec's 4: at 4
   the Add button sat almost on the box's edge while its own side gutter was 12, which read as
   the field having been cropped. 12 all the way round the tools row instead. */
.vd-note-tools { display: flex; align-items: center; gap: 4px; margin-top: 8px; padding-bottom: 12px; }   /* 4, not 8: the 40px attach button already carries 12px of its own inset, so an 8px gap put 28px between the two glyphs */
.vd-note-icon { width: 40px; height: 40px; border-radius: 999px; border: none; background: none; color: #100f0f; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.vd-note-icon.sm { width: 32px; height: 32px; }
.vd-note-icon:hover { background: #f0eeec; }
.vd-note-icon svg { width: var(--icon-md); height: var(--icon-md); }
/* Add — a green primary that goes quiet while there's nothing to add. Disabled is the design's
   own pattern (Figma 1189:8842): a grey FILL with grey text, not a faded green and not the white
   outline the shared secondary rule was giving it. Keyed off :disabled rather than a class, so
   the button is genuinely inert when it looks it. */
.vd-note-add { margin-left: auto; background: var(--btn-green); border: 1px solid var(--btn-green); color: #fff; }
.vd-note-add:hover:not(:disabled) { background: var(--btn-green-hover); border-color: var(--btn-green-hover); }
.vd-note-add:disabled { background: #f0eeec; border-color: #f0eeec; color: #9c9591; cursor: default; }
/* Feed */
.vd-note-empty { font-size: var(--text-base); color: #64605e; padding: 4px 0 8px; }
/* One event of the timeline the notes history is built on (Figma 1189:8341): a 24px actor
   avatar, 12px to the content column, then a 4px-spaced name row above the note itself. Events
   are 4px apart at the top and 16px at the bottom, which is what separates one from the next.
   The 1px connector rail is gone — the reference draws none. */
/* Reminders — the rows and the hushed line under them that says when a rule applies (or
   cannot yet). Same metrics as the date section's meta rows, so the section reads as one set. */
.vd-rem-list { display: flex; flex-direction: column; gap: 6px; }
.vd-rem-note { font-size: var(--text-xs); line-height: 16px; color: #64605e; padding-left: 24px; }

/* Activity — the second tab on the records that have history but no notes. A timeline, not a
   conversation: a dot per entry against a hairline, and nothing to type into. */
.vd-act-feed { display: flex; flex-direction: column; padding: 4px 0 8px; }
/* ── RyuTimeline, condensed (Figma 1344:20362), measurement for measurement ──────────────
   Figma's colours: hushed #6E6A68, primary #1A1919, constructive #26763B, rail #D2CECB,
   bubble #F4F2F0, avatar fill #BABAB8. TWK Lausanne 300 maps to 400 (the loaded faces).
   The name line keeps Figma's own 4px gaps around its dot (not the 6px meta separator):
   it is a 14px name beside a 12px dot and time, baseline-aligned. */
.rt-tl { display: flex; flex-direction: column; align-items: flex-start; }
.rt-tl-event { display: flex; align-items: flex-start; gap: 12px; padding-top: 4px; width: 100%; }
.rt-tl-actor { flex: none; align-self: stretch; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.rt-tl-av { position: relative; flex: none; width: 24px; height: 24px; border-radius: 96px; overflow: hidden;
  background: #BABAB8; display: flex; align-items: center; justify-content: center; }
.rt-tl-av > span { font-size: 10px; line-height: 12px; font-weight: 500; color: #FFFFFF; letter-spacing: 0.02em; }
.rt-tl-av img { position: absolute; inset: 0; display: block; }
.rt-tl-rail { flex: 1 0 0; min-height: 1px; width: 1px; background: #D2CECB; }
.rt-tl-event:last-child .rt-tl-rail { display: none; }
.rt-tl-content { flex: 1 0 0; min-width: 0; display: flex; flex-direction: column; gap: 4px; padding-bottom: 16px; }
.rt-tl-name { display: flex; align-items: baseline; gap: 4px; padding: 2px 0; color: #6E6A68; white-space: nowrap; font-feature-settings: 'case' on; }
.rt-tl-who { font-size: 14px; line-height: 20px; font-weight: 400; }
.rt-tl-dot, .rt-tl-when { font-size: 12px; line-height: 16px; font-weight: 400; }
.rt-tl-events { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.rt-tl-text { font-size: 14px; line-height: 20px; font-weight: 400; color: #1A1919; font-feature-settings: 'case' on; overflow-wrap: anywhere; }
.rt-tl-text.is-constructive { color: #26763B; }
/* Hugs its text: align-self keeps the column from stretching it to full width, and a long
   note still wraps at the column's edge. */
.rt-tl-bubble { align-self: flex-start; max-width: 100%; box-sizing: border-box;
  background: #F4F2F0; padding: 8px; border-radius: 0 8px 8px 8px;   /* square at the top-left, toward the actor */
  font-size: 14px; line-height: 20px; font-weight: 400; color: #1A1919; white-space: pre-wrap; overflow-wrap: anywhere; font-feature-settings: 'case' on; }
.vd-act-row { position: relative; display: flex; gap: 12px; padding: 10px 0 10px 4px; }
.vd-act-row + .vd-act-row::before {
  content: ''; position: absolute; left: 7px; top: -10px; height: 20px; width: 1px;
  background: var(--border, #e5e1de);
}
.vd-act-dot {
  width: 7px; height: 7px; margin-top: 7px; flex-shrink: 0;
  border-radius: 50%; background: #cecac7;
}
.vd-act-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.vd-act-what { font-size: var(--text-base); line-height: 20px; color: #100f0f; }
.vd-act-meta { font-size: var(--text-xs); line-height: 16px; color: #64605e; }

.vd-note-item { display: flex; align-items: flex-start; gap: 12px; padding-top: 4px; }
.vd-note-av {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  background: #fcfbfa; border: 1px solid rgba(185,180,177,0.4);
  display: flex; align-items: center; justify-content: center;
  font-size: 8px; line-height: 8px; font-weight: 500; color: #100f0f;
}
.vd-note-content { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 4px; padding-bottom: 16px; }
/* Baseline, not centre: the 14px name and the 12px timestamp sit on one line in the reference. */
.vd-note-meta { display: flex; align-items: baseline; gap: 0; padding: 2px 0; color: var(--fg-hushed); }   /* 14px author + 12px time: baseline; .meta-sep spaces the dot */
.vd-note-meta .meta-sep { font-size: var(--text-xs); line-height: 16px; }
.vd-note-author { font-size: var(--text-base); line-height: 20px; color: var(--fg-hushed); }
.vd-note-dot, .vd-note-time { font-size: var(--text-xs); line-height: 16px; color: var(--fg-hushed); }
/* The note as a bubble: square top-left corner, pointing back at the avatar. #f2f1f0 is the
   app's light fill — the reference's #f4f2f0 to within a shade, and one grey instead of two. */
.vd-note-body {
  align-self: flex-start; max-width: 100%;
  background: #f2f1f0; padding: 8px; border-radius: 0 8px 8px 8px;
  font-size: var(--text-base); line-height: 20px; color: #100f0f;
  white-space: pre-wrap; word-break: break-word;
}
/* Customer card — Figma 1065:5584. The name moved up into the section heading (same move as the
   date), so the card is the two contact lines beside the 64px avatar, which sets the row height.
   Figma wraps the card in 20px of padding; here .vd-sec-head's 24px already does that job, so the
   row is the bare 64 and the section rhythm matches Team / Instructions / Line items. */
/* The avatar leads the row, ahead of the contact lines — the same avatar-then-text order the
   Team row uses, so the two sections scan alike. space-between is gone with it: that existed
   only to push the avatar to the far right, and with it leading it would strand the text. */
.vd-cust { display: flex; align-items: center; gap: 12px; }
/* gap 2 + 14/20 lines mirror .vd-dt-meta ("Anytime · 30 mins" / "Repeats…"); the three of them
   come to 64, which is what sets the row height now that the avatar is 40. */
.vd-cust-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vd-cust-line { font-size: var(--text-base); line-height: 20px; color: #64605e;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Phones: the email · phone line wraps instead of truncating the number. Each value stays whole
   (.vd-nw), so the break falls between them and the phone drops to its own line. */
.vd-nw { white-space: nowrap; }
@media (max-width: 680px) {
  .vd-cust-contact { white-space: normal; overflow: visible; text-overflow: clip; }
}
/* chevron rides with the name rather than being pushed to the far edge by .vd-sec-head's
   space-between — it belongs to the name, not to the row */
/* Reads as a link to the client: pointer on the whole row, and the caret slides 2px on hover so
   the row answers the cursor. (There is no client page in the prototype, so the click itself has
   no destination yet — same as View profile in the ⋯ menu.) */
.vd-cust-title { display: flex; align-items: center; gap: 8px; cursor: pointer; width: fit-content; }
.vd-cust-title svg { transition: transform 0.12s ease; }
.vd-cust-title:hover svg { transform: translateX(2px); }
/* Client actions live in the section head's ⋯ menu (see visitPanelHTML) — the outlined
   Message / Email pair that used to sit under the card read as two primary-looking controls for
   what are secondary reads. */
.vd-cust-av {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: #e5e1de; color: #100f0f;
}
/* sections separated by whitespace (side-panel: no dividers, strong heading + rhythm) */
.vd-sec { margin-top: 45px; position: relative; }   /* 24px above divider + 1px rule + 20px below */
/* 1px divider — 24px above, 20px below */
.vd-sec::before { content: ''; position: absolute; left: 0; right: 0; top: -21px; height: 1px; background: #e5e1de; }
.vd-panel { flex: 1; overflow-x: hidden; overflow-y: auto; padding-bottom: 32px; padding-right: 32px; margin-right: -32px; scrollbar-gutter: stable; }
.vd-panel > .vd-sec:first-child { margin-top: 24px; }
.vd-panel > .vd-sec:first-child::before { display: none; }
.vd-sec::before { display: none; }   /* TEMP: dividers hidden for review; delete this line to restore */
.vd-sec { margin-top: 32px; }   /* 32px between sections (dividers are hidden, so space alone groups them) */
.vd-sec-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }   /* was 12 — heading sat too far from its content */
.vd-sec-ico {
  width: 32px; height: 32px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%; background: transparent; color: var(--fg-primary); cursor: pointer; padding: 0;
}
.vd-sec-ico:hover { background: var(--bg-tertiary); }
.vd-team-row { display: flex; align-items: center; gap: 12px; }   /* no bottom margin: the 32px section gap does the spacing (it made this one gap 56px) */
.vd-team-names { font-size: var(--text-base); line-height: 20px; color: #100f0f; }
/* "Unassigned" is the absence of a name, not a name — it reads as the same hushed grey the
   contact lines and the date meta use, so a real assignee is the only black text in the row. */
.vd-team-names.is-none { color: var(--fg-hushed); }
.vd-sec-title { font-size: var(--text-md); line-height: 24px; font-weight: 600; letter-spacing: -0.16px; color: #100f0f; }
.vd-sec > .vd-sec-title { margin-bottom: 20px; }   /* heading → content (was 24) */
.vd-sec-edit { font-size: var(--text-base); color: #100f0f; text-decoration: underline; cursor: pointer; background: none; border: none; font-family: inherit; }
.vd-checks { display: flex; align-items: center; gap: 20px; }
.vd-check { display: inline-flex; align-items: center; gap: 8px; font-size: var(--text-base); color: #100f0f; }
.vd-check .vd-box { width: 18px; height: 18px; border: 1.5px solid #c9c4c0; border-radius: 2px; }
.vd-field { border: 1px solid #cecac7; border-radius: var(--radius-control); padding: 8px 12px; margin-bottom: 8px; }
.vd-field-label { font-size: var(--text-xs); color: #64605e; line-height: 16px; }
.vd-field-value { font-size: var(--text-md); color: #100f0f; line-height: 24px; }
.vd-times { display: flex; margin-bottom: 8px; }
.vd-times .vd-field { flex: 1; margin: 0; border-radius: 0; }
.vd-times .vd-field:first-child { border-radius: var(--radius-control) 0 0 var(--radius-control); }
.vd-times .vd-field:last-child { border-radius: 0 var(--radius-control) var(--radius-control) 0; border-left: none; }
.vd-field-ico { display: flex; align-items: center; justify-content: space-between; }
.vd-field-ico svg { color: #64605e; }
.vd-dur-label { font-size: var(--text-base); font-weight: 500; color: #100f0f; margin-bottom: 8px; }
/* A length we filled in and nobody has confirmed: the assistant's blue with its star leading,
   and no fill behind it — the star already marks it as ours, and a pill on a line that already
   has dot separators read as a third kind of chip. An edit clears it. */
/* Plain inline, not inline-flex: an inline-flex takes its first child's edge as its baseline,
   and with the icon first that lifted "29 min" off the line the rest of the meta sits on. Now
   the text shares the line's baseline and the icon rides beside it, centred on the caps. */
.dur-guess { display: inline; white-space: nowrap; color: #425e93; }
.dur-guess svg { display: inline-block; width: 12px; height: 12px; margin-right: 4px; vertical-align: -1px; }
/* The AI mark's stroke is its gradient, not the text colour. !important because it is beating a
   blanket rule — both pages add `stroke: currentColor` to every Phosphor path to dial icon
   weight, and there is no way to opt one glyph out of it from the other side. */
svg.ai-mark > path { stroke: var(--ai-stroke, none) !important; }
.vd-duration { display: flex; align-items: center; gap: 8px; }
.vd-step { display: flex; align-items: center; border: 1px solid #cecac7; border-radius: var(--radius-control); overflow: hidden; }
.vd-step button { width: 36px; height: 38px; border: none; background: #f0eeec; color: var(--green); font-size: var(--text-md); cursor: pointer; font-family: inherit; }
.vd-step button:hover { background: #e7e4e1; }
.vd-step .vd-step-val { width: 46px; text-align: center; font-size: var(--text-base); color: #100f0f; border-left: 1px solid #cecac7; border-right: 1px solid #cecac7; line-height: 38px; }
.vd-step-unit { font-size: var(--text-base); color: #64605e; margin: 0 6px 0 2px; }
.vd-chip-field { display: flex; align-items: center; justify-content: space-between; border: 1px solid #cecac7; border-radius: var(--radius-control); padding: 8px 10px; margin-bottom: 10px; }
.vd-chip { display: inline-flex; align-items: center; gap: 8px; padding: 4px 10px 4px 4px; border-radius: 999px; background: #efece9; font-size: var(--text-base); color: #100f0f; }
.vd-chip-av { width: 22px; height: 22px; border-radius: 50%; background: #23413a; color: #fff; font-size: var(--text-2xs); font-weight: 500; display: flex; align-items: center; justify-content: center; }
.vd-chip-x { color: #64605e; cursor: pointer; }
.vd-chip-actions { display: flex; align-items: center; gap: 10px; color: #64605e; }
.vd-select { display: flex; align-items: center; justify-content: space-between; border: 1px solid #cecac7; border-radius: var(--radius-control); padding: 8px 12px; }
.vd-select .vd-field-label { line-height: 16px; }
.vd-textarea { width: 100%; min-height: 96px; border: 1px solid #cecac7; border-radius: var(--radius-control); padding: 10px 12px; font-family: inherit; font-size: var(--text-base); line-height: 22px; color: #100f0f; resize: vertical; }
.vd-instr-preview { font-size: var(--text-base); line-height: 22px; color: #100f0f; white-space: pre-wrap; word-break: break-word; }
.vd-li-title { font-size: var(--text-base); font-weight: 500; color: #100f0f; margin-bottom: 6px; }
.vd-li-row { display: flex; justify-content: space-between; font-size: var(--text-base); color: #100f0f; padding: 6px 0; }
.vd-li-row .vd-li-v { font-weight: 500; }
.vd-li-total { border-top: 1px solid #e5e1de; margin-top: 8px; padding-top: 8px; }
.vd-muted { font-size: var(--text-base); color: #64605e; }
/* Line items — "Services & items" list layout (name + meta · price, thin dividers, sum rows, pay pill) */
.vd-li-list { display: flex; flex-direction: column; }
.vd-li-item { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 4px 0; }
.vd-li-name { font-size: var(--text-base); font-weight: 400; line-height: 22px; color: #100f0f; }
.vd-li-meta { font-size: var(--text-sm); line-height: 20px; color: #64605e; margin-top: 2px; }
.vd-li-price { font-size: var(--text-base); line-height: 22px; color: #64605e; white-space: nowrap; flex-shrink: 0; }   /* same grey as the other subtext in this panel */
/* ── Line items table — RyuTableRow.Responsive (Figma 1335:11919), stacked ──────────────
   Each row is its own 64px bordered cell pair; stacked rows overlap by 1px so neighbours share
   one line. Figma's colours (#EBE8E5 border, #1A1919 text); its 300 weight maps to 400. */
.vd-li-table { display: flex; flex-direction: column; }
.vd-li-trow { display: flex; align-items: center; min-height: 64px; background: #fff; border: 1px solid #EBE8E5; }
.vd-li-trow + .vd-li-trow { margin-top: -1px; }
.vd-li-tcell { box-sizing: border-box; padding: 14px 12px; font-size: 14px; line-height: 20px; font-weight: 400; color: #1A1919;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vd-li-tname { flex: 1 0 0; min-width: 0; font-feature-settings: 'case' on; }
.vd-li-tprice { flex: none; width: 140px; text-align: right; font-feature-settings: 'lnum' on, 'tnum' on; }
.vd-li-trow.is-total .vd-li-tcell { font-weight: 500; }
/* rules above the subtotal and the total; the row's own 8px padding sits the line evenly */
.vd-li-item.is-rule { border-top: 1px solid #e5e1de; margin-top: 8px; padding-top: 16px; }
/* 16px each side of the line: the margin tops up the previous row's 8px padding above it,
   and padding-top carries the space below it. */
/* the total is the figure that matters — black and medium, against the regular grey rows above */
.vd-li-item.is-total .vd-li-name,
.vd-li-item.is-total .vd-li-price { color: #100f0f; font-weight: 500; }
.vd-pay-btn { width: 100%; margin-top: 20px; height: 48px; border: none; border-radius: 999px; background: #100f0f; color: #fff; font-family: inherit; font-size: var(--text-base); font-weight: 500; cursor: pointer;  }
.vd-pay-btn:hover { background: #000; }

/* ── panel footer + Mark complete (the green primary) ── */
.vd-footer { flex-shrink: 0; display: flex; align-items: center; gap: 12px; padding: 24px 32px; background: #fff; box-shadow: 0 -1px 0 #e5e1de; }
/* Hugs its label and sits right, matching .rd-save in the route footer. It used to be
   flex:1, which stretched it across the whole bar. */
.vd-complete { display: flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 16px; border: none; border-radius: var(--radius-control); background: var(--green); color: #fff; font-size: var(--text-base); font-weight: 500; cursor: pointer; font-family: inherit; white-space: nowrap; margin-left: auto; }   /* right-aligned; Actions sits left */
.vd-complete:hover { background: var(--green-hover); }
.vd-complete.undo { background: #fff; border: 1px solid #cecac7; color: #100f0f; }
.vd-complete.undo:hover { background: var(--bg-tertiary, #f7f5f3); }   /* whatever .btn-secondary:hover uses on this page */

/* ═══════════════════════════════════════════════════════════════════════════════
   STANDALONE LAYER — add .vp-standalone next to .visit-detail
   ═══════════════════════════════════════════════════════════════════════════════
   index.html already defines every token and every piece of surrounding chrome
   (.pnl-head, .rd-close, .rd-opt-*, .pnl-foot-actions) globally, and uses them for
   the route drawer too — so it must NOT opt in, or these copies would start
   competing with its own cascade.

   A host that has only the panel — voodoo/schedule.html — opts in and gets the
   tokens and chrome the panel markup expects. Values are copied from index.html;
   everything is scoped inside .vp-standalone so nothing leaks onto the host page.
   ═══════════════════════════════════════════════════════════════════════════════ */

.vp-standalone {
  --bg-tertiary: #f3f3ee;
  --border-med: #cecac7;
  --btn-green: #00ab00;
  --btn-green-hover: #008c00;
  --btn-h: 40px;
  --btn-weight: 500;
  --fg-hushed: #64605e;
  --fg-primary: #100f0f;
  --font-sans: 'ABC Oracle', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --green: #00ab00;
  --green-hover: #009400;
  --green-tint: #e4f2e7;
  --icon-sm: 14px;
  --text-2xl: 28px;
  --text-2xs: 10px;
  --text-base: 14px;
  --text-lg: 20px;
  --text-md: 16px;
  --text-sm: 13px;
  --text-xs: 12px;
}

/* ── panel header bar ── */
.vp-standalone .pnl-head {
  flex-shrink: 0; display: flex; align-items: center; gap: 4px;
  padding: 12px 24px;   /* 24 + the button's own 8px inset = the 32px content gutter */
}
.vp-standalone .pnl-head .rd-close { margin-left: auto; }
.vp-standalone .pnl-head .vd-back  { margin-left: 0; }
.vp-standalone .rd-close {
  width: 32px; height: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; border-radius: 50%;
  color: var(--fg-primary); cursor: pointer;
}
.vp-standalone .rd-close:hover { background: var(--bg-tertiary); color: #100f0f; }

/* ── Actions button + its dropdown ── */
.vp-standalone .rd-opt-wrap { position: relative; flex-shrink: 0; }
/* Placement only — the menu itself is shared/menu.css, the one component both pages use. */
.vp-standalone .rd-opt-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 240px; display: none; flex-direction: column; z-index: 20;
}
.vp-standalone .rd-opt-menu.open { display: flex; }
.vp-standalone .rd-opt-wrap.is-up .rd-opt-menu { top: auto; bottom: calc(100% + 8px); left: 0; right: auto; }
.vp-standalone .vd-footer .rd-opt-wrap { margin-left: 0; margin-right: auto; }
.vp-standalone .pnl-foot-actions {
  display: flex; align-items: center; gap: 6px;
  height: 40px; padding: 10px 8px;
  border: none; background: transparent; color: #100f0f;
  font-family: inherit; font-size: var(--text-base); line-height: 20px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
}
.vp-standalone .pnl-foot-actions span { text-decoration: underline; }
.vp-standalone .pnl-foot-actions:hover { background: #f2f1f0; border-radius: var(--radius-control); }
.vp-standalone .rd-opt-menu button { font-feature-settings: "case" 1; }
.vp-standalone .rd-opt-label { flex: 1 0 0; min-width: 0; }


/* ═══════════════════════════════════════════════════════════════════════════════
   VENDORED FROM index.html — panel
   Declarations the panel's classes pick up from rules elsewhere in index.html's stylesheet,
   many of them grouped with unrelated components (.vd-note-add took its whole geometry from a
   rule shared with .bt-btn, .afd-clear, .map-toggle-btn and three others — which is why the
   Add button had colour but no shape on a page that has no such rule).

   Left unprefixed on purpose: index.html's own copies come later in its cascade and carry the
   same values, so nothing changes there, while a page with only this sheet gets the geometry.
   ═══════════════════════════════════════════════════════════════════════════════ */

.vd-textarea:focus { border-color: #cecac7; outline: 2px solid #100f0f; outline-offset: -1px; }   /* default border at rest; the 2px black ring only while typing, drawn over the border */
.rd-opt-wrap { position: relative; flex-shrink: 0; }
/* Placement only — shell and rows are shared/menu.css. */
.rd-opt-menu { position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 240px; display: none; flex-direction: column; z-index: 20; }
.rd-opt-menu.open { display: flex; }
.rd-opt-wrap.is-up .rd-opt-menu { top: auto; bottom: calc(100% + 8px); left: 0; right: auto; }
.rd-footer .rd-opt-wrap,
.vd-footer .rd-opt-wrap { margin-left: 0; margin-right: auto; }
.pnl-foot-actions { display: flex; align-items: center; gap: 6px;
  height: 40px; padding: 10px 8px;
  border: none; background: transparent; color: #100f0f;
  font-family: inherit; font-size: var(--text-base); line-height: 20px; font-weight: 500;
  cursor: pointer; white-space: nowrap; }
.pnl-foot-actions span { text-decoration: underline; }
.pnl-foot-actions:hover { background: #f2f1f0; border-radius: var(--radius-control); }
.rd-opt-menu button { font-feature-settings: "case" 1; }
.rd-opt-label { flex: 1 0 0; min-width: 0; }

.rd-opt-slash { display: none; align-items: center; color: #9c9591; }
.rd-opt-menu button.locked .rd-opt-slash { display: flex; }
.rd-opt-wrap { position: relative; margin-left: auto; flex-shrink: 0; }
.rd-options { display: flex; align-items: center; gap: 4px; height: 40px; padding: 10px 8px;
  border: none; background: none; font-family: inherit;
  font-size: var(--text-base); line-height: 20px; color: #100f0f; cursor: pointer; }
.rd-options span { text-decoration: underline; }
.rd-options { border-radius: var(--radius-control); }
   /* was grouped with unrelated selectors in index.html */
.vd-sec-edit { padding: 4px 8px; margin: -4px -8px; border-radius: var(--radius-control); }
.pnl-head { flex-shrink: 0; display: flex; align-items: center; gap: 4px;
  padding: 12px 24px; }
.pnl-head .rd-close { margin-left: auto; }
.pnl-head .vd-back { margin-left: 0; }
   /* was grouped with unrelated selectors in index.html */
.rd-close { width: 32px; height: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; border-radius: 50%;
  color: var(--fg-primary); cursor: pointer; }
   /* was grouped with unrelated selectors in index.html */
.rd-close:hover { background: var(--bg-tertiary); color: #100f0f; }
   /* was grouped with unrelated selectors in index.html */
.rd-options,
.vd-complete { border-radius: var(--radius-control); }
   /* was grouped with unrelated selectors in index.html */
.vd-complete,
.vd-note-add { box-sizing: border-box;          
  height: var(--btn-h); padding: 8px 16px;
  border-radius: var(--btn-radius);
  font-family: var(--font-sans); font-size: var(--text-base); line-height: 20px;
  font-weight: var(--btn-weight);
  cursor: pointer; white-space: nowrap; }
   /* was grouped with unrelated selectors in index.html */
.vd-complete { background: var(--btn-green); border: 1px solid var(--btn-green); color: #fff; }
   /* was grouped with unrelated selectors in index.html */
.vd-complete:hover { background: var(--btn-green-hover); border-color: var(--btn-green-hover); }
   /* was grouped with unrelated selectors in index.html */
.vd-sec-edit,
.rd-options { font-family: var(--font-sans); font-size: var(--text-base); line-height: 20px;
  font-weight: var(--btn-weight);
  color: var(--fg-primary); text-decoration: underline; text-underline-offset: 2px;
  background: transparent; border: none; cursor: pointer; }
   /* was grouped with unrelated selectors in index.html */
.vd-sec-edit:hover,
.rd-options:hover { color: var(--fg-primary); background: var(--bg-tertiary); }
   /* was grouped with unrelated selectors in index.html */
.vd-complete:disabled { opacity: 0.5; cursor: default; }
   /* was grouped with unrelated selectors in index.html */
.pnl-head { --icon-md: 18px; }

@media (max-width: 680px) {
.vd-tabs { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }
   /* was grouped with unrelated selectors in index.html */
.vd-content,
.vd-footer { padding-left: 24px; padding-right: 24px; }
.pnl-head,
.vd-header.pnl-head { padding-left: 16px; padding-right: 16px; }
}

/* Line items: tabular figures everywhere a price or quantity sits, so the digits line up down
   the column instead of shifting with each 1 and 8. */
.vd-li-table, .vd-li-list, .vd-li-row { font-variant-numeric: tabular-nums lining-nums; }

