/* ===========================================================================
   ui-core.css — scaffolding shared by every style

   Three things live here, because all four styles must agree on them:

     1. THE CONTAINER. One centred rail. 84% of the viewport capped at 1480px
        on desktop; below 1100px the full available width with 24px gutters;
        16px gutters on phones. The logo, toolbar, progress bar, booking cards
        and sticky bar are all driven by it, so they cannot drift apart.

     2. THE TEXT SIZE SCALE. Standard / Large / Extra large at 100 / 112.5 /
        125%, applied as real typography — the root font size changes and the
        styles are authored in rem, so cards and controls grow with the text
        instead of being magnified. No browser zoom, no transform.

     3. THE TOOLBAR CONTROLS. "Choose your style" and "Text size", styled from
        the --ui-* contract so each style can restyle them without forking the
        markup.

   HOW A STYLE PLUGS IN
       <html data-ui="classic|signature|futuristic|showcase" data-text="std|lg|xl">
   Every style sheet scopes all of its rules under html[data-ui="<id>"], and
   all of them load up front. Switching either control is one attribute write:
   nothing re-renders, nothing is fetched, nothing navigates — which is why a
   switch mid-booking cannot disturb the engine's state.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. THE CONTAINER
   --------------------------------------------------------------------------- */
:root {
  --ui-rail-max: 1350px;
  --ui-rail-pct: 84%;
  --ui-gutter: 24px;
  /* Side margin on desktop. 2026-09-15: the rail was 84% of the viewport, which
     left 115px of empty margin each side at 1440 and 102px at 1280 - more than
     the content needed. It became the full width less a margin scaling from
     32px to 56px, capped at 1480px (1280 -> 1203px, 1440 -> 1354px,
     1920 -> 1480px).

     2026-09-17 (round 5): that read too wide, so every rail comes in by about
     9%. The margin is now a percentage of the viewport rather than a near-fixed
     number, which keeps the reduction proportional instead of shrinking narrow
     screens more than wide ones, and the cap drops to 1350px so the very widest
     screens come in by the same proportion.
     Measured: 1280 -> 1095px (-9.0%), 1440 -> 1232px (-9.0%), 1920 -> 1350px
     (-8.8%). Below 1101px the gutter rule takes over and phones are unchanged. */
  --ui-side: clamp(32px, 7.2vw, 140px);
  /* The single source of truth for every aligned edge on the page. */
  --ui-rail: min(calc(100% - (var(--ui-side) * 2)), var(--ui-rail-max));
  --ui-nav-h: 82px;

  /* Logo box. ~35% larger than the previous 156x48. The toolbar reserves
     --ui-logo-w plus a gap, so enlarging the logo never lets it slide under
     the navigation. */
  --ui-logo-w: 210px;
  --ui-logo-h: 65px;
  --ui-logo-gap: 28px;
}

/* Two fixes for one symptom: the fixed-position logo sitting a pixel or two
   off the container's left edge.

   `scrollbar-gutter: stable` makes the layout viewport a constant width, so
   the logo (positioned against the viewport) and the container (sized against
   the body) start from the same number.

   `overflow-x: clip` replaces the baseline's `overflow-x: hidden` on body.
   Setting overflow-x:hidden forces the computed overflow-y to `auto`, which
   made body its own scroll container and reserved a SECOND scrollbar inside
   the page — measured: body content box 1410px inside a 1425px viewport. That
   is what put the logo 1.2px out, and it also meant the page carried a nested
   scroll area nobody asked for. `clip` suppresses horizontal overflow without
   turning the element into a scroll container, so body is a full 1425px and
   the two edges resolve identically.

   The gutter is reserved only above 1100px, which is exactly where the logo is
   position:fixed and the two bases have to agree. Below that the logo is back
   in the flow and needs no help, and reserving a gutter there would push the
   right margin 15px wider than the left — visibly off-centre on a phone. */
