/* ============================================================
   UCMS Provider Scheduler (Epic 2) - design prototype
   Screen E2-1: Provider search, operator view.

   This sheet holds only what the Epic 1 sheets do not already
   carry: the member-context strip, the search-criteria set in its
   three review variants, the results table and the slot chips. Every
   colour, size, space and radius below reads an existing custom
   property from css/styles.css. No colour literal is written here
   and no token is added.

   Rulings this sheet serves, by board node id:
     339:1225  member strip gains time zone and full address
     339:1229  team filter replaces the two dead toggles
     339:1233  sort values are earliest available and distance
     339:1250  tier becomes a table column, modality takes icons
     339:1254  next available follows the search criteria
     342:1261  distance in miles is a criteria field
     342:1283  individual days of the week, weekends included
     342:1306  availability is calibrated to the criteria location
     343:1314  accessibility needs is promoted to the primary set
     343:1369  compare providers and the row checkboxes are gone
     364:1920  primary criteria above the table, extended set in a
               labelled Advanced Filters drawer
     122:4132  time period keeps four values plus a weeks-ahead run
     122:4143  default state: criteria collapsed, rail minimized
     122:4178  a confirmed booking reads green
     122:4182  a held slot reads orange
     194:1319  the look-forward range is a criteria control
   ============================================================ */

/* ============================================================
   Operator content width (standing rule for every Epic 2 screen)

   Epic 1 is a provider reading cards and filling forms, so its
   content column is capped at --pp-content-max (1180px) and the
   measure stays comfortable. Epic 2 is an operator working a dense
   queue: a search table of eight columns, three time chips a row and
   a criteria grid four fields wide. Capping that at 1180 left a dead
   strip down the right of the canvas and forced the language,
   location and specialty cells to wrap for no reason.

   So the operator surfaces run fluid. The cap is lifted and the edge
   gutter is the shell's own --cds-padding-xlarge (32px), already
   applied by .app__canvas, so nothing touches the rim. A generous
   ceiling stops the table going gangly on a very wide monitor: at
   1920 the canvas gives about 1784px, which is inside the ceiling,
   so both review widths are genuinely full-bleed and the centring
   only starts above roughly a 2000px viewport.

   This rule lives here, in the Epic 2 sheet, and is reached through
   one extra class on the page. css/styles.css is untouched, so no
   Epic 1 screen changes.
   ============================================================ */
.content--wide {
  max-width: 1800px;
  margin-inline: auto;
}

/* ---------- Member context strip (339:1225) ----------
   The case the operator is acting on behalf of. It sits above the
   criteria because every field under it is read against this member:
   the search location, the time zone the slots are stated in, and
   the eligibility that decides which panels are open. */
.member-strip {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--cds-space-150) var(--cds-space-200);
  padding: var(--cds-padding-medium) var(--cds-padding-large);
}

.member-strip__lead {
  display: flex;
  align-items: center;
  gap: var(--cds-space-75);
  padding-right: var(--cds-space-200);
  border-right: 1px solid var(--pp-border-divider);
}

.member-strip__name {
  font-size: var(--pp-type-sub-size);
  line-height: var(--pp-type-sub-line);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

.member-strip__facts {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--cds-space-150) var(--cds-space-200);
  margin: 0;
}

.member-strip__fact {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-25);
}

.member-strip__fact dt {
  font-size: var(--pp-type-meta-size);
  line-height: 16px;
  color: var(--pp-ink-secondary);
}

.member-strip__fact dd {
  margin: 0;
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

/* The open-question note is gone. Jaspal ruled on 2026-08-20 that those
   communication points come off the design surface entirely, so the five
   tags and this rule set were removed together. The questions are kept,
   verbatim and per screen, in crit/e2-open-points.md. */

/* ---------- Search criteria (DSGN-290, 364:1920) ----------
   The criteria are an accordion above the table, not a left drawer.
   Closed on load (122:4143), with the current criteria stated on the
   header so a closed panel still says what the results are. */
.crit__summary {
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-regular);
  color: var(--pp-ink-secondary);
}

/* The summary states the criteria for a panel that cannot be read. With
   the panel open the fields below say the same thing in full, and the
   line reads as a subtitle under the heading, which nothing on this set
   has. */
#criteria[data-open="true"] .crit__summary {
  display: none;
}

/* A collapsed accordion was zero pixels tall and nothing else: twenty
   eight controls stayed focusable and stayed in the accessibility tree
   while the header said the panel was closed. The script marks the panel
   inert with the collapse; this is the other half of it, held back until
   the collapse has finished so the panel is still drawn while it runs. */
#criteria .acc__panel {
  transition: grid-template-rows 200ms ease-out, visibility 0s linear 0s;
}

#criteria[data-open="false"] .acc__panel {
  visibility: hidden;
  transition: grid-template-rows 200ms ease-out, visibility 0s linear 200ms;
}

.crit__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--cds-space-150);
}

.crit__grid .field,
.crit__grid .fieldset {
  min-width: 0;
}

.crit__span2 {
  grid-column: span 2;
}

/* Days Of The Week is seven short pills, about 460px of content. On a
   row of its own it left three quarters of the grid empty and pushed
   every field below it down. At span 3 it sits beside Time Period, so
   the first row of the panel is the whole "when" question read left to
   right and the criteria card loses a dead band. */
.crit__span3 {
  grid-column: span 3;
}

.crit__span4 {
  grid-column: 1 / -1;
}

/* Two groups that sit next to each other rather than on their own grid
   columns, for short pill sets whose content is narrower than the column
   the grid would give them. */
.crit__inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cds-space-150) var(--cds-space-200);
}

.crit__inline > .fieldset {
  min-width: 0;
}

/* The same rule for two short FIELDS. Panel / Tier and Referral Type held
   two of four grid columns and left the other two empty in the middle of
   the panel, with the disclosure and the apply row under them. On one
   full-width row they sit next to each other at the width their labels
   and values need, and the space the row does not use is one margin at
   its end, which is what 11.2 states. */
.crit__inline--fields > .field {
  flex: 0 1 240px;
  min-width: 0;
}

.crit__rule {
  grid-column: 1 / -1;
  height: 1px;
  background: var(--pp-border-divider);
}

.crit__quick {
  display: flex;
  align-items: center;
  gap: var(--cds-space-50);
  margin-top: var(--cds-space-50);
}

.crit__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--cds-space-75);
  margin-top: var(--cds-space-150);
  padding-top: var(--cds-space-150);
  border-top: 1px solid var(--pp-border-divider);
}

.crit__foot-end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--cds-space-75);
}

/* ---------- Results toolbar ---------- */
.res-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--cds-space-100);
  padding: var(--cds-padding-medium) var(--cds-padding-large);
  border-bottom: 1px solid var(--pp-border-divider);
}

.res-bar__end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--cds-space-100);
}

.res-bar__sort {
  display: flex;
  align-items: center;
  gap: var(--cds-space-50);
  font-size: var(--pp-type-body-size);
  color: var(--pp-ink-emphasis);
}

.res-bar__sort .select-wrap {
  width: 180px;
}

/* It holds 300px wherever the bar has the room, and gives that room up
   before the bar breaks onto a second line. Variant B takes 256px out of
   this card, and a fixed 300 there wrapped the sort control and the count
   under everything else. */
.res-search {
  flex: 0 1 300px;
  min-width: 180px;
}

.res-count {
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink-emphasis);
  font-variant-numeric: tabular-nums;
}

/* ---------- How to read the table ----------
   Two things sat between the toolbar and the table head: a standing note
   about the time zone, and the key to the three slot states. Both were
   full-width blocks with their own vertical padding, so 147px of a 394px
   results card was spent before the first row, and the note was a solid
   blue band 1254px wide carrying two short lines.

   They are one band now: the note on the left, the key on the right, on
   the card's own white with a divider under it. The band belongs to the
   table it explains rather than floating over it.

   The rule this states, for the rest of Epic 2: a permanent explanation
   inside a working surface takes the quiet band. The blue wash is for a
   state that has just changed and needs to be noticed, not for a line
   that is true on every load. */
.res-context {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--cds-space-75) var(--cds-space-200);
  padding: var(--cds-space-75) var(--pp-card-pad);
  border-bottom: 1px solid var(--pp-border-divider);
}

.res-note {
  flex: 1 1 320px;
  min-width: 0;
}

.res-legend {
  flex: none;
  margin-left: auto;
}

/* The shared message box, stated quietly. The icon keeps the accent so
   the band still reads as a note; the wash, the boundary and the block
   padding come off, because the band is already the container. */
.res-note .msg-box {
  align-items: center;
  gap: var(--cds-space-50);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}

.res-note .msg-box__title {
  color: var(--pp-ink);
}

.res-note .msg-box__body {
  margin-top: 2px;
  color: var(--pp-ink-secondary);
}

.res-context .wk-legend {
  padding: 0;
}

/* With no results there is no table to explain, so the band goes with it
   rather than sitting over an empty state that says the opposite. */
.cds-card:has(#res-empty:not([hidden])) > .res-context {
  display: none;
}

/* The three slot states, keyed. Jaspal asked for this on July 14:
   the reference coloured slots and cards with no key anywhere. */
.wk-legend__swatch--open {
  background: var(--pp-primary-tint-soft);
  border-color: var(--pp-primary-200);
}

.wk-legend__swatch--held {
  background: var(--cds-orange-50-opacity-15);
  border-color: var(--cds-orange-350);
}

.wk-legend__swatch--confirmed {
  background: var(--cds-green-400-opacity-07);
  border-color: var(--cds-green-400);
}

/* ---------- Results table (339:1250) ----------
   The reference grouped the rows under REQUESTED PROVIDER,
   PREFERRED PROVIDER and INTERNAL WPO CLINICIANS bands. The tier is
   now a column, so the band is gone and the ranking it carried moves
   into the default sort: requested, then preferred, then internal.
   The scroller is positioned so an absolutely placed child inside it
   cannot project to the scrolled width and widen the document. */
/* The scroller sits in a static host so the clip edge can be marked from
   outside it, the way the calendar's does: an overlay inside a scroll
   container rides away with the content. */
.res-view {
  position: relative;
}

.res-view::after {
  content: "";
  position: absolute;
  z-index: 3;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--cds-space-200);
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to right, transparent, var(--cds-neutral-0));
  transition: opacity 150ms ease-out;
}

.res-view[data-edge~="end"]::after {
  opacity: 1;
}

.res-scroll {
  position: relative;
  overflow-x: auto;
  /* The identity column is pinned over the scroll port, so a chip the
     keyboard reaches to the left of the fold would otherwise be scrolled
     to the port edge and land underneath it. */
  scroll-padding-left: 340px;
}

/* border-collapse: separate is what lets a cell pin. Every rule on this
   table is a bottom border and the cells carry them one each, so the
   drawn result is the same table. */
.res {
  width: 100%;
  min-width: 1040px;
  border-collapse: separate;
  border-spacing: 0;
}

.res thead th {
  padding: var(--cds-space-75) var(--cds-space-100);
  border-bottom: 1px solid var(--pp-border-divider);
  background: var(--cds-neutral-10);
  text-align: left;
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.res thead th:first-child {
  padding-left: var(--cds-padding-large);
}

.res thead th:last-child {
  padding-right: var(--cds-padding-large);
}

.res tbody td {
  padding: var(--cds-space-100);
  border-bottom: 1px solid var(--pp-border-divider);
  vertical-align: top;
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  color: var(--pp-ink);
}

.res tbody td:first-child {
  padding-left: var(--cds-padding-large);
}

.res tbody td:last-child {
  padding-right: var(--cds-padding-large);
}

/* ---------- The identity column holds still ----------
   With variant B's panel open, or with Advanced Filters open in variant
   A, the table gives up its right-hand columns to a horizontal scroller
   and the operator loses Next Available and Book. Scrolled, it also lost
   who each row was. The identity column pins to the left edge and the
   other columns pass under it, which is the rule the calendar grid
   already keeps, at the same values. */
.res thead th:first-child,
.res tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  border-right: 1px solid var(--pp-border-divider);
}

.res thead th:first-child {
  background: var(--cds-neutral-10);
}

.res tbody td:first-child {
  background: var(--cds-neutral-0);
}

/* Scrolled off the left edge the pinned column is over content rather
   than beside it, and the boundary takes the separator step to say so. */
.res-view[data-edge~="start"] .res thead th:first-child,
.res-view[data-edge~="start"] .res tbody td:first-child {
  border-right-color: var(--pp-ink-tertiary);
}

.res tbody tr:hover td {
  background: var(--cds-neutral-10);
}

/* A booked row states it four ways: the green chip, the Confirmed badge,
   the Booked button and this wash. Jaspal's July 14 crit was that Confirm
   changed nothing on the row at all, and 122:4178 asks a confirmed
   appointment to read green, so the change is legible while scanning the
   whole table rather than only inside the cell that was pressed. It sits
   after the hover rule and paints the same cells, so pointing at a
   confirmed row never washes the confirmation off it. */
.res tbody tr[data-booked-slot] td {
  background: var(--cds-green-400-opacity-07);
}

/* A referred row changed too, and it has to be as legible while scanning
   as a confirmed one. It does not take a status colour: green is booked
   and orange is held (122:4178, 122:4182, 365:2004), and a referral is
   neither. It takes the quiet ground, and the word Referred on the row
   carries the meaning. */
.res tbody tr[data-referred] td {
  background: var(--cds-neutral-50);
}

/* That wash is the neutral badge's own ground, so the tier pill and the
   Referred pill on the row stopped reading as pills. On a referred row
   they take the card white back. Only the neutral badges: the tier
   colours carry their own ground and are unaffected. */
.res tbody tr[data-referred] .cds-badge--neutral {
  background: var(--cds-neutral-0);
}

/* Location and language are short fixed strings and read badly broken
   after a comma ("Round Rock," over "TX"). Holding them on one line
   raises their min-content width, so the auto table layout gives them
   what they need and takes it from the columns that have slack,
   rather than the width being guessed in pixels here. */
.res tbody td:nth-child(3),
.res tbody td:nth-child(4) {
  white-space: nowrap;
}

.res tbody tr[hidden] {
  display: none;
}

/* Width hints, not a fixed layout: the browser still grows a column
   that would otherwise clip a badge or a name. Retuned for the fluid
   width above. The three cells that were wrapping for no reason now
   get enough room to sit on one line at 1440 (location, language and
   the modality label), and Next Available gets enough for all three
   time chips in a single row. */
/* 318 rather than the earlier 286. The identity cell now carries the
   details chevron, and at 286 two of the three specialty lines broke
   where one used to. Measured at 1440: 318 puts the cell back to 296px
   and leaves the longest specialty as the only wrap. */
/* Retuned again once Next Available stopped wrapping. That column now
   states a real 239px minimum, and the 1302px the card gives at 1440 has
   to come from somewhere: the identity cell dropped to 258 and broke all
   three specialty lines where it used to break one. The four cells that
   were carrying more than their content needs give the width back. */
.res__c-prov { width: 340px; }
.res__c-tier { width: 138px; }
.res__c-loc { width: 134px; }
.res__c-lang { width: 140px; }
.res__c-mode { width: 152px; }
.res__c-dist { width: 70px; }
.res__c-next { width: 240px; }
.res__c-act { width: 84px; }

/* The identity cell is the way into the provider details drawer, so the
   whole cell is the control rather than a separate link beside the name.
   The chevron says where it goes; the underline on hover says it is a
   control at all. It is still one affordance, so the table keeps its
   eight columns and nothing else on the row moves. */