@media (min-width: 1101px) {
  html { scrollbar-gutter: stable; }
}
html[data-ui] body { overflow-x: clip; }

@media (max-width: 1100px) {
  :root { --ui-rail: calc(100% - (var(--ui-gutter) * 2)); }
}
@media (max-width: 560px) {
  :root { --ui-gutter: 16px; }
}

/* The baseline sets .container max-width:1100px, .ab-progress-inner 1100px and
   .stickyCtaInner 1120px — three different rails plus a floating logo. These
   replace all of them. Written with html + attribute so they outrank the
   baseline's bare class selectors in every style. */
html[data-ui] .container {
  width: var(--ui-rail);
  max-width: none;
  margin-inline: auto;
  padding-left: 0;
  padding-right: 0;
  padding-top: 0;
  padding-bottom: 120px;
}

html[data-ui] .ab-progress-inner {
  width: 100%;
  max-width: none;
  margin: 0;
  padding-inline: 0;
}

html[data-ui] .stickyCtaInner {
  width: var(--ui-rail);
  max-width: none;
  margin-inline: auto;
}

/* 2026-09-17: --ui-rail is a percentage of its containing block, and the sticky
   bar carried 12px of its own horizontal padding - so its rail resolved against
   1401px where every other rail resolved against 1425px, and the summary sat
   24px narrower than the panels above it. Dropping that padding puts the sticky
   bar on the same base as the container, which is what makes one rail actually
   mean one rail. */
html[data-ui] .stickyCta { padding-inline: 0; }

/* The logo is declared outside .container and positioned fixed, so it cannot
   join the toolbar's flex row. Pinning its left edge to the rail's left edge
   lines it up with content it is not a sibling of.
   `%` not `vw`: vw includes the scrollbar and % does not, which otherwise
   leaves the logo a few pixels out of step with the container.

   LOGO SIZE. Raised ~35% on 2026-09-13 (156x48 -> 210x65) so a real customer
   wordmark has room to be legible instead of shrinking to fit. `contain` keeps
   the aspect ratio whatever shape the file is, and the toolbar's padding-left
   is derived from the same width below, so a bigger logo pushes the nav
   controls across rather than sliding underneath them. */
html[data-ui] body { position: relative; }
html[data-ui] .siteLogoLink {
  /* Absolute, not fixed. At the old 156x48 a fixed logo was small enough to
     sit above everything harmlessly; at 210x65 it overlapped the sticky
     progress bar as soon as the page scrolled. Absolute keeps it in the header
     where it belongs and lets the sticky bars own the top of the viewport.
     It also improves alignment: positioned against body, its percentages
     resolve against the same box that centres .container. */
  position: absolute;
  top: 8px;
  left: calc((100% - var(--ui-rail)) / 2);
  right: auto;
  width: var(--ui-logo-w);
  height: var(--ui-logo-h);
  background-position: left center;
  background-size: contain;
  background-repeat: no-repeat;
  border-radius: 8px;
  z-index: 61;
}

/* The toolbar clears the fixed logo and keeps its own controls on the rail.
   booking.html calls this row .topbar; my-bookings.html calls it .nav. Both
   need the same clearance or the fixed logo overlaps their first item. */
html[data-ui] .topbar,
html[data-ui] .container > .nav {
  min-height: var(--ui-nav-h);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  padding-left: calc(var(--ui-logo-w) + var(--ui-logo-gap));
}

/* Below 1100px the logo returns to the flow above the controls: at that width
   a logo plus two multi-option controls cannot share one row without wrapping
   into something unreadable. */
@media (max-width: 1100px) {
  html[data-ui] .siteLogoLink {
    position: relative !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    display: block !important;
    width: 200px !important;
    height: 62px !important;
    margin: 12px 0 0 var(--ui-gutter) !important;
    background-position: left center !important;
  }
  html[data-ui] .topbar,
  html[data-ui] .container > .nav {
    padding-left: 0;
    justify-content: flex-start;
    min-height: 0;
    padding-block: 8px;
  }
  html[data-ui] .topbar .actions { margin-left: auto; }
  /* The baseline reserves room for the old floating logo; it is in the flow now. */
  html[data-ui] .siteLogoLink ~ .container { padding-top: 0 !important; }
}