.res__prov {
  display: flex;
  align-items: flex-start;
  gap: var(--cds-space-75);
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* The text takes the width it needs and gives it back when the column is
   tight; it does not claim the whole cell. On a 1920 monitor the identity
   column runs 438px and a stretched text block parked the chevron 180px
   away from the name it belongs to, reading as a stray mark at the column
   edge rather than as this row's way in. The button still fills the cell,
   so the target the operator clicks is unchanged. */
.res__prov-text {
  flex: 0 1 auto;
  min-width: 0;
}

.res__prov-chev {
  flex: none;
  align-self: center;
  display: flex;
  color: var(--pp-ink-secondary);
}

.res__prov-chev svg {
  width: 20px;
  height: 20px;
}

.res__prov:hover .res__name {
  text-decoration: underline;
}

/* The chevron takes about 32px out of the identity cell, which was
   enough to break the longest name and the longest specialty over an
   extra line each. Holding the name on one line raises the column's
   min-content width, so the auto table layout gives the cell what it
   needs and takes it from the columns with slack. Same device the
   location and language cells above already use, rather than guessing
   a new pixel width. */
.res__prov .res__name {
  white-space: nowrap;
}

.res__avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 17px;
  background: var(--pp-primary-tint);
  color: var(--pp-primary);
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
}

.res__name {
  display: block;
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

.res__spec {
  display: block;
  margin-top: 2px;
  font-size: var(--pp-type-meta-size);
  line-height: 16px;
  color: var(--pp-ink-secondary);
}

.res__status {
  display: inline-flex;
  margin-top: var(--cds-space-50);
}

.res__mode {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-25);
}

.res__mode-item {
  display: flex;
  align-items: center;
  gap: var(--cds-space-25);
  white-space: nowrap;
}

.res__mode-item svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--pp-ink-secondary);
}

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

.res__next-day {
  display: block;
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

/* A row can be in the results and still have nothing on the days that
   were searched. The cell says so in one line rather than going blank,
   which is the rule the grid's empty cell already keeps, and the row's
   Book is switched off with it. */
.res__next-none {
  display: block;
  color: var(--pp-ink-secondary);
}

.res__hold {
  display: block;
  margin-top: var(--cds-space-25);
  font-size: var(--pp-type-meta-size);
  line-height: 16px;
  color: var(--cds-orange-400);
}

.res__hold:empty {
  display: none;
}

/* Book and Refer stacked, so every external row stood a third taller
   than an internal one and the external panel read looser than the panel
   beside it. Side by side, the column states a real min-content width and
   the auto layout takes it from the columns with slack, which is the
   device this sheet already uses for Location, Language and the chips. */
.res__act {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--cds-space-50);
}

/* The row action is a small pill. The set on this screen is one
   height down from the page buttons so eight rows of them never read
   as eight calls to action. */
.res__act .cds-btn {
  height: 32px;
  padding: 0 var(--cds-space-75);
  border-radius: var(--cds-radius-btn-small);
}

/* ---------- Time slot chips (122:4178, 122:4182) ----------
   Three states, and the colour is never the only signal: the row
   badge and the held line say the same thing in words.
     open      quiet accent tint
     held      orange, the five-minute hold
     confirmed green, the booking is made */
.slots {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cds-space-25);
  margin-top: var(--cds-space-50);
}

/* In the table the three chips are one reading, so they hold one line.
   At 1440 the Next Available cell settled at 198px against the 207px the
   three chips need, so every row broke 2 over 1 and stood 117px tall
   against 87px at 1920: the same table, thirty pixels a row worse on the
   narrower of the two review widths, for nine pixels.

   The fix is the device this sheet already uses twice. A row that cannot
   wrap states a real min-content width, so the auto table layout gives
   the column what it needs and takes it from the columns with slack,
   rather than a pixel width being guessed here. Scoped to the table: the
   drawer builds its own chip rows a day at a time and those still wrap. */
.res .slots {
  flex-wrap: nowrap;
}

.slot-chip {
  height: 26px;
  padding: 0 var(--cds-space-50);
  border: 1px solid var(--pp-primary-100);
  border-radius: var(--cds-radius-btn-small);
  background: var(--pp-primary-tint-soft);
  color: var(--pp-primary);
  font-family: inherit;
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 150ms ease-out, border-color 150ms ease-out;
  /* No tabular figures here. In HN for TELUS the tabular set gives the
     colon a digit-wide advance, so "9:00 am" renders as "9 : 00 am". */
}

.slot-chip:hover:not(:disabled) {
  background: var(--pp-primary-tint);
  border-color: var(--pp-primary-200);
}

/* Once a slot on this provider is booked the other chips are switched
   off in the script, and nothing said so: they kept the open tint, the
   pointer cursor and the hover step while doing nothing. A disabled mark
   is one of the two jobs the tertiary ink is for. */
.slot-chip:disabled {
  border-color: var(--pp-border-card);
  background: var(--cds-neutral-10);
  color: var(--pp-ink-tertiary);
  cursor: not-allowed;
}

.slot-chip[aria-pressed="true"] {
  background: var(--cds-orange-50-opacity-15);
  border-color: var(--cds-orange-350);
  color: var(--cds-orange-400);
}

.slot-chip[data-booked="true"],
.slot-chip[data-booked="true"]:hover {
  background: var(--cds-green-400-opacity-07);
  border-color: var(--cds-green-400);
  color: var(--cds-green-400);
  cursor: default;
}

/* ---------- Results footer (360:1341) ---------- */
.res-foot {
  display: flex;
  align-items: center;
  gap: var(--cds-space-100);
  padding: var(--cds-padding-medium) var(--cds-padding-large);
  border-top: 1px solid var(--pp-border-divider);
}

.res-foot__end {
  margin-left: auto;
}

/* ---------- Advanced filters drawer (364:1920) ----------
   The board spec on the Provider Search section (360:4178) states a
   420px right drawer on a 1440x900 canvas, which is what this uses.
   Epic 1's own drawers are 400px, so the width is declared here
   rather than changed anywhere the Epic 1 screens can read it. */
.drawer--adv {
  width: min(420px, 100vw);
}

.drawer--adv .drawer__body {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-150);
}

.drawer--adv .drawer__foot {
  display: flex;
  gap: var(--cds-space-75);
}

.drawer--adv .drawer__foot .cds-btn {
  flex: 1;
}

/* ============================================================
   E2-2 Provider details drawer (122:4165, 343:1356)

   E2-2 is a state of E2-1, not a screen of its own: the row opens a
   right drawer that sits over the results. Width is 420px, which is the
   board's own right-drawer spec for this canvas (360:4178) and the width
   the other two right drawers on this page already use. The Figma Make
   export draws this panel at 320px, but there it is an in-flow column
   that pushes the table sideways; as an overlay at 420 the availability
   chips sit three to a row instead of two and nothing wraps.

   The page holds still behind it. details.css steps .app__main aside for
   a right drawer above 1280, which is right for Advanced Filters but
   wrong here: this drawer is meant to be read against the row it came
   from, so only the scrim moves.
   ============================================================ */
.drawer--prov {
  width: min(420px, 100vw);
  display: none;
}

.scrim--prov {
  display: none;
}

/* The shared drawer state on the body draws the criteria drawers. This
   one has its own state, so the two can never be open together and
   neither can be left drawn by the other's close. */
[data-prov="open"] .drawer--prov {
  display: flex;
}

[data-prov="open"] .scrim--prov {
  display: block;
}

.drawer--prov .drawer__body {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-150);
}

.pav__id {
  display: flex;
  align-items: flex-start;
  gap: var(--cds-space-100);
}

.pav__id-text {
  flex: 1;
  min-width: 0;
}

/* The provider is the subject of this drawer and About and Availability
   are the structure around them. All three ran at the sub role, so the
   name and the two section labels were the same size, weight and colour
   and nothing said which one the panel was about. The name takes the
   section role; the labels keep the sub role a step under it. */
.pav__name {
  font-size: var(--pp-type-section-size);
  line-height: var(--pp-type-section-line);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

/* A 34px mark is the table's size, where it rides a 14px name. Beside a
   20px name in the drawer it reads undersized. */
.pav__id .res__avatar {
  width: 40px;
  height: 40px;
  border-radius: 20px;
  font-size: var(--pp-type-body-size);
}

.pav__line {
  margin-top: 2px;
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  color: var(--pp-ink-secondary);
}

/* Tier, location and distance are the row's own columns, restated where
   the operator is now reading. Same shape as the member strip above the
   table so the two context blocks read as one family. */
.pav__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cds-space-100) var(--cds-space-200);
  margin: 0;
  padding: var(--cds-padding-medium) 0;
  border-top: 1px solid var(--pp-border-divider);
  border-bottom: 1px solid var(--pp-border-divider);
}

.pav__fact {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-25);
}

.pav__fact dt {
  font-size: var(--pp-type-meta-size);
  line-height: 16px;
  color: var(--pp-ink-secondary);
}

.pav__fact dd {
  margin: 0;
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

.pav__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cds-space-50);
}

/* The modality item is cloned out of the row, where it is a plain icon
   and label in a cell. Beside the language and credential chips it has
   to read as one of the set, so it takes the same neutral chip shell
   rather than sitting between them as loose text. */
.pav__tags .res__mode-item {
  height: 24px;
  padding: 0 var(--cds-padding-small);
  border-radius: var(--cds-radius-xsmall);
  background: var(--cds-neutral-50);
  color: var(--pp-ink-emphasis);
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  line-height: 1;
}

.pav__tags .res__mode-item svg {
  width: 14px;
  height: 14px;
}

.pav__h {
  font-size: var(--pp-type-sub-size);
  line-height: var(--pp-type-sub-line);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-navy);
}

.pav__h-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cds-space-75);
}

.pav__count {
  font-size: var(--pp-type-meta-size);
  color: var(--pp-ink-secondary);
}

.pav__about {
  margin-top: var(--cds-space-50);
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  color: var(--pp-ink);
}

/* 343:1356 removes the two date pickers and asks for the weekly jump to
   be more visible, so the navigator is a bar in its own right rather
   than a pair of arrows tucked beside the heading. */
.pav__wknav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cds-space-50);
  margin-top: var(--cds-space-100);
  padding: var(--cds-space-25) var(--cds-space-50);
  border: 1px solid var(--pp-border-card);
  border-radius: var(--pp-block-radius);
  background: var(--cds-neutral-10);
}

.pav__wklabel {
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

.pav__days {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-150);
  margin-top: var(--cds-space-150);
}

.pav__days:empty {
  display: none;
}

.pav__day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cds-space-75);
}

.pav__day-name {
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-ink-strong);
}

.pav__day-range {
  font-size: var(--pp-type-meta-size);
  color: var(--pp-ink-secondary);
}

/* The footer states the hold in words beside the button that acts on
   it, which is the same contract the row keeps. */
.drawer--prov .drawer__foot {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-75);
}

.pav__state {
  font-size: var(--pp-type-meta-size);
  line-height: 16px;
  color: var(--pp-ink-secondary);
}

.pav__state:empty {
  display: none;
}

.pav__state--held {
  color: var(--cds-orange-400);
}

.pav__state--confirmed {
  color: var(--cds-green-400);
}

.pav__acts {
  display: flex;
  gap: var(--cds-space-75);
}

.pav__acts .cds-btn {
  flex: 1;
}

.pav__acts .cds-btn[hidden] {
  display: none;
}

/* ============================================================
   E2-3 Booking confirmation (108:857, 366:2101, 360:1341) and
   E2-4 Referral confirmation (343:1423, 343:1407, 51:156)
   The modal shell, its two faces and the success state are the set's
   own, out of css/details.css, so only what these two steps add is
   here: the fact list a confirmation states, the quiet note under it,
   and the modality choice the booking carries.
   ============================================================ */

/* The fact list. A confirmation states what is being committed, one
   fact per line, and both steps state a different set of them, so the
   component is named for the dialog rather than for the booking. */
.mdl__facts {
  margin: 0;
  border-top: 1px solid var(--pp-border-divider);
}

/* A label and a value on one line, with the labels on one column edge so
   the values read down as a list rather than as a run of sentences. */
.mdl__fact {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  align-items: baseline;
  gap: var(--cds-space-100);
  padding: var(--cds-space-100) 0;
  border-bottom: 1px solid var(--pp-border-divider);
}

.mdl__fact[hidden] {
  display: none;
}

.mdl__fact dt {
  font-size: var(--pp-type-meta-size);
  line-height: 20px;
  color: var(--pp-ink-secondary);
}

.mdl__fact dd {
  margin: 0;
  font-size: var(--pp-type-body-size);
  line-height: 20px;
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

/* The consequence of the action, which is true on every load of the
   dialog rather than a state that has just changed, so it takes the
   quiet band rather than the blue wash. Same treatment as the time-zone
   note beside it; the name is the general one because what it carries
   here is not a time zone. */
.mdl__note {
  display: flex;
  align-items: flex-start;
  gap: var(--cds-space-50);
  margin-top: var(--cds-space-150);
  padding: var(--cds-padding-small) var(--cds-padding-medium);
  border: 1px solid var(--pp-border-card);
  border-radius: var(--cds-radius-small);
  background: var(--cds-neutral-50);
  font-size: var(--pp-type-meta-size);
  color: var(--pp-ink-emphasis);
}

.mdl__note svg {
  width: 16px;
  height: 16px;
  flex: none;
  margin-top: 1px;
  color: var(--pp-ink-secondary);
}

/* The choice is a control inside a row of facts, so it takes the row's
   own height rather than the page control height, and it is absent
   entirely for a provider who offers one modality. */
.bk__modes .cds-seg__item {
  height: 26px;
  padding: 0 var(--cds-space-75);
  font-size: var(--pp-type-meta-size);
}

.bk__modes[hidden] {
  display: none;
}

.bk__modes .cds-seg__item svg {
  width: 14px;
  height: 14px;
  margin-right: var(--cds-space-25);
}

.mdl__body .tz-note {
  margin-top: var(--cds-space-150);
}

/* ---------- Narrow widths ----------
   The prototype is a desktop review surface. Below the Epic 1
   breakpoint the criteria grid drops to two columns and then one, so
   the panel stays readable rather than pretending to be responsive. */
@media (max-width: 1200px) {
  .crit__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .crit__span2 {
    grid-column: span 1;
  }

  .crit__span3 {
    grid-column: 1 / -1;
  }
}

@media (max-width: 760px) {
  .crit__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .crit__span2,
  .crit__span3,
  .crit__span4 {
    grid-column: 1 / -1;
  }

  .res-search {
    width: 100%;
  }
}

/* ============================================================
   Search criteria in three variants (Jaspal, 2026-08-20)

   The same criteria, in three containers, so the review can settle
   which container the build gets. The fields themselves exist once, in
   #crit-set, and the extended set exists once, in #adv-set. The
   switcher moves those two blocks; it never copies them. That is why
   the three variants filter the table identically: they are the same
   nodes and the same handlers.

     A  the accordion above the table, with the extended set in a
        separate 420px Advanced Filters drawer. Default, and what the
        team has already reviewed.
     B  Bryan's original left criteria panel, from the Figma Make
        export. An in-flow 256px column beside the results, opened
        from a Search Criteria button on the results header. The Make
        design keeps the extended fields in this same panel, under a
        collapsed More options disclosure, so B has no second drawer.
     C  a trigger at the right end of the member strip opening one
        420px right drawer that overlays the page. The extended fields
        are in that same drawer, under Advanced Options, so C has no
        second drawer either.

   The state is one attribute on the document element, so the head
   script can stamp it from the URL before first paint.
   ============================================================ */

/* ---------- What each variant hides ---------- */
[data-crit-variant="a"] .member-strip__crit,
[data-crit-variant="a"] .res-bar__crit,
[data-crit-variant="a"] .crit-left,
[data-crit-variant="a"] .crit__more,
[data-crit-variant="a"] .drawer--critc {
  display: none;
}

[data-crit-variant="b"] #criteria,
[data-crit-variant="b"] .member-strip__crit,
[data-crit-variant="b"] [data-adv-open],
[data-crit-variant="b"] .drawer--adv,
[data-crit-variant="b"] .drawer--critc {
  display: none;
}

[data-crit-variant="c"] #criteria,
[data-crit-variant="c"] .res-bar__crit,
[data-crit-variant="c"] .crit-left,
[data-crit-variant="c"] [data-adv-open],
[data-crit-variant="c"] .drawer--adv {
  display: none;
}

/* ---------- Variant B: the search row ----------
   The criteria column and the results sit in one flex row, which is
   how the Make export builds it. The results column carries min-width
   0 so the table can still scroll inside .res-scroll rather than
   widening the page. */
.srch-row {
  display: flex;
  align-items: flex-start;
  gap: var(--cds-space-150);
  min-width: 0;
}

.srch-row__main {
  flex: 1;
  min-width: 0;
}

/* 256px is the Make panel width (w-64). Closed on load; the results
   take the full row until the operator opens it.

   It is a surface sitting on the canvas beside another surface, so it
   takes the card treatment the results card next to it has. Before this
   pass it carried no ground, no edge and no radius: fifteen fields and
   two buttons stood loose on the canvas with only the head's own
   hairline to say where the panel began, and the eye read them as page
   content rather than as a panel the operator had opened.

   Sixteen fields in one 256px column run past 1900px, which left the
   results card floating in the top half of a page of empty canvas. The
   panel is capped at the viewport and scrolls its own body instead, so
   the head stays put and the page keeps the height of its content. */
.crit-left {
  display: none;
  flex: none;
  width: 256px;
  flex-direction: column;
  position: sticky;
  top: var(--cds-space-150);
  max-height: calc(100vh - var(--pp-appbar-height) - var(--cds-space-200));
  background: var(--cds-neutral-0);
  border: 1px solid var(--pp-border-card);
  border-radius: var(--pp-card-radius);
}

[data-crit-variant="b"][data-critleft="open"] .crit-left {
  display: flex;
}

.crit-left__head {
  display: flex;
  align-items: center;
  flex: none;
  gap: var(--cds-space-75);
  padding: var(--cds-padding-medium);
  border-bottom: 1px solid var(--pp-border-divider);
}

.crit-left__title {
  flex: 1;
  min-width: 0;
  font-size: var(--pp-type-sub-size);
  line-height: var(--pp-type-sub-line);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--wpo-navy);
}