/* ---------------------------------------------------------------------------
   2. THE TEXT SIZE SCALE

   `100%` on the root element resolves to the browser's own default, so a
   visitor who has already raised their default keeps that and this multiplies
   it rather than overriding it. Styles are authored in rem, so every size,
   and the padding expressed in rem with it, grows together.
   --------------------------------------------------------------------------- */
:root { --ui-ts: 1; }
html[data-text="lg"] { --ui-ts: 1.125; }
html[data-text="xl"] { --ui-ts: 1.25; }

html { font-size: calc(100% * var(--ui-ts)); }

/* Classic is the exception: assets/booking.css declares 74 font sizes and all
   of them are px, so raising the root size does nothing there. These restate
   the ones that carry text, multiplied by the same factor. The px values are
   the baseline's own — taken from booking.css and styles.css, not invented —
   so at Standard they compute back to exactly what Classic renders today. */
html[data-ui="classic"] {
  --c-12: calc(12px * var(--ui-ts));
  --c-13: calc(13px * var(--ui-ts));
  --c-14: calc(14px * var(--ui-ts));
  --c-15: calc(15px * var(--ui-ts));
  --c-16: calc(16px * var(--ui-ts));
  --c-18: calc(18px * var(--ui-ts));
  --c-20: calc(20px * var(--ui-ts));
  --c-22: calc(22px * var(--ui-ts));
  --c-34: calc(34px * var(--ui-ts));
}
html[data-ui="classic"] body { font-size: var(--c-16); }
html[data-ui="classic"] .small,
html[data-ui="classic"] label,
html[data-ui="classic"] .apptDateLabel,
html[data-ui="classic"] .svcSub,
html[data-ui="classic"] .svcChip,
html[data-ui="classic"] .empMeta,
html[data-ui="classic"] .badge,
html[data-ui="classic"] .pill .svcMeta { font-size: var(--c-12); }
html[data-ui="classic"] .sub,
html[data-ui="classic"] .ab-label,
html[data-ui="classic"] .ab-dot,
html[data-ui="classic"] .dateNotice,
html[data-ui="classic"] .msgSubtitle,
html[data-ui="classic"] .modalSubPro,
html[data-ui="classic"] .welcomeNote .welcomeSub,
html[data-ui="classic"] .pill .svcName { font-size: var(--c-13); }
html[data-ui="classic"] .svcTitle,
html[data-ui="classic"] .userPill,
html[data-ui="classic"] #datePretty { font-size: var(--c-14); }
html[data-ui="classic"] .msgBody,
html[data-ui="classic"] .thankNote { font-size: var(--c-15); }
html[data-ui="classic"] .btn,
html[data-ui="classic"] .thankLead,
html[data-ui="classic"] input[type="text"],
html[data-ui="classic"] .svcSearch { font-size: var(--c-16); }
/* booking.css:641 sets these three at 16px !important, so matching that weight
   is the only way the scale can reach them. */
html[data-ui="classic"] #loginBtn,
html[data-ui="classic"] #myBookingsBtn,
html[data-ui="classic"] #logoutBtn { font-size: var(--c-16) !important; }
html[data-ui="classic"] .card h2,
html[data-ui="classic"] .empName { font-size: var(--c-18); }
html[data-ui="classic"] .msgTitle { font-size: var(--c-20); }
html[data-ui="classic"] .modalTitlePro { font-size: var(--c-22); }
html[data-ui="classic"] .thankTitle { font-size: var(--c-34); }
html[data-ui="classic"] .slotgrid button,
html[data-ui="classic"] #employeeList,
html[data-ui="classic"] #totalDuration,
html[data-ui="classic"] #totalPrice,
html[data-ui="classic"] .reviewBox,
html[data-ui="classic"] #stickyServices,
html[data-ui="classic"] #stickyDate { font-size: var(--c-14); }