.crit-left__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--cds-padding-medium);
}

/* One column at 256px, and the two custom-range dates stack rather
   than squeezing side by side. Sixteen stacked fields do not need the
   24px interval the four-across grid uses; at this width the label and
   its control are already an unmistakable pair. */
.crit-left .crit__grid {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--cds-space-100);
}

.crit-left .crit__span2,
.crit-left .crit__span3,
.crit-left .crit__span4 {
  grid-column: 1 / -1;
}

.crit-left .field__row {
  flex-direction: column;
  align-items: stretch;
}

/* The Make panel ends on a full-width Update results. Same here, and
   Clear All sits under it rather than beside it. */
.crit-left .crit__foot {
  flex-direction: column;
  align-items: stretch;
}

.crit-left .crit__foot-end {
  margin-left: 0;
}

.crit-left .crit__foot .cds-btn {
  width: 100%;
  justify-content: center;
}

/* ---------- The apply row stays reachable in both narrow containers ----------
   B and C carry the whole criteria set in one column: sixteen fields and
   the extended set under them. The row that applies them sat at the end
   of that column, so in B it was a page-scroll away and in C it was a
   drawer-scroll away, and in both the operator had to leave the fields to
   reach the button that acts on them.

   Both containers scroll their own body, so the row pins to the bottom of
   that scroller. It bleeds to the container's edges and repaints the
   ground behind it, so the fields pass under a solid strip rather than
   showing through it. Variant A is untouched: its host is an accordion
   inside the page, with no scroller of its own to pin to.

   A sticky offset is resolved against the scroll port already inset by
   the scroller's own padding, so bottom:0 parks the row one padding step
   short of the edge and the fields show through the strip underneath.
   The offset is that padding, negated. */
.crit-left .crit__foot,
.drawer--critc .crit__foot {
  position: sticky;
  z-index: 1;
  margin-bottom: 0;
  background: var(--cds-neutral-0);
}

.crit-left .crit__foot {
  bottom: calc(-1 * var(--cds-padding-medium));
  margin-inline: calc(-1 * var(--cds-padding-medium));
  padding: var(--cds-space-150) var(--cds-padding-medium) var(--cds-padding-medium);
}

.drawer--critc .crit__foot {
  bottom: calc(-1 * var(--pp-card-pad));
  margin-inline: calc(-1 * var(--pp-card-pad));
  padding: var(--cds-space-150) var(--pp-card-pad) var(--pp-card-pad);
}

/* ---------- Days of the week in a narrow container ----------
   Seven pills wrapping freely broke 3 / 3 / 1 in the 256px panel and
   5 / 2 in the 420px drawer, so the last row was an orphan in both and
   no two columns lined up. Four to a row reads 4 / 3 in either width and
   the pills sit on a grid. */
.crit-left .crit__span3 .pills,
.drawer--critc .crit__span3 .pills {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.crit-left .crit__span3 .pill,
.drawer--critc .crit__span3 .pill {
  justify-content: center;
  padding-inline: var(--cds-space-25);
}

.res-bar__crit {
  flex: none;
}

/* With the panel open the table loses 256px and the auto layout starts
   breaking provider names across three lines, which reads as a fault
   rather than as the cost of the panel. Holding the name on one line
   raises the column's min-content width, so the layout gives it room
   and .res-scroll scrolls instead. Scoped to this one state, so the
   table in variants A and C is untouched. */
[data-crit-variant="b"][data-critleft="open"] .res__name {
  white-space: nowrap;
}

/* ---------- Variant C: the member-strip trigger and its drawer ----------
   The trigger sits at the right end of the strip the search is run
   against, which is the point of this variant: the criteria hang off
   the member, not off the results. */
.member-strip__crit {
  margin-left: auto;
  flex: none;
}

/* Same 420px as the Advanced Filters drawer, from the board build spec
   on this canvas (360:4178). It overlays: no rule here gives .app__main
   a right padding, so the table stays where it is and the scrim carries
   the click-out. */
.drawer--critc {
  width: min(420px, 100vw);
}

/* css/details.css steps the page aside for a right drawer above 1280.
   That is right for Advanced Filters in variant A, where the operator
   keeps reading the table while the extended fields are open. It is
   wrong here: variant C exists to be judged as a drawer that sits ON
   the results, so the page holds still and only the scrim moves. */
[data-crit-variant="c"] [data-drawer="open"] .app__main {
  padding-right: 0;
}

.drawer--critc .crit__grid {
  grid-template-columns: minmax(0, 1fr);
}

.drawer--critc .crit__span2,
.drawer--critc .crit__span3,
.drawer--critc .crit__span4 {
  grid-column: 1 / -1;
}

/* ---------- Advanced Options, variants B and C ----------
   The extended set, inside the criteria panel, collapsed on load. This
   is the Make design's own treatment (isMoreOptionsExpanded starts
   false) and it is what removes the need for a second drawer. */
.crit__more {
  margin-top: var(--cds-space-150);
  padding-top: var(--cds-space-150);
  border-top: 1px solid var(--pp-border-divider);
}

.crit__more-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cds-space-50);
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  color: var(--wpo-navy);
  cursor: pointer;
}

.crit__more-title {
  font-size: var(--pp-type-sub-size);
  line-height: var(--pp-type-sub-line);
  font-weight: var(--cds-font-weight-semibold);
}