/* booking.css:668 sets `#date { font-size: 16px !important }` — and 14px in a
   media query — so the date field is the one control the scale cannot reach by
   inheritance, in any style. Each style sets --ui-date-fs to whatever suits it;
   the default tracks the root, so it scales either way. */
html[data-ui] #date { font-size: var(--ui-date-fs, 1rem) !important; }
html[data-ui="classic"] { --ui-date-fs: var(--c-16); }

/* Text fields need the same treatment for a different reason: booking.html
   writes <input id="custName"> with no type attribute, so `input[type="text"]`
   never matches it and it falls back to the UA's own 13.33px, which no scale
   can reach. Targeting the element itself fixes all three fields at once. */
html[data-ui] input,
html[data-ui] select,
html[data-ui] textarea { font-size: var(--ui-field-fs, 1rem); }
html[data-ui="classic"] { --ui-field-fs: var(--c-16); }

/* styles.css:357 keeps controls at 16px under 560px so iOS Safari does not zoom
   the page on focus. Scaling must not undercut that, so the small-screen value
   is a floor rather than a replacement. */
@media (max-width: 560px) {
  html[data-ui] input,
  html[data-ui] select,
  html[data-ui] textarea { font-size: max(1rem, var(--ui-field-fs, 1rem)); }
}

/* At the two larger sizes a service row needs more room than a three-column
   grid can give it, in every style. Dropping a column is what keeps names and
   prices from clipping — the requirement's "reduce columns when needed". */
html[data-text="lg"] .svcGroupBody .svcGrid,
html[data-text="lg"] #serviceList .svcGrid,
html[data-text="lg"] .pills.svcGrid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
html[data-text="xl"] .svcGroupBody .svcGrid,
html[data-text="xl"] #serviceList .svcGrid,
html[data-text="xl"] .pills.svcGrid { grid-template-columns: 1fr !important; }
@media (max-width: 900px) {
  html[data-text="lg"] .svcGroupBody .svcGrid,
  html[data-text="lg"] #serviceList .svcGrid,
  html[data-text="lg"] .pills.svcGrid { grid-template-columns: 1fr !important; }
}

/* auth.html's sign-in panel is also called .card, and the styles' own .card
   rules are written for booking.html's step cards — Minimal deliberately makes
   those transparent and square, which erased the sign-in panel entirely.
   Re-asserting it here from the --auth-* tokens keeps one owner for that
   surface and stops each style having to remember the collision.
   Specificity (0,2,2) clears the per-style html[data-ui="x"] .card at (0,2,1). */
html[data-ui] .wrap > .card {
  background: var(--auth-surface, #fff) !important;
  border: 1px solid var(--auth-line, rgba(2,6,23,.10)) !important;
  border-radius: var(--auth-radius, 14px) !important;
  box-shadow: var(--auth-shadow, 0 10px 30px rgba(2,6,23,.08)) !important;
  padding: 22px !important;
  margin-top: 0 !important;
}

/* Respect the OS setting everywhere, including styles added later. */
@media (prefers-reduced-motion: reduce) {
  html[data-ui] *,
  html[data-ui] *::before,
  html[data-ui] *::after { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------------------
   3. TOOLBAR CONTROLS
   Style-agnostic: they read only the --ui-* contract, so each style restyles
   them by setting tokens rather than by rewriting these rules.
   --------------------------------------------------------------------------- */
:root {
  --ui-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --ui-ink: #0f172a;
  --ui-ink-soft: #5b6b7b;
  --ui-surface: #ffffff;
  --ui-line: rgba(15, 23, 42, .12);
  --ui-accent: #2563eb;
  --ui-accent-ink: #ffffff;
  --ui-accent-soft: rgba(37, 99, 235, .10);
  --ui-radius-pill: 999px;
  --ui-shadow: 0 10px 26px rgba(15, 23, 42, .08);
  --ui-ring: 0 0 0 3px rgba(37, 99, 235, .35);
  --ui-speed: 160ms;
}

/* The two groups may wrap relative to each other, but a group must never split
   across lines — a segmented control with one option on the next row reads as
   two separate controls. */
.uiControls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  flex-wrap: wrap;
}

.uiStyleBar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
}
.uiStyleSeg { flex-wrap: nowrap; }

/* At Extra large the two labels cost roughly 200px and push the toolbar onto a
   second and third row at 1440. The buttons read as "Classic" / "Signature" /
   "A" on their own, and each group keeps its accessible name through
   aria-labelledby, so the visible labels are the right thing to drop first. */
html[data-text="xl"] .uiStyleBar__label { display: none; }

.uiStyleBar__label {
  font-family: var(--ui-font);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ui-ink-soft);
  white-space: nowrap;
}