.crit__more-chevron svg {
  display: block;
  width: 20px;
  height: 20px;
  transition: transform 150ms ease-out;
}

.crit__more-head[aria-expanded="true"] .crit__more-chevron svg {
  transform: rotate(180deg);
}

.crit__more-body {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-150);
  margin-top: var(--cds-space-100);
}

/* A class-set display beats the hidden attribute's user-agent rule, so
   the attribute needs saying again here or the panel never closes. */
.crit__more-body[hidden] {
  display: none;
}

/* The extended set carries its own stacking wherever it lands, because
   in variant A its host is the drawer body and in B and C it is the
   Advanced Options panel. */
.adv__set {
  display: flex;
  flex-direction: column;
  gap: var(--cds-space-150);
}

/* ---------- Variant switcher, prototype only ----------
   Not design. Three letters stacked in the empty foot of the side rail,
   which is the one strip of chrome on this page that carries nothing,
   so the control sits over the shell rather than over the screen it is
   switching. It is opaque, because a translucent pill reads as a bug
   when the page scrolls under it. Each letter names its variant on
   hover and to a screen reader. */
.vswitch {
  position: fixed;
  left: 17px;
  bottom: var(--cds-space-100);
  z-index: 90;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--cds-space-25);
  width: 38px;
  padding: var(--cds-space-25) 0;
  border: 1px solid var(--pp-border-card);
  border-radius: var(--cds-radius-btn-large);
  background: var(--cds-neutral-0);
}

.vswitch__btn {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: none;
  font-family: inherit;
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink-emphasis);
  cursor: pointer;
}

.vswitch__btn:hover {
  background: var(--cds-neutral-50);
}

.vswitch__btn[aria-pressed="true"] {
  background: var(--pp-primary-tint);
  color: var(--pp-primary);
}

/* ---------- Narrow widths ----------
   Below roughly a laptop the criteria column stops being a column and
   sits above the results. The review widths are 1440 and 1920, so this
   is hygiene rather than a supported breakpoint. */
@media (max-width: 1000px) {
  .srch-row {
    flex-direction: column;
  }

  .crit-left {
    width: 100%;
  }
}

/* ============================================================
   Results calendar view (193:1308, 343:1380, 343:1393)

   A view of the results, on the same card, under the same toolbar.
   It is not a screen of its own, so the panel switch, the filter box,
   the sort, the time-zone note and the slot key above it all still
   apply and are not restated here.

   Three board asks and no others:
     193:1308  a two-week timeline by default, with buttons that shift
               the whole window at once
     343:1380  the day columns are the days the search asked for, not a
               fixed Monday to Sunday week
     343:1393  a provider multi-select that narrows the grid

   The grid echoes the Epic 1 calendar's vocabulary (css/calendar.css):
   a head row of uppercase day names over date numbers, a divider
   between columns, today marked in the head only. It does not read
   that sheet: the Epic 1 grid is a time-of-day grid for one provider
   and this one is a day grid for several, so the rules are stated
   here, page-scoped, and css/calendar.css is untouched.
   ============================================================ */

/* One view at a time. The state is an attribute on the document
   element, stamped by the head script from the URL before first paint,
   the same contract the criteria variant keeps. */
[data-res-view="table"] .res-cal {
  display: none;
}

[data-res-view="calendar"] .res-view {
  display: none;
}

.res-cal[hidden] {
  display: none;
}

/* With no grid there is nothing for the band above to explain, which is
   the rule the table's own empty state already keeps. */
[data-res-view="calendar"] .cds-card:has([data-cal-empty]:not([hidden])) > .res-context {
  display: none;
}

/* ---------- The calendar's own toolbar ----------
   The horizon control and the provider picker belong to the grid, not
   to the result set, so they sit on a second band under the results
   toolbar rather than crowding into it. */
.res-cal__bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--cds-space-100);
  padding: var(--cds-space-75) var(--pp-card-pad);
  border-bottom: 1px solid var(--pp-border-divider);
}

.res-cal__nav {
  display: flex;
  align-items: center;
  gap: var(--cds-space-50);
}

/* 193:1308 asks for buttons that shift the view fast, so a press moves
   the whole two-week window rather than one week. The label states the
   window it landed on, and it holds its width so the grid under it does
   not step sideways as the label changes length. */
.res-cal__range {
  min-width: 156px;
  text-align: center;
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

/* The bar's right group. The count that says what the grid is drawing
   sits beside the control that changed it, so the two are read together
   and the card never carries two counts that disagree. */
.res-cal__bar-end {
  display: flex;
  align-items: center;
  gap: var(--cds-space-100);
  margin-left: auto;
}

/* The results toolbar counts the result set; this counts what the grid
   is drawing out of it. It shows only while the picker is narrowing,
   because otherwise the two numbers are the same number. */
.res-cal__showing {
  font-size: var(--pp-type-body-size);
  color: var(--pp-ink-secondary);
  font-variant-numeric: tabular-nums;
}

.res-cal__showing[hidden] {
  display: none;
}

/* ---------- Provider multi-select (343:1393) ---------- */
.res-cal__pick {
  position: relative;
}

.res-cal__pick-btn {
  gap: var(--cds-space-50);
}

.res-cal__pick-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 var(--cds-space-25);
  border-radius: var(--cds-radius-xsmall);
  background: var(--pp-primary-tint);
  color: var(--pp-primary);
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
}

/* A floating overlay is not a surface at rest: it is a state of the
   control that opened it, so it takes the one shadow the system has.
   Section 3's rule that nothing wears a shadow at rest is unchanged. */
.res-cal__menu {
  position: absolute;
  z-index: 5;
  top: calc(100% + var(--cds-space-25));
  right: 0;
  width: 264px;
  padding: var(--cds-space-75);
  border: 1px solid var(--pp-border-card);
  border-radius: var(--pp-card-radius);
  background: var(--cds-neutral-0);
  box-shadow: var(--pp-shadow-hover);
}

.res-cal__menu[hidden] {
  display: none;
}

.res-cal__menu-list {
  display: flex;
  flex-direction: column;
}

.res-cal__menu-foot {
  margin-top: var(--cds-space-50);
  padding-top: var(--cds-space-50);
  border-top: 1px solid var(--pp-border-divider);
}

/* A pick the filter has since excluded. It stays on the list so the
   pill's count is always something the menu shows, and it says why it
   draws nothing. */
.res-cal__menu-off {
  color: var(--pp-ink-secondary);
}

.res-cal__menu-note {
  margin-left: auto;
  padding-left: var(--cds-space-50);
  font-size: var(--pp-type-meta-size);
  color: var(--pp-ink-secondary);
  white-space: nowrap;
}

/* ---------- The grid ----------
   Providers are rows and days are columns, which is the shape the
   reference drew. The first column carries the identity and the row's
   actions, so a provider is still one reading across the row. */
/* The scroller sits in a static host so the clip edge can be marked
   from outside it: an overlay inside a scroll container scrolls with the
   content and would ride away from the edge it is meant to state. */
.res-cal__view {
  position: relative;
}

/* A clipped scroller says so. The mask is a state of the scroller, not
   elevation, so it is a gradient rather than a shadow and section 3's
   one-shadow rule is unchanged. */
.res-cal__view::after {
  content: "";
  position: absolute;
  z-index: 3;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--cds-space-200);
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to right, transparent, var(--cds-neutral-0));
  transition: opacity 150ms ease-out;
}

.res-cal__view[data-edge~="end"]::after {
  opacity: 1;
}

.res-cal__scroll {
  position: relative;
  overflow-x: auto;
  /* The identity column is pinned over the scroll port, so a chip the
     keyboard reaches in a column to the left of the fold would be
     scrolled to the port edge and land underneath it. The reserve is the
     column's maximum, which costs a little over-scroll and never hides
     the thing that was just focused. */
  scroll-padding-left: 300px;
}

/* The day columns take a maximum, so a one or two day search draws real
   columns rather than two 533px bands with a chip floating in each. The
   trailing track takes whatever is left, which keeps every row rule and
   every row wash running to the panel edge: section 9's rule that a cap
   inside a larger surface becomes a hole. */
.res-cal__grid {
  display: grid;
  grid-template-columns:
    minmax(236px, 300px)
    repeat(var(--cal-cols, 5), minmax(104px, 200px))
    1fr;
}

.res-cal__grid:empty {
  display: none;
}

/* ---------- The identity column holds still ----------
   The grid scrolls sideways as soon as a sixth day is checked, and the
   first column carries the whole reading: who the row is, what state it
   is in, and what can be done with it. Scrolled away, the grid is rows
   of anonymous times. So the identity column and its head pin to the
   left edge of the scroller and the day columns pass under them. */
.res-cal__corner,
.res-cal__prov,
.res-cal__acts {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--cds-neutral-0);
  border-right: 1px solid var(--pp-border-divider);
}

/* The pinned column already draws the boundary, so the first day column
   drops its own left rule and the seam stays one pixel wide. */
.res-cal__corner + .res-cal__week,
.res-cal__week + .res-cal__dayhead,
.res-cal__prov + .res-cal__cell {
  border-left: 0;
}

/* Scrolled off the left edge, the pinned column is over content rather
   than beside it, and the boundary takes the separator step to say so. */
.res-cal__view[data-edge~="start"] .res-cal__corner,
.res-cal__view[data-edge~="start"] .res-cal__prov,
.res-cal__view[data-edge~="start"] .res-cal__acts {
  border-right-color: var(--pp-ink-tertiary);
}

.res-cal__corner {
  grid-row: span 2;
  display: flex;
  align-items: flex-end;
  padding: var(--cds-space-50) var(--pp-card-pad) var(--cds-space-75);
  border-bottom: 1px solid var(--pp-border-divider);
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--pp-ink-secondary);
}

/* The two weeks are named, because a ten-column run of date numbers
   does not say on its own where one week ends and the next begins. */
.res-cal__week {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--cds-space-50);
  border-left: 1px solid var(--pp-border-divider);
  background: var(--cds-neutral-10);
  text-align: center;
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink-secondary);
  white-space: nowrap;
}

/* The window travels as a whole, so it can land on a week the current
   panel has no data for. An entire band of dashes reads as a fault; the
   band states the emptiness instead. */
.res-cal__week-note {
  font-weight: var(--cds-font-weight-regular);
}

.res-cal__dayhead {
  padding: var(--cds-space-50) var(--cds-space-25) var(--cds-space-75);
  border-left: 1px solid var(--pp-border-divider);
  border-bottom: 1px solid var(--pp-border-divider);
  text-align: center;
}

.res-cal__dayname {
  display: block;
  font-size: var(--pp-type-meta-size);
  font-weight: var(--cds-font-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--pp-ink-secondary);
}

.res-cal__daynum {
  display: block;
  margin-top: 2px;
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
  font-variant-numeric: tabular-nums;
}

/* Today is marked in the head only, which is what the Epic 1 grid does:
   a wash down the whole column would sit under the slot chips and make
   both of them muddy. */
.res-cal__dayhead--today {
  background: var(--pp-primary-tint-soft);
}

.res-cal__dayhead--today .res-cal__dayname,
.res-cal__dayhead--today .res-cal__daynum {
  color: var(--pp-primary);
}

/* Where the second week starts. The tertiary step is the separator job
   section 1 gives it, so the seam reads without a second rule weight. */
.res-cal__week + .res-cal__week,
.res-cal__dayhead--split,
.res-cal__cell--split {
  border-left-color: var(--pp-ink-tertiary);
}

/* The identity and the row's actions are two cells stacked in the same
   column rather than one cell holding both, so the row's DOM order is
   provider, times, Book. In the table the operator tabs provider, then
   the times, then Book; the calendar now reads the same way, instead of
   putting Book before any time there is to book. */
.res-cal__prov {
  padding: var(--cds-space-100) var(--pp-card-pad) 0;
}

/* The table holds a provider name on one line because that is what
   raises the column's min-content width and keeps the eight columns
   honest. Here the column is a capped track and the name has little
   room, so it wraps. */
.res-cal__prov .res__name {
  white-space: normal;
}

/* The panel-open rule above holds a name on one line to raise the
   TABLE column's min-content width. A grid track has no min-content to
   raise, so the same rule ran the name straight through the identity
   column and over the chevron. The calendar keeps wrapping in that
   state too. */
[data-crit-variant="b"][data-critleft="open"] .res-cal__prov .res__name {
  white-space: normal;
}

.res-cal__acts {
  padding: var(--cds-space-75) var(--pp-card-pad) var(--cds-space-100);
  border-bottom: 1px solid var(--pp-border-divider);
}

.res-cal__cell {
  grid-row: span 2;
  padding: var(--cds-space-100) var(--cds-space-50);
  border-left: 1px solid var(--pp-border-divider);
  border-bottom: 1px solid var(--pp-border-divider);
}

/* The track that takes the leftover width. It carries the row's rule and
   the row's wash and nothing else, so a sparse day selection still reads
   as a full-width surface. */
.res-cal__fill {
  border-bottom: 1px solid var(--pp-border-divider);
}

.res-cal__fill--band {
  background: var(--cds-neutral-10);
  border-bottom: 0;
}

/* The chips are the cell's whole content, so they centre in the column
   rather than hanging off its left rule. The drawer's day list keeps
   its own left alignment: there the chips sit under a day heading. */
/* One time to a line, at every width. Wrapping alone gave one chip a
   line at 1440 and paired them at 1920, so the same column read as a
   list on one screen and as a ragged grid on the other. A day column is
   a list of that provider's times and reads down. */
.res-cal__cell .slots {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 0;
}

/* A day the provider does not work is stated, not left blank, so an
   empty cell cannot read as a rendering fault. The mark is non-text,
   which is the other job the tertiary step carries. */
.res-cal__none {
  display: block;
  text-align: center;
  color: var(--pp-ink-tertiary);
}

/* The same four signals the table row carries. The wash runs the whole
   calendar row, provider cell and day cells together, because a row that
   changed has to be as legible while scanning a grid as it is while
   scanning a table. The values are the table's own. */
.res-cal__wash--booked {
  background: var(--cds-green-400-opacity-07);
}

.res-cal__wash--referred {
  background: var(--cds-neutral-50);
}

/* The referred wash is the neutral badge's own ground, so the Referred
   pill would stop reading as a pill. It takes the card white back, which
   is the rule the referred table row already keeps. */
.res-cal__wash--referred .cds-badge--neutral {
  background: var(--cds-neutral-0);
}

/* The same rule, the other half of it. The booked wash is 7 percent
   green on white and the Confirmed pill paints 7 percent green on white,
   so the two composite to the same value and the pill reads as loose
   text. It takes the card white back. Written for the table row as well
   as the calendar row, because the table had the defect first and the
   two surfaces have to state a booking the same way. */
.res tbody tr[data-booked-slot] .cds-badge--green,
.res-cal__wash--booked .cds-badge--green {
  background-image: none;
  background-color: var(--cds-neutral-0);
}

/* ============================================================
   E2-1 concept calendar, prototype only
   ------------------------------------------------------------
   The second version of the results calendar, behind the
   ?ver=concept switch, for the Sep 1 concept review: A2 Find
   Matching plus C1 Match Highlight on the grid B1 steps one
   week at a time. Every rule here is reached only through
   [data-cal-ver="concept"] or through markup the script writes
   on that path, so the current calendar above is untouched.

   These rules live beside the calendar they extend rather than
   in css/calendar.css: that file is the Epic 1 calendar family
   (screens 2, 3 and 4) and is loaded by thirty other screens,
   while every .res-cal rule this concept builds on is here.
   ============================================================ */