.uiStyleSeg {
  display: inline-flex;
  padding: 3px;
  gap: 3px;
  background: var(--ui-accent-soft);
  border: 1px solid var(--ui-line);
  border-radius: var(--ui-radius-pill);
}

.uiStyleBtn {
  appearance: none;
  border: 0;
  cursor: pointer;
  font-family: var(--ui-font);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1;
  padding: 0.5rem 0.75rem;
  border-radius: var(--ui-radius-pill);
  background: transparent;
  color: var(--ui-ink-soft);
  white-space: nowrap;
  min-height: 2.125rem;
  transition: background var(--ui-speed), color var(--ui-speed);
}
.uiStyleBtn:hover { color: var(--ui-ink); }
.uiStyleBtn[aria-pressed="true"] {
  background: var(--ui-surface);
  color: var(--ui-ink);
  box-shadow: var(--ui-shadow);
}
.uiStyleBtn:focus-visible { outline: none; box-shadow: var(--ui-ring); }

/* The text-size control uses the same geometry but labels sized A / A / A so
   the option itself demonstrates what it does. */
.uiTextBtn .abbr { font-weight: 800; }
.uiTextBtn[data-text-id="std"] .abbr { font-size: 0.8125rem; }
.uiTextBtn[data-text-id="lg"]  .abbr { font-size: 0.9375rem; }
.uiTextBtn[data-text-id="xl"]  .abbr { font-size: 1.0625rem; }