/* The version pill group. It reuses .vswitch, which is fixed to the
   rail foot for the A/B/C switcher, so the calendar's own copy is put
   back in the flow at the left end of the toolbar. The two-class
   selector is what wins against the base rule further up this file. */
.res-cal .vswitch--cal {
  position: static;
  flex-direction: row;
  width: auto;
  padding: var(--cds-space-25);
  gap: var(--cds-space-25);
}

.res-cal .vswitch--cal .vswitch__btn {
  width: auto;
  height: 24px;
  padding: 0 var(--cds-space-75);
  border-radius: var(--cds-radius-btn-small);
  font-size: var(--pp-type-meta-size);
}

/* ---------- C1 match highlight ----------
   Emphasis, not disabling. The chip keeps its tint, its pointer, its
   hover step and its place in the tab ring; what it loses is weight,
   and it takes all of it back the moment it is hovered or focused, so
   nothing here can be read as a switched-off control.

   The weight it loses is the hue first and the wash second. A single
   0.42 fade carried the whole job and took the label to 1.85:1, which
   is a bookable control that cannot be read at rest. The hue is what
   the grid uses to say "match", so dropping it to body ink is the
   de-emphasis that costs the least legibility: composited, the label
   reads 3.7:1 on an open cell and on a quieted one. */
.res-cal__chip--dim {
  opacity: 0.6;
  color: var(--pp-ink);
}

.res-cal__chip--dim:hover,
.res-cal__chip--dim:focus-visible {
  opacity: 1;
  color: var(--pp-primary);
}

/* A cell with nothing in it that matches quiets as a whole, which is
   what lets a searched weekday outside the pattern read as one block
   rather than as a column of separately faded chips. */
.res-cal__cell--dim {
  background: var(--cds-neutral-10);
}

/* 343:1328's badge, in the pinned column under the name. The neutral
   badge is the shape the status slot beside it already uses, so the
   column gains a reading and not a new component. */
.res-cal__match {
  align-self: flex-start;
  margin-top: var(--cds-space-25);
}

.res-cal__match[hidden] {
  display: none;
}

/* A2's one control in the grid. It sits under the chip it belongs to,
   inside the selected cell, and is the quiet button the page already
   has rather than a second call to action in a cell.

   It is measured against the cell and not against its own label. The
   first build left the button at its intrinsic width (a 14px label in
   the medium button's 16px side padding, 127px) inside a 106px column,
   so it hung 28px into the next day, the day rule ran through the word
   and the neighbouring cell painted over the overhang: the right third
   of the button took no pointer at all. Width is therefore the cell's,
   the label wraps rather than pushing the box out, and the height comes
   off the content instead of the medium button's fixed 40px. */
.res-cal__find {
  display: flex;
  width: 100%;
  height: auto;
  min-height: 24px;
  margin: var(--cds-space-50) 0 0;
  padding: var(--cds-space-25);
  font-size: var(--pp-type-meta-size);
  line-height: 1.25;
  white-space: normal;
  text-align: center;
}

/* The fourth legend swatch, the concept's only new state. It is the
   open chip at full strength, which is exactly what the grid says a
   match is: everything that does not match steps back from it. */
.wk-legend__item--match {
  display: none;
}

[data-cal-ver="concept"][data-res-view="calendar"] .wk-legend__item--match {
  display: inline-flex;
}

/* The swatch is the open chip's own fill and border, the two values
   .slot-chip sets, because a matching chip is the open chip: what the
   concept changes is everything around it. The first build keyed this
   item to a stronger blue than the grid draws anywhere, so the key
   pointed at a chip that does not exist. */
.wk-legend__swatch--match {
  background: var(--pp-primary-tint-soft);
  border-color: var(--pp-primary-100);
}

/* The counter's second half puts a comma in a string that is set in
   tabular figures, and in HN for TELUS the tabular set gives the comma
   a digit-wide advance, so "Providers, 0 Match" renders as
   "Providers ,  0 Match". The current version's sentence carries no
   punctuation and keeps the tabular set it has always had; the concept
   version's sentence does, so it takes the proportional set. */
[data-cal-ver="concept"] .res-cal__showing {
  font-variant-numeric: normal;
}

/* ---------- A2 proposed series ----------
   Inline under the grid and never a popover: the accordion panel inner
   in this build has overflow:hidden for its open and close animation,
   so a popover raised out of a cell would be clipped. */
.cal-series {
  padding: var(--cds-space-100) var(--pp-card-pad) var(--cds-space-150);
  border-top: 1px solid var(--pp-border-divider);
}

.cal-series[hidden] {
  display: none;
}

.cal-series__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cds-space-100);
  padding-bottom: var(--cds-space-75);
}

.cal-series__title {
  margin: 0;
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

/* The count carries the series length, which is where the concept
   states that the length is fixed at six. Number Of Appointments is a
   parked change-queue item and is deliberately not drawn as a field. */
.cal-series__count {
  font-size: var(--pp-type-body-size);
  color: var(--pp-ink-secondary);
}

.cal-series__count[hidden],
.cal-series__done[hidden],
.cal-series__rows[hidden],
.cal-series__foot[hidden] {
  display: none;
}

.cal-series__rows {
  display: flex;
  flex-direction: column;
}

/* One row per week, on one grid so the week, the date and the time
   line up down the panel instead of ragging with the content. */
.cal-series__row {
  display: grid;
  grid-template-columns: 160px 180px minmax(96px, auto) 1fr;
  align-items: center;
  gap: var(--cds-space-100);
  padding: var(--cds-space-75) 0;
  border-top: 1px solid var(--pp-border-divider);
  font-size: var(--pp-type-body-size);
}

.cal-series__wk {
  font-weight: var(--cds-font-weight-semibold);
  color: var(--pp-ink);
}

.cal-series__date {
  color: var(--pp-ink-secondary);
}

/* A week the series cannot land on is quieter than one it can, and it
   still says which week it is, so the gap is a fact on the row rather
   than a row that never appears. */
.cal-series__row--gap .cal-series__wk,
.cal-series__row--gap .cal-series__date {
  color: var(--pp-ink-tertiary);
  font-weight: var(--cds-font-weight-regular);
}

.cal-series__gap {
  color: var(--pp-ink-tertiary);
}

/* Alternatives is a grid item in the row's free track, so it stretched
   the whole 733px of it and put a centred label some 380px right of the
   week it belongs to, over a clickable band of empty row. It sizes to
   its label and sits against the gap text it answers. */
.cal-series__row [data-cal-series-alt] {
  justify-self: start;
}

/* The panel's chips are readouts of slots the grid is already showing
   held, so they take the chip's shape without its behaviour. */
.cal-series__chip {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  cursor: default;
}

.cal-series__done {
  margin: 0;
  padding-top: var(--cds-space-75);
  border-top: 1px solid var(--pp-border-divider);
  font-size: var(--pp-type-body-size);
  font-weight: var(--cds-font-weight-semibold);
  color: var(--cds-green-400);
}

.cal-series__foot {
  display: flex;
  align-items: center;
  gap: var(--cds-space-100);
  padding-top: var(--cds-space-150);
}

/* The series hold and the series confirmation take the page's own two
   slot states, the same values the legend keys and the same values the
   single-slot hold and booking already paint. They are written after
   the disabled rule above on purpose: a confirmed series sits on a
   booked row, whose other chips are switched off. */
.slot-chip[data-series="held"],
.slot-chip[data-series="held"]:disabled {
  background: var(--cds-orange-50-opacity-15);
  border-color: var(--cds-orange-350);
  color: var(--cds-orange-400);
}

.slot-chip[data-series="confirmed"],
.slot-chip[data-series="confirmed"]:disabled {
  background: var(--cds-green-400-opacity-07);
  border-color: var(--cds-green-400);
  color: var(--cds-green-400);
}

/* A slot the series is holding is never dimmed: it is the answer the
   pattern was asked for. */
.slot-chip[data-series] {
  opacity: 1;
}