.uiSrOnly {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Two labelled controls plus two nav buttons will not fit one row on a phone.
   The labels go first — the buttons say "Classic", "Signature", "A" and are
   legible without them, and each group keeps its accessible name. */
@media (max-width: 760px) {
  .uiStyleBar__label { display: none; }
  .uiControls { gap: 10px; justify-content: flex-start; }
}

/* Four style options at Extra large do not fit 343px, and a nowrap group in a
   flex-end row overflows to the LEFT — where body's overflow-x:clip silently
   cuts the first option in half ("lassic"). Below 760px the group is allowed
   to wrap onto a second line instead. Two tidy rows beat a clipped control,
   and the rule is scoped so wide screens keep every group on one line. */
@media (max-width: 760px) {
  .uiControls { flex-wrap: wrap; max-width: 100%; min-width: 0; }
  .uiStyleBar { flex-wrap: wrap; min-width: 0; max-width: 100%; }
  .uiStyleSeg { flex-wrap: wrap; }
}

/* ---------------------------------------------------------------------------
   "Show me the admin console"

   A customer-facing invitation sitting in a row of system buttons (Log in, My
   bookings, Log out). Those are all .btn, so a plain .btn here would disappear
   into them and the brief asks for this one to be clearly visible. It takes
   the theme's own accent as an outline rather than a fill, so it reads as the
   one optional thing in the row without competing with the primary booking
   action further down the page.

   Each theme publishes --ui-accent as part of the toolbar contract, so this
   picks up the right colour in all four with no per-theme rule. The fallback
   is the baseline blue, so it still looks deliberate before a theme loads.
   --------------------------------------------------------------------------- */
html[data-ui] .demoConsoleBtn {
  --dcb: var(--ui-accent, #2563eb);
  border: 1px solid var(--dcb) !important;
  color: var(--dcb) !important;
  background: transparent !important;
  font-weight: 600;
  white-space: nowrap;
}
html[data-ui] .demoConsoleBtn::before {
  content: "";
  display: inline-block;
  width: .5em; height: .5em;
  margin-right: .5em;
  border-radius: 50%;
  background: var(--dcb);
  vertical-align: baseline;
}
html[data-ui] .demoConsoleBtn:hover {
  background: color-mix(in srgb, var(--dcb) 12%, transparent) !important;
}
html[data-ui] .demoConsoleBtn:focus-visible {
  outline: 2px solid var(--dcb);
  outline-offset: 2px;
}

/* The action row already wraps; at phone width the longest label in it is this
   one, so it gets the whole line rather than squeezing the others. */
@media (max-width: 620px) {
  html[data-ui] .demoConsoleBtn { flex-basis: 100%; text-align: center; }
}

/* ---------------------------------------------------------------------------
   The availability panel — why there are no times, and what to do next.

   Replaces a modal that said "Fully booked" for every empty slot list. It sits
   under the slot grid rather than over the page, because it is an explanation
   of what is on screen, not an interruption of it.

   Built entirely from the tokens each theme already publishes, so all four get
   it without a rule of their own and none of the approved designs changes. The
   tone colours are the semantic ones the baseline already defines (--ok,
   --warn, --danger); only the surface tint is derived here.
   --------------------------------------------------------------------------- */
html[data-ui] .availPanel {
  margin-top: 12px;
  padding: 14px 16px;
  border-radius: var(--radius, 12px);
  border: 1px solid var(--border, rgba(15, 23, 42, .14));
  background: var(--card, #fff);
  color: var(--text, #0f172a);
  line-height: 1.5;
}
html[data-ui] .availPanel[hidden] { display: none; }

html[data-ui] .availMsg {
  font-weight: 700;
  font-size: 1rem;
}
html[data-ui] .availDetail {
  margin-top: 6px;
  font-size: .9rem;
  color: var(--muted, #64748b);
}
html[data-ui] .availActions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}
html[data-ui] .availActions:empty { display: none; }

/* Per-person reasons (2026-09-15 round 2): one verified line per colleague. */
html[data-ui] .availLinesTitle { margin-top: 10px; font-size: .85rem; font-weight: 700; color: var(--muted, #64748b); }
html[data-ui] .availLines { margin: 6px 0 0; padding: 0; list-style: none; display: grid; gap: 6px; }
html[data-ui] .availLine {
  position: relative; padding-left: 18px; font-size: .92rem; line-height: 1.45; overflow-wrap: anywhere;
}
html[data-ui] .availLine::before {
  content: ""; position: absolute; left: 2px; top: .55em; width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted, #94a3b8);
}
html[data-ui] .availLine--available::before { background: var(--ok, #10b981); }

/* A 4px edge carries the tone, so the panel reads at a glance without four
   different background colours fighting whichever theme is loaded. */
html[data-ui] .availPanel--info   { border-left: 4px solid var(--accent, #2563eb); }
html[data-ui] .availPanel--ok     { border-left: 4px solid var(--ok, #10b981); }
html[data-ui] .availPanel--warn   { border-left: 4px solid var(--warn, #f59e0b); }
html[data-ui] .availPanel--error  { border-left: 4px solid var(--danger, #ef4444); }

/* Futuristic is the one theme dark enough that a plain --card surface would
   vanish into the page behind it.

   Only the three neutral edges are restated. Setting the shorthand
   border-color here would also overwrite the tone edge on the left, because
   this rule comes after the tone rules and carries the same specificity - the
   panel then loses the one thing that says at a glance whether it is an error
   or a closure. */
html[data-ui="futuristic"] .availPanel {
  background: var(--l2, #152a44);
  border-top-color: var(--edge, rgba(148, 197, 232, .16));
  border-right-color: var(--edge, rgba(148, 197, 232, .16));
  border-bottom-color: var(--edge, rgba(148, 197, 232, .16));
  box-shadow: var(--hi, inset 0 1px 0 rgba(255, 255, 255, .06));
}

@media (max-width: 620px) {
  html[data-ui] .availActions { flex-direction: column; align-items: stretch; }
  html[data-ui] .availActions .btn { width: 100%; }
}

/* ---------------------------------------------------------------------------
   Staff photos in Step 2 (2026-09-15)
   Each style sizes .empAvatar for an initials tile. A photo needs more room to
   read as a face, and must crop rather than squash. `img.empAvatar` outranks
   the style rules, so the initials fallback keeps each style's own tile.
   --------------------------------------------------------------------------- */
/* 2026-09-15 round 2: photographic portraits. Faces need real size to be
   recognisable, so every style shows them at 84px (72px on phones, 64px under
   380px). Pixel sizes on purpose: larger text sizes enlarge the words beside
   the photo, not the photo, so the staff details keep their room. */
html[data-ui] #employeeList img.empAvatar {
  display: block;
  width: 84px;
  height: 84px;
  object-fit: cover;
  object-position: center 35%;
  padding: 0;
  background: #e2e8f0;
  flex: none;
  border-radius: 50%;
}
html[data-ui="signature"]  #employeeList img.empAvatar { border-radius: 18px; }
html[data-ui="futuristic"] #employeeList img.empAvatar { border-radius: 16px; border: 1px solid rgba(34, 211, 238, .38); background: #0b1a2a; }
html[data-ui="showcase"]   #employeeList img.empAvatar { border: 3px solid #fff; background: #ede9fe; box-shadow: 0 4px 14px rgba(109, 40, 217, .22); }
@media (max-width: 620px) {
  html[data-ui] #employeeList img.empAvatar { width: 72px; height: 72px; }
}
@media (max-width: 380px) {
  html[data-ui] #employeeList img.empAvatar { width: 64px; height: 64px; }
}
/* A disabled or unavailable card dims its portrait with the rest of the card. */
html[data-ui] #employeeList .empCard[aria-disabled="true"] img.empAvatar { filter: grayscale(.6); opacity: .7; }

/* Staff cards are focusable toggle buttons (booking.staff.js, 2026-09-15).
   ui-interaction.css removes the outline on the selected card, so the focus
   ring is restated here with higher specificity - keyboard focus must stay
   visible whether or not the card is the selected one. */
html[data-ui] #employeeList .empCard:focus { outline: none; }
html[data-ui] #employeeList .empCard:focus-visible,
html[data-ui] #employeeList .empCard.on:focus-visible {
  outline: 3px solid var(--ui-focus, #2563eb) !important;
  outline-offset: 3px !important;
}
html[data-ui="futuristic"] #employeeList .empCard:focus-visible,
html[data-ui="futuristic"] #employeeList .empCard.on:focus-visible { outline-color: #67e8f9 !important; }

/* Staff card breathing room (2026-09-15 round 2). The selected mark sits in
   the card's top-right corner (ui-interaction.css). Classic gave cards no
   right padding, so with the larger portraits the name ran under the mark on
   phones. Every style now reserves the mark's width, and long names wrap. */
html[data-ui] #employeeList .empCard { padding-right: calc(var(--fx-mark, 1.15rem) + 1.1rem) !important; }
html[data-ui="classic"] #employeeList .empCard { padding-left: .5rem; padding-top: .5rem; padding-bottom: .5rem; }
html[data-ui] #employeeList .empInfo { min-width: 0; }
html[data-ui] #employeeList .empName,
html[data-ui] #employeeList .empMeta { overflow-wrap: anywhere; }
