/**
 * Red Orchid — Section Library stylesheet (issue #32)
 * ============================================================
 * Ported from the owner-approved prototype
 * (.dev/prototypes/section-service-hero-soft-ui/index.html — approved
 * through 6 review rounds, issue #31) into production. Consumes only
 * design-system/tokens.css semantics — never a raw hex.
 *
 * Scope of this file for now: the global button/badge/chip/coin atoms
 * (spec sheet 9 — every future section reuses these) + the Hero Banner
 * section (issue #32's mandated pilot). Later section-library issues add
 * their own block below, each labeled with its issue number, same
 * pattern as design-system/page-skins.css.
 *
 * Locked rule carried from tokens.css: NO transform motion on hover
 * (shadow/border/brightness/background only); :active press-scale is
 * fine; prefers-reduced-motion zeroes all of it and disables auto-advance.
 */

/* ============================================================
   ATOMS — buttons, badges, chips, coins (spec sheet 9)
============================================================ */
.ro-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--ro-font-sans); font-weight: 700; font-size: 15px; /* intentional middle step: no 15px role tier */
  padding: 13px 26px; border-radius: var(--ro-radius-control);
  border: 1px solid transparent; cursor: pointer; text-decoration: none;
  min-height: 48px;
  transition: box-shadow var(--ro-dur) var(--ro-ease),
              border-color var(--ro-dur) var(--ro-ease),
              background-color var(--ro-dur) var(--ro-ease),
              filter var(--ro-dur) var(--ro-ease);
}
.ro-btn:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-btn:active { transform: scale(.97); }
.ro-btn svg { width: 18px; height: 18px; flex: none; }

.ro-btn--primary {
  background: linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%);
  color: #fff; box-shadow: var(--ro-shadow-btn);
}
/* color re-asserted on :hover (not just the shadow/filter), and every
   selector below doubles up on classes (.ro-btn.ro-btn--primary:hover,
   not just .ro-btn--primary:hover) on purpose. Two real conflicts exist
   site-wide on <a> hover color: the theme's base `a:hover{color}` (element
   + pseudo-class) and Elementor's own Kit re-point `.elementor-kit-15
   a:hover{color}` (class + element + pseudo-class) — the second one's
   specificity (0,2,1) already beats a single-class hover rule (0,2,0).
   Two joined classes + :hover = (0,3,0), which beats both regardless of
   their element-count. Confirmed live by diffing matched CSS rules
   against the Book Now button, not guesswork. Same pattern as the
   pre-existing .deal-ribbon a:hover fix below. */
.ro-btn.ro-btn--primary:hover { color: #fff; box-shadow: var(--ro-shadow-btn-hover); filter: brightness(1.05); }

.ro-btn--secondary {
  background: var(--ro-surface); color: var(--ro-primary-text);
  border-color: var(--ro-border); box-shadow: var(--ro-shadow-card);
}
.ro-btn.ro-btn--secondary:hover { color: var(--ro-primary-text); background: var(--ro-surface); border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card-hover); }

.ro-btn--ghost { background: transparent; color: var(--ro-primary-text); padding: 13px 16px; }
.ro-btn.ro-btn--ghost:hover { color: var(--ro-primary-text); background: rgb(var(--ro-rgb-primary) / 0.08); }
/* :focus and :active re-asserted at (0,3,0) DELIBERATELY. Two of these are
   real <button> elements (section-quick-booking.php:144,
   section-works-slider.php:671) and Hello Elementor ships
   `button:hover, button:focus { background-color: rgb(204,51,102) }` at
   (0,2,0), which out-specifies a component's own (0,1,1). (0,2,0) here
   would only TIE, and a tie is decided by print order, which a
   CSS-combining plugin can flip. :focus-visible is not a defence against
   a hostile :focus. Without this the re-point fixes the resting state and
   leaves a magenta ambush on focus (#237).
   The :hover rule above carries `background` for the SAME reason: Hello's
   ambush is `button:hover, button:focus`, and a hover rule that sets only
   `color` leaves #D42450 on #CC3366 -- 1.016:1. Measured by Gate A. */
.ro-btn.ro-btn--secondary:focus,
.ro-btn.ro-btn--secondary:active { color: var(--ro-primary-text); background: var(--ro-surface); }
.ro-btn.ro-btn--ghost:focus,
.ro-btn.ro-btn--ghost:active { color: var(--ro-primary-text); background: rgb(var(--ro-rgb-primary) / 0.08); }

.ro-btn--dark {
  background: rgb(var(--ro-rgb-sidebar)); color: rgb(var(--ro-rgb-sidebar-fg));
  box-shadow: var(--ro-shadow-card);
}
.ro-btn.ro-btn--dark:hover { color: rgb(var(--ro-rgb-sidebar-fg)); box-shadow: var(--ro-shadow-card-hover); filter: brightness(1.15); }

.ro-btn[disabled] { opacity: .45; pointer-events: none; box-shadow: none; }
.ro-btn--sm { min-height: 40px; padding: 9px 18px; font-size: var(--ro-fs-ui-sm); }
.ro-btn--lg { min-height: 56px; padding: 16px 34px; font-size: var(--ro-fs-ui); border-radius: 14px; }

.ro-contact {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 999px; padding: 10px 20px 10px 12px; min-height: 48px;
  font-weight: 600; font-size: var(--ro-fs-ui-sm); color: var(--ro-foreground);
  text-decoration: none; box-shadow: var(--ro-shadow-card); cursor: pointer;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
/* .ro-contact.ro-contact:hover (class doubled, not a typo): needs (0,3,0)
   specificity to beat Elementor's own Kit re-point `.elementor-kit-15
   a:hover{color}` (0,2,1) — see the .ro-btn comment above for the full
   diagnosis. No second real class co-occurs on this element to pair with
   instead, so the class is deliberately repeated. */
.ro-contact.ro-contact:hover { color: var(--ro-foreground); box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover); }
.ro-contact:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-contact:active { transform: scale(.97); }
.ro-contact__icon {
  width: 30px; height: 30px; border-radius: 999px; flex: none;
  display: inline-flex; align-items: center; justify-content: center; color: #fff;
}
.ro-contact__icon svg { width: 16px; height: 16px; }
.ro-contact__icon--phone    { background: var(--ro-primary-strong); }
.ro-contact__icon--whatsapp { background: #23A55A; }
.ro-contact__icon--telegram { background: #2AABEE; }
.ro-contact__icon--insta    { background: linear-gradient(45deg,#F58529,#DD2A7B 60%,#8134AF); }
.ro-contact__icon--sms      { background: var(--ro-secondary-strong); }

.ro-iconbtn {
  width: 48px; height: 48px; border-radius: 999px; border: 1px solid var(--ro-border);
  background: var(--ro-surface); color: var(--ro-primary-strong);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-iconbtn.ro-iconbtn:hover { color: var(--ro-primary-strong); box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover); }
.ro-iconbtn:active { transform: scale(.97); }
.ro-iconbtn svg { width: 20px; height: 20px; }

.ro-badge {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: 999px; padding: 5px 14px; font-size: var(--ro-fs-ui-micro); font-weight: 700;
}
.ro-badge--deal  { background: rgb(var(--ro-rgb-primary) / 0.12); color: var(--ro-primary-strong); }
.ro-badge--new   { background: rgb(var(--ro-rgb-secondary) / 0.16); color: var(--ro-secondary-strong); }
.ro-badge--solid { background: var(--ro-primary-strong); color: #fff; box-shadow: var(--ro-shadow-btn); }
.ro-badge--outline {
  background: rgb(255 255 255 / .75); border: 1.5px solid var(--ro-primary);
  color: var(--ro-primary-strong); letter-spacing: .04em; text-transform: uppercase; font-size: var(--ro-fs-ui-micro);
}

.ro-chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--ro-surface-2); border: 1px solid var(--ro-border);
  border-radius: 999px; padding: 8px 16px; font-size: var(--ro-fs-ui-sm); font-weight: 600;
  color: var(--ro-foreground);
}
.ro-chip svg { width: 16px; height: 16px; color: var(--ro-primary-strong); }
.ro-chip b { font-weight: 800; }

.value-coin {
  width: 52px; height: 52px; border-radius: 16px;
  display: inline-flex; align-items: center; justify-content: center;
}
.value-coin svg { width: 26px; height: 26px; }
.value-coin--primary    { background: rgb(var(--ro-rgb-primary) / 0.13);   color: var(--ro-primary-strong); }
.value-coin--secondary  { background: rgb(var(--ro-rgb-secondary) / 0.16); color: var(--ro-secondary-strong); }
.value-coin--accent     { background: rgb(var(--ro-rgb-accent) / 0.16);    color: var(--ro-accent-strong); }
.value-coin--foreground { background: rgb(var(--ro-rgb-foreground) / 0.08); color: var(--ro-foreground); }

.frame { position: relative; display: inline-block; max-width: 100%; --frame-c: var(--ro-primary); }
.frame::before {
  content: ""; position: absolute; inset: 0; border-radius: 10px;
  background: var(--frame-c); transform: translate(-16px, -16px);
}
.frame > img, .frame > .frame-fallback { position: relative; z-index: 1; border-radius: 10px; display: block; }
.frame--secondary { --frame-c: var(--ro-secondary); }
.frame--accent { --frame-c: var(--ro-accent); }
.frame--flip::before { transform: translate(16px, 16px); }

/* ============================================================
   SECTION RHYTHM + CONTENT BOX (2026-07-13)
   Every renderer emits <div class="wrap"> as its content box, but the
   rule was scoped to .ro-hero-banner only during the #33 migration —
   on a full-width Elementor container every other section sprawled
   edge-to-edge. One shared rule per section root, never a bare .wrap
   (legacy site CSS could collide with an unscoped class).
   Vertical beat: each section root takes half of --ro-section-gap on
   each side, so any two adjacent sections sum to exactly one gap.
   Hero Banner is exempt (it opens the page flush under the header and
   ships its own bottom padding on .hero2-sec).
============================================================ */
.ro-hero-banner .wrap,
.ro-service-hero .wrap,
.ro-pricing-table .wrap,
.ro-values .wrap,
.ro-reading-content .wrap,
.ro-section-indications .wrap,
.ro-section-qb .wrap,
.ro-section-faq .wrap,
.ro-section-category-listing .wrap,
.ro-services-grid .wrap,
.ro-deals-listing .wrap,
.ro-deal-single .wrap,
.ro-works-slider .wrap,
.ro-section-service-detail .wrap,
.ro-section-maintenance-path .wrap,
.ro-section-contact .wrap,
.ro-section-arrival .wrap,
.ro-editorial-gallery .wrap {
  /* R2: the page gutter is a token, not a literal 24. It reaches 24px at
     533px and holds there, so nothing at tablet or above moves; below that
     it scales down and hands the width back to the reading column, which
     is the whole point of the one-gutter model (tokens.css §4a). */
  max-width: var(--ro-content-max); margin-inline: auto; padding-inline: var(--ro-gutter);
}

/* ------------------------------------------------------------
   R3 · CONTAINER QUERY CONTEXTS (v3.76.0)
   Three sections lay out in two columns, and what decides whether two
   columns still read is the width of THEIR OWN content box, not the
   viewport's. Measured 2026-08-17 at clientWidth 1425 on one service
   page: Service Detail's wrap resolved to 1152px while Indications'
   resolved to 1072px, because they sit in differently-configured
   Elementor containers — so a viewport breakpoint fired those two
   layouts at different real column widths. That mismatch is the bug;
   the container opt-out in elementor-overrides.css §7 removes the
   1072/1152 split and these contexts make the queries measure the
   thing they actually care about.

   An element cannot answer its own container query, so each context
   goes on the .wrap ABOVE the grid. All three wraps already exist —
   zero markup change.

   `container-type: inline-size` also applies `contain: layout style`,
   so each .wrap becomes a containing block for absolutely positioned
   descendants and a counter scope. Audited on the live DOM before
   shipping: all 28 abs-positioned descendants in these three sections
   are `li::before` / `li::after` markers resolving against their own
   `position: relative` li — not one resolved against the .wrap, so
   nothing re-anchors. .ro-service-procedure's `counter-reset` sits
   inside the same wrap as its `counter-increment`, so the numbered
   steps are unaffected by the style containment.

   Named contexts, not anonymous: an unnamed query binds to the nearest
   ancestor container, which after this change is whichever of these
   three happens to be closest — a silent cross-section match.
------------------------------------------------------------ */
/* ro-rc joined in v3.119.0 for Reading Content's wide-state container
   threshold. The same containment audit was re-run before adding it, across
   all three page types Reading Content renders on — a category term
   (/services/extensions/), a service single
   (/services/manicure/russian/gel-manicure/) and a legal page
   (/policies/, h1 + 11 headings + lists), at 390/768/928/1600:
   0 absolutely positioned descendants, 0 abs-positioned pseudo-elements and
   0 CSS counters inside .ro-reading-content on every one. .ro-callout is
   position: static. Nothing re-anchors and no counter scope moves.

   NOTE for anyone deriving a threshold against these contexts: an
   inline-size container resolves against its own CONTENT box, not its
   border box, and .wrap carries padding-inline: var(--ro-gutter). So a
   container query here fires LATER than the same number read as a
   viewport width, and the offset is not a constant — it moves with the
   scrollbar width and with the Elementor container's own width.
   Measured: a 960px viewport yields an 896.7px ro-rc container, i.e.
   `min-width: 880px` is live from roughly a 943px viewport. Do not
   encode that 943 anywhere; the container number is the contract.
   Recorded because the viewport figure was got wrong twice while
   deriving this. The `ch` measure belongs on descendants, where the
   element's own prose font-size supplies its unit basis. */
.ro-section-service-detail .wrap { container: ro-sd / inline-size; }
.ro-section-indications .wrap    { container: ro-ind / inline-size; }
.ro-values .wrap                 { container: ro-values / inline-size; }
.ro-reading-content .wrap        { container: ro-rc / inline-size; }

.ro-service-hero,
.ro-pricing-table,
.ro-values,
.ro-reading-content,
.ro-section-indications,
.ro-section-qb,
.ro-section-faq,
.ro-section-category-listing,
.ro-works-slider,
.ro-section-service-detail,
.ro-section-maintenance-path,
.ro-section-contact,
.ro-section-arrival {
  padding-block: calc(var(--ro-section-gap) / 2);
}
/* v3.210.0: an in-page jump to a looks rail (#design-looks) lands its heading below the 64px sticky header. */
.ro-works-slider[id] { scroll-margin-top: 72px; }

/* ============================================================
   HERO BANNER (issue #32 pilot) — deal ribbon + 62vh slider + tile nav
============================================================ */

.deal-ribbon {
  background: rgb(var(--ro-rgb-secondary) / 0.22);
  border-bottom: 1px solid rgb(var(--ro-rgb-secondary) / 0.3);
}
.deal-ribbon__in {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  min-height: 46px; padding-top: 6px; padding-bottom: 6px; font-size: var(--ro-fs-ui);
  font-family: var(--ro-font-sans);
}
.deal-ribbon b { font-weight: 800; color: var(--ro-foreground); }
.deal-ribbon span { color: var(--ro-muted-fg); font-weight: 500; }
.deal-ribbon a {
  color: var(--ro-secondary-strong); font-weight: 700;
  text-decoration: underline; text-underline-offset: 3px; border-radius: 4px;
}
/* .deal-ribbon.deal-ribbon (class doubled): `.deal-ribbon a:hover` alone
   is (0,2,1), an exact specificity TIE with Elementor's Kit re-point
   `.elementor-kit-15 a:hover` (0,2,1) — ties fall back to source order,
   which happens to currently favor us, but that's fragile (breaks the
   moment enqueue order or a CSS-combining plugin changes). Doubling the
   class wins outright at (0,3,1) instead of relying on the tie. */
.deal-ribbon.deal-ribbon a:hover { color: var(--ro-foreground); }
.deal-ribbon a:focus-visible, .deal-ribbon__close:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.deal-ribbon__close {
  /* 44x44 min hit area (a11y.md) — the ribbon bar itself is short (46px
     min-height), so the button's visual box stays 32px via padding while
     the actual clickable area meets the floor. */
  margin-left: auto; width: 44px; height: 44px; border: none; background: none;
  border-radius: 10px; color: var(--ro-muted-fg); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.deal-ribbon__close:hover { background: rgb(var(--ro-rgb-secondary) / 0.28); color: var(--ro-foreground); }
.deal-ribbon__close svg { width: 15px; height: 15px; }

.hero2-sec { padding: 0 0 40px; }
.hero2 {
  position: relative; overflow: hidden;
  width: 100%; max-width: 100%;
  height: 62vh; min-height: 420px;
}
.ro-hero-banner .hero2__pattern {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .9; pointer-events: none;
}
.ro-hero-banner .hero2__pattern-layer--media { display: none; }
/* .ro-hero-banner prefix (0,2,0): Elementor's frontend.min.css ships
   `.elementor img { height: auto }` at (0,1,1), which beats a bare
   `.hero2__pattern` (0,1,0) and collapses the pattern to its intrinsic
   SVG ratio — caught live 2026-07-13 (251px pattern on a 713px banner).
   Any stretched img inside a section needs its height rule at (0,2,0)+. */
.hero2__slide {
  position: absolute; inset: 0; display: flex; align-items: center;
  opacity: 0; transform: translateX(48px); pointer-events: none;
  transition: opacity 420ms var(--ro-ease), transform 420ms var(--ro-ease);
}
.hero2__slide--active { opacity: 1; transform: translateX(0); pointer-events: auto; }
.hero2__slide--plain {
  background:
    radial-gradient(120% 90% at 85% 15%, rgb(var(--ro-rgb-secondary) / .18) 0%, transparent 55%),
    linear-gradient(115deg, transparent 40%, rgb(var(--ro-rgb-primary) / .35) 100%);
}
.hero2__media { position: absolute; inset: 0; }
/* CENTER anchor: banner art grows symmetrically left+right, so the
   designed transparent left zone survives any viewport (locked 2026-07-12).
   (0,2,1) prefix: `.elementor img {height:auto}` is an exact (0,1,1) tie
   with the bare selector — don't rely on source order. */
.ro-hero-banner .hero2__media img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.hero2__content { position: relative; z-index: 2; max-width: 1200px; margin: 0 auto; padding: 20px 24px; width: 100%; }
.hero2__box { max-width: 42%; display: flex; flex-direction: column; gap: 13px; align-items: flex-start; font-family: var(--ro-font-sans); }
/* Lead copy. */
.hero2__box .hero-tagline { font-size: var(--ro-fs-lead); max-width: var(--ro-measure-lead); }

/* Breadcrumb trail, overlaid on the banner art. Markup comes from Rank Math,
   so every rule stays scoped under .hero-crumbs — a Rank Math breadcrumb
   rendered anywhere else on the site must not inherit the hero's skin.
   Rendered once, outside the slide loop (see section-hero-banner.php).
   The wrapper is a full-width positioning rail aligned to .hero2__content's
   1200px/24px rhythm so the trail starts on the same left edge as the title;
   pointer-events:none keeps that invisible rail from swallowing clicks meant
   for the slide beneath it, and the pill re-enables them for its own links. */
.hero-crumbs {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 3;
  max-width: 1200px;
  margin-inline: auto;
  padding: 18px 24px 0;
  pointer-events: none;
  font-family: var(--ro-font-sans);
}
/* Glass pill — same vocabulary as .rws-chip/.rws-pad. The banner art is
   owner-supplied and its tone behind the trail can't be assumed, so the pill
   (not the photo) is what carries AA contrast for the white text. */
.hero-crumbs__pill {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  overflow-x: auto;
  /* thin, not none: the desktop-classic reinforcement. --ro-muted-fg (5.68
     on white, 5.08 on the worst-case pill surface), NEVER --ro-border-hover,
     which is 1.50:1 and would be an affordance nobody can see. */
  scrollbar-width: thin;
  scrollbar-color: var(--ro-muted-fg) transparent;
  white-space: nowrap;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: var(--ro-fs-meta);
  font-weight: 600;
  line-height: 1.4;
  color: var(--ro-muted-fg);
  background: rgba(var(--ro-rgb-surface) / 0.95);
  border: 1px solid var(--ro-border);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  box-shadow: 0 2px 8px rgba(56, 46, 51, 0.04);
}
/* J-4: the trail overflows its scroller with no affordance and no keyboard
   route. The PRIMARY cue is this always-painted edge fade, not the scrollbar:
   on overlay-scrollbar platforms (macOS 'automatically', iOS Safari, Android
   Chrome) the scrollbar is INVISIBLE until the user scrolls -- exactly the
   pre-interaction moment the cue exists to serve.
   It is an overlay CHILD, deliberately not mask-image on the pill itself: the
   pill is focusable as of R6, and a mask applies to the element's entire
   rendering INCLUDING its outline, which would eat the focus ring at the right
   edge in the one case it matters. It also collides with the backdrop-filter.
   Sticky in the inline axis + a negative start margin gives it zero layout
   width. pointer-events:none, and a pseudo-element is not an a11y node. */
.hero-crumbs__pill::after {
  content: "";
  position: sticky;
  right: 0;
  flex: 0 0 auto;
  align-self: stretch;
  width: 24px;
  margin-inline-start: -24px;
  pointer-events: none;
  background: linear-gradient(to right, rgb(var(--ro-rgb-surface) / 0), rgb(var(--ro-rgb-surface) / 0.95));
}
/* A cue that paints when the content does NOT overflow is a lie, so bind it to
   the scrollable state -- no JS, no ResizeObserver for a decoration. Where
   scroll-driven animations are unsupported the base fade above stands and may
   over-paint a short trail by a few px of alpha: an accepted cosmetic cost.
   Under prefers-reduced-motion the .ro-hero-banner block above sets
   `animation: none`, which drops the enhancement back to that same base. */
@supports (animation-timeline: scroll(nearest inline)) {
  .hero-crumbs__pill::before {
    content: "";
    position: sticky;
    left: 0;
    flex: 0 0 auto;
    align-self: stretch;
    width: 24px;
    margin-inline-end: -24px;
    pointer-events: none;
    opacity: 0;
    background: linear-gradient(to left, rgb(var(--ro-rgb-surface) / 0), rgb(var(--ro-rgb-surface) / 0.95));
    animation: ro-crumbs-cue-in linear both;
    animation-timeline: scroll(nearest inline);
  }
  .hero-crumbs__pill::after {
    animation: ro-crumbs-cue-out linear both;
    animation-timeline: scroll(nearest inline);
  }
}
@keyframes ro-crumbs-cue-in  { 0% { opacity: 0 } 12%, 100% { opacity: 1 } }
@keyframes ro-crumbs-cue-out { 0%, 88% { opacity: 1 } 100% { opacity: 0 } }
/* The pill becomes focusable in this release; an invisible focus target is a
   regression, not a fix. outline-offset is -2px, NOT the site-wide +2px: an
   outset ring lands on owner-supplied banner photography where nothing
   guarantees 3:1. Inset, it sits on the pill's own surface -- worst case (a
   pure-black photo) resolves to #F2F2F2, against which --ro-rgb-ring measures
   3.49 and clears 3:1. The ring token is unchanged; only its offset is. */
.hero-crumbs__pill:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: -2px;
}

.hero-crumbs p,
.hero-crumbs span {
  display: inline;
  margin: 0;
  padding: 0;
}
.hero-crumbs a {
  color: var(--ro-primary-text);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--ro-dur) var(--ro-ease);
}
.hero-crumbs a:hover {
  color: var(--ro-foreground);
}
.hero-crumbs a:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
  border-radius: 4px;
}
.hero-crumbs [aria-current="page"],
.hero-crumbs .breadcrumb_last {
  color: var(--ro-foreground);
  text-decoration: none;
  pointer-events: none;
}
@media (max-width: 900px) {
  .hero-crumbs { padding: 12px 16px 0; }
}

.hero-eyebrow {
  font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ro-primary-text); display: flex; align-items: center; gap: 8px;
}
.hero-eyebrow svg { width: 15px; height: 15px; }
.hero-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  line-height: 1.15; letter-spacing: -.01em; color: var(--ro-foreground);
}
/* Lead copy. */
.hero-tagline { font-size: var(--ro-fs-lead); color: var(--ro-muted-fg); font-weight: 500; margin: 0; max-width: var(--ro-measure-lead); }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-top: var(--ro-stack-xs); }

.price-row { display: flex; align-items: baseline; gap: 10px; font-size: 17px; color: var(--ro-muted-fg); font-family: var(--ro-font-sans); }
.price-row b { font-size: 34px; font-weight: 800; color: var(--ro-foreground); letter-spacing: -.01em; }
.price-row s { font-size: 20px; color: var(--ro-muted-fg); opacity: .75; font-weight: 600; }

.hero2-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 22px; }
.hero2-tile {
  display: flex; align-items: center; gap: 13px; font-family: var(--ro-font-sans);
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 16px; padding: 15px 17px; text-decoration: none; color: var(--ro-foreground);
  box-shadow: var(--ro-shadow-card); cursor: pointer;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
/* .hero2-tile.hero2-tile:hover (class doubled) — this is a <button> (tab
   nav) for most tiles and an <a> (extra_tiles) for the rest, and the
   theme's base style.min.css ships BOTH `button:hover`/`[type="button"]:hover`
   AND `a:hover` rules that set `color` + `background-color: rgb(204,51,102)`
   (a hardcoded magenta unrelated to our tokens) at (0,2,0)/(0,2,1)
   specificity. Re-asserting color alone (previous fix) wasn't enough —
   background must be re-asserted too, or it silently flips to that
   magenta on hover since nothing else contests it. Same treatment on
   :focus-visible, since `button:focus`/`[type="button"]:focus` carry the
   identical background/color pair. */
.hero2-tile.hero2-tile:focus, .hero2-tile.hero2-tile:active { color: var(--ro-foreground); background: var(--ro-surface); }
.hero2-tile.hero2-tile:hover, .hero2-tile.hero2-tile:focus:hover, .hero2-tile.hero2-tile:active:hover { color: var(--ro-foreground); background: var(--ro-surface); box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover); }
.hero2-tile.hero2-tile:focus-visible { outline: 2px solid rgb(var(--ro-rgb-secondary)); outline-offset: 2px; }
.hero2-tile > div { min-width: 0; }
/* Full label always visible — wrap, never truncate (owner: a clamp that cut
   "Therapeutic Med-Pedi serv…" reads as broken). min-width:0 on the flex
   parent lets it wrap; break-word handles the rare over-long single token. */
.hero2-tile b {
  display: block;
  font-size: var(--ro-fs-ui);
  font-weight: 800;
  line-height: 1.25;
  overflow-wrap: break-word;
  hyphens: auto;
}
.hero2-tile span:not(.value-coin) { font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); font-weight: 500; }
.hero2-tile .value-coin { width: 40px; height: 40px; border-radius: 12px; flex: none; }
.hero2-tile .value-coin svg { width: 20px; height: 20px; }
.hero2-tile--active {
  border-color: rgb(var(--ro-rgb-primary) / 0.55);
  box-shadow: var(--ro-shadow-card-hover), 0 0 0 3px rgb(var(--ro-rgb-primary) / 0.12);
}
button.hero2-tile { font-family: inherit; text-align: left; }
.hero2-tile { position: relative; overflow: hidden; }
.hero2-tile__bar {
  position: absolute; left: 0; bottom: 0; height: 3px; width: 0;
  background: linear-gradient(90deg, var(--ro-primary), var(--ro-primary-strong));
  border-radius: 0 3px 3px 0;
}
.hero2-tile--active .hero2-tile__bar { animation: roTileProgress 6s linear forwards; }
@keyframes roTileProgress { from { width: 0 } to { width: 100% } }

/* ============================================================
   SERVICE HERO
============================================================ */
.hero-card {
  background: var(--ro-surface);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  overflow: hidden;
  display: grid; grid-template-columns: 460px 1fr;
  position: relative;
}
/* Release the grid item's default stretch so the photographer's 4:5 crop
   resolves against the 460px track; the same rule follows the single-column
   width at 900px and below, with no second mobile crop family. */
.hero-media {
  position: relative;
  align-self: start;
  aspect-ratio: 4 / 5;
  width: 100%;
}
/* (0,2,0) beats `.elementor img { height: auto }` — see .hero2__pattern */
.ro-service-hero .hero-media__img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.hero-media--framed {
  display: flex; align-items: center; justify-content: center;
  padding: 44px 10px 34px 44px; background: var(--ro-surface-2);
}
.hero-media--framed .frame img { width: 100%; aspect-ratio: 4 / 3.4; object-fit: cover; }
.ro-service-hero .hero-media--framed {
  padding: 0;
}
.ro-service-hero .frame {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.ro-service-hero .frame::before {
  content: none;
}
.ro-service-hero .frame img {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
  border-radius: 0;
}
.hero-media--framed .ro-badge--solid { top: 30px; left: 30px; z-index: 2; }
.hero-media--fallback {
  background:
    radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-rgb-secondary) / .25) 0%, transparent 50%),
    radial-gradient(130% 110% at 85% 90%, rgb(var(--ro-rgb-accent) / .22) 0%, transparent 55%),
    linear-gradient(150deg, #FBDCE4 0%, var(--ro-primary) 120%);
  display: flex; align-items: center; justify-content: center;
}
.hero-media--fallback .orchid-mark { text-align: center; color: #fff; }
.hero-media--fallback .orchid-mark svg { width: 84px; height: 84px; margin: 0 auto 10px; opacity: .95; }
.hero-media--fallback .orchid-mark span {
  font-family: var(--ro-font-serif); font-size: 15px; /* brand wordmark, not text typography */ letter-spacing: .3em;
  text-transform: uppercase; opacity: .9;
}
.hero-media .ro-badge--solid { position: absolute; top: 20px; left: 20px; }

.hero-body { padding: 44px 48px; display: flex; flex-direction: column; gap: 18px; }
.hero-eyebrow {
  font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ro-primary-text); display: flex; align-items: center; gap: 8px;
}
.hero-eyebrow svg { width: 15px; height: 15px; }
h1.hero-title, .hero2__box h1.hero-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h1); line-height: 1.15; letter-spacing: -.01em; margin: 0;
}
h2.hero-title, h3.hero-title, .hero2__box h2.hero-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h2); line-height: 1.2; letter-spacing: -.01em; margin: 0;
}
.hero-meta { display: flex; flex-wrap: wrap; gap: 10px; }
/* Body copy. */
.hero-desc { color: var(--ro-muted-fg); font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); max-width: var(--ro-measure); }
.hero-desc strong { color: var(--ro-foreground); font-weight: var(--ro-fw-semibold); }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-top: var(--ro-stack-xs); }
.hero-trust {
  display: flex; align-items: center; gap: 8px; margin-top: 8px;
  font-size: var(--ro-fs-ui-sm); color: var(--ro-muted-fg);
}
.hero-trust svg { width: 16px; height: 16px; color: var(--ro-secondary-strong); flex: none; }

/* v3.211.0 design-tier style cards: one photo card per style guide, under the hero card, before the calculator.
   4:5 is the Works photo crop family; three across at every width so all styles show in one screen. */
.ro-style-cards { margin-top: var(--ro-stack-lg); }
h3.ro-style-cards__title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h3); line-height: 1.3; margin: 0;
}
.ro-style-cards__lede { margin: 6px 0 0; color: var(--ro-muted-fg); font-size: var(--ro-fs-ui-sm); }
.ro-style-cards__grid {
  list-style: none; margin: var(--ro-stack-md) 0 0; padding: 0; max-width: 900px;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px;
}
.ro-style-cards__grid > li { margin: 0; padding: 0; }
.ro-style-card {
  position: relative; display: block; aspect-ratio: 4 / 5; overflow: hidden;
  border-radius: var(--ro-radius-card); border: 1px solid var(--ro-border);
  background: var(--ro-surface-2); box-shadow: var(--ro-shadow-card);
  color: #fff; text-decoration: none;
  transition: transform var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease),
              border-color var(--ro-dur) var(--ro-ease);
}
/* (0,2,1) beats `.elementor img { height: auto }`. */
.ro-style-cards .ro-style-card img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  border-radius: 0; transition: transform var(--ro-dur-slow) var(--ro-ease);
}
.ro-style-card::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.68) 0%, rgba(0, 0, 0, 0.28) 34%, transparent 58%);
}
.ro-style-card__body {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; flex-direction: column; gap: 2px; padding: 16px 18px;
}
.ro-style-card__name { font-family: var(--ro-font-serif); font-weight: 900; font-size: 22px; line-height: 1.2; color: #fff; }
.ro-style-card__cue { font-size: var(--ro-fs-meta); font-weight: 600; color: rgb(255 255 255 / 0.88); }
.ro-style-card.ro-style-card:hover {
  color: #fff; transform: translateY(-3px);
  box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover);
}
.ro-style-card.ro-style-card:hover img { transform: scale(1.04); }
.ro-style-card.ro-style-card:active { transform: scale(0.98); }
.ro-style-card.ro-style-card:focus-visible {
  color: #fff; outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .ro-style-card.ro-style-card:hover, .ro-style-card.ro-style-card:active,
  .ro-style-card.ro-style-card:hover img { transform: none; }
}
@media (max-width: 640px) {
  .ro-style-cards__grid { gap: 10px; }
  .ro-style-card { border-radius: 14px; }
  .ro-style-card__body { padding: 10px 10px 9px; }
  .ro-style-card__name { font-size: 16px; }
  .ro-style-card__cue { font-size: 11px; }
}

/* ============================================================
   PRICING TABLE
============================================================ */
.price-filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: var(--ro-stack-md); }
.price-filter {
  font-family: inherit; font-weight: 700; font-size: var(--ro-fs-ui-sm); cursor: pointer;
  padding: 10px 20px; min-height: 44px; border-radius: 999px;
  background: var(--ro-surface); color: var(--ro-muted-fg); border: 1px solid var(--ro-border);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease),
              background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.price-filter.price-filter:hover {
  color: var(--ro-muted-fg); background: var(--ro-surface);
  border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card);
}
.price-filter.price-filter:focus-visible {
  color: var(--ro-muted-fg); background: var(--ro-surface);
  outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px;
}
.price-filter--active {
  background: var(--ro-primary-text); color: #fff; border-color: transparent;
  box-shadow: var(--ro-shadow-btn);
}
.price-filter.price-filter--active:hover,
.price-filter.price-filter--active:focus-visible {
  color: #fff; background: var(--ro-primary-text);
}
.price-card {
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card); box-shadow: var(--ro-shadow-card);
  padding: 10px 32px 22px;
}
.price-group { padding-top: 8px; }
.price-group[hidden] { display: none; }
.price-group__head {
  display: flex; align-items: center; gap: 12px;
  font-size: 18px; font-weight: 800; padding: 20px 0 6px;
}
.price-group__head .value-coin { width: 38px; height: 38px; border-radius: 11px; }
.price-group__head .value-coin svg { width: 19px; height: 19px; }
.price-row-line {
  display: grid; grid-template-columns: 1fr auto auto; gap: 18px; align-items: center;
  padding: 14px 0; border-bottom: 1px solid var(--ro-border);
}
.price-group .price-row-line:last-child { border-bottom: none; }
.price-name { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.price-name b { font-size: var(--ro-fs-ui); font-weight: 700; }
.price-name small { flex-basis: 100%; color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); }
.price-val { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.price-val b { font-size: 17px; font-weight: 800; }
.price-val s { color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); }

/* PRICING TABLE — one card, service rows flow in one column above 900px
   (owner: "inside the table, not two layout columns"). Original row style
   kept: service name left, price·duration right, hairline divider. */
.price-card--cols {
  background: var(--ro-surface);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  padding: 26px 34px;
  margin-top: 24px;
}
/* Single category → the service ROWS flow in one column. */
.pt-list--rows { column-count: 1; }
.pt-list--rows .price-group { display: contents; }
/* Multiple categories → each category BLOCK flows as a unit (label + its rows
   stay together) in one column. */
.pt-list--groups { column-count: 1; }
.pt-list--groups .price-group { break-inside: avoid; display: block; margin-bottom: 22px; }
.price-group[hidden] { display: none; }

.pt-group-label {
  font-family: var(--ro-font-serif); font-weight: 700; font-size: var(--ro-fs-h4); line-height: 1.35;
  color: var(--ro-primary-text); margin: 0 0 10px;
  padding-left: 11px; border-left: 3px solid var(--ro-primary-strong);
  break-after: avoid;
}
.pt-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 13px 0; border-bottom: 1px solid rgb(var(--ro-rgb-secondary) / 0.18);
  break-inside: avoid;
}
.price-group:last-child .pt-row:last-child { border-bottom: none; }
.pt-name { font-weight: 600; font-size: var(--ro-fs-ui); color: var(--ro-foreground); min-width: 0; }
.pt-name .ro-pill { margin-left: 6px; vertical-align: middle; }
.pt-price {
  flex: none; text-align: right; white-space: nowrap;
  display: inline-flex; align-items: baseline; gap: 6px;
}
.pt-price b { font-size: var(--ro-fs-ui); font-weight: 800; color: var(--ro-foreground); }
.pt-price:has(> s) > b { color: var(--ro-success-text); }
.pt-price s { color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); font-weight: 500; }
.pt-dur { color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); font-weight: 500; }

/* v3.66.0 — presentation sub-heading inside a curated context group. Visually
   SUBORDINATE to .pt-group-label (no accent bar, smaller, muted) so it cannot
   read as a category, and it carries no filter affordance.
   break-after remains as defense-in-depth if the list widens again; it is inert
   in the current one-column layout. When multicolumn was active, this heading
   was a direct child and a column break could strand "Essential Pedicure
   options" away from its rows, reinstating the exact misreading it prevents. */
.pt-subhead {
  font-family: var(--ro-font-sans); font-weight: 600; font-size: var(--ro-fs-meta);
  letter-spacing: .06em; text-transform: uppercase; color: var(--ro-muted-fg);
  margin: 18px 0 2px; break-after: avoid;
}
.price-group .pt-subhead:first-child { margin-top: 4px; }

/* Popular view only: curated subtitle + Book CTA (invariant 8). */
.pt-name { flex: 1 1 auto; }
.pt-sub { display: block; color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); font-weight: 500; margin-top: 2px; max-width: var(--ro-measure); }
/* v3.208.0 — registry-mapped "how it works" link (RO_PRICING_ROW_DETAILS). Inline-block +
   padding gives a >=24px target (WCAG 2.5.8) without changing the row's text rhythm.
   Scoped under .pt-name: `.elementor a { text-decoration: none }` (0,1,1) would otherwise
   strip the underline and leave the link distinguishable by colour alone. */
.pt-name .pt-more {
  display: inline-block; padding-block: 3px;
  color: var(--ro-primary-text); font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
  transition: text-decoration-thickness var(--ro-dur) var(--ro-ease);
}
.pt-name .pt-more:hover { text-decoration-thickness: 2px; }
.pt-name .pt-more:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; border-radius: 2px; }
@media (prefers-reduced-motion: reduce) { .pt-name .pt-more { transition: none; } }
.pt-book {
  flex: none; align-self: center;
  min-height: 40px; padding: 8px 18px; font-size: var(--ro-fs-ui-sm);
}
@media (pointer: coarse) { .pt-book { min-height: 44px; } }

/* v3.66.1 — Popular view stacks its two sections FULL WIDTH inside the one card.
   They are two parts of one menu, not alternatives. This explicit override is
   now defence-in-depth: base list modes are already single-column above 900px,
   but Popular must stay stacked if those modes widen again. */
.ro-pricing-table--popular .pt-list--groups { column-count: 1; column-rule: none; }
.ro-pricing-table--popular .price-group { margin-bottom: 0; }
/* One clean separator instead of a row hairline immediately followed by a
   group border. */
.ro-pricing-table--popular .price-group .pt-row:last-child { border-bottom: none; }
.ro-pricing-table--popular .price-group + .price-group {
  margin-top: 26px; padding-top: 26px; border-top: 1px solid var(--ro-border);
}

/* Full-width rows get DETERMINISTIC columns so price and Book align down the
   whole card. Fixed tracks, not minmax(…, max-content): grid tracks size per
   grid, and every .pt-row is its own grid, so a content-sized track would let a
   wider price grow that row alone and align nothing. 190px fits the widest live
   row, now `C$109 C$87 · ~120 min` (v3.101.0; measured 143px, down from 169px
   when it read `110–120 min`); minmax(0, 1fr) lets a long name wrap instead of
   forcing overflow. Nothing is shrunk to make this fit. The track was RE-DERIVED
   after the duration change and deliberately LEFT AT 190px: price and Book are
   `justify-self: end`, so shrinking it moves no right edge — 1fr absorbs the
   slack and the only effect would be extra wrapping room for long names.
   ≥901px only — at 900 and below .pt-list--groups is already single-column and
   the existing flex row is kept exactly as it was. */
@media (min-width: 901px) {
  .ro-pricing-table--popular .pt-row {
    display: grid; align-items: center; column-gap: 24px;
    grid-template-columns: minmax(0, 1fr) 190px 96px;
  }
  .ro-pricing-table--popular .pt-price { justify-self: end; }
  .ro-pricing-table--popular .pt-book { justify-self: end; }
}

/* The row for the service whose own page this is. Tint only — .pt-row:hover
   stays untouched (locked design decision, skins.css). */
.pt-row--current {
  background: rgb(var(--ro-rgb-primary) / 0.05);
  box-shadow: inset 3px 0 0 rgb(var(--ro-rgb-primary) / 0.55);
  border-radius: 6px 0 0 6px;
}

@media (max-width: 640px) {
  .pt-name { display: contents; }
  .pt-row {
    flex-wrap: wrap; align-items: baseline; row-gap: 4px; column-gap: 8px;
    justify-content: flex-start;
  }
  .pt-label {
    flex: 0 0 100%; min-width: 0; margin-bottom: 4px;
    font-weight: 600; font-size: var(--ro-fs-ui);
  }
  .pt-sub { flex: 0 0 100%; order: 1; margin-top: 0; }
  .pt-price { order: 2; }
  .pt-name .ro-pill { order: 3; margin-left: 0; }
  .pt-row:has(.pt-book)::after {
    content: ''; flex: 0 0 100%; height: 0; order: 4;
  }
  .pt-book {
    order: 5; flex: 0 0 auto; align-self: start; margin-top: 4px;
  }
}

.ro-pill {
  display: inline-flex; align-items: center; border-radius: 999px;
  padding: 1px 8px; font-size: var(--ro-fs-ui-micro); font-weight: 700; font-style: normal;
  letter-spacing: .03em; text-transform: uppercase; border: 1px solid currentColor;
  background: var(--ro-surface); white-space: nowrap;
}
.ro-pill--popular { color: var(--ro-primary-text); }
/* Deal pill takes an OPAQUE orange-tinted surface, not an alpha wash: the
   resolved 10%-over-white value. An rgb(... / .10) wash would make the
   ratio a function of whatever ancestor sits behind it (4.71 over white,
   4.27 over the warm canvas = FAIL), and .ro-pill renders inside .pt-name
   on rows that may carry .pt-row--current's tint. Opaque removes the
   dependency. The base rule's 1px currentColor border inherits the new
   colour and thereby clears the 3:1 non-text gate at 4.71. */
.ro-pill--deal { color: var(--ro-accent-text); background: #FEF6EE; }
.ro-pill--new { color: var(--ro-secondary-text); }

/* ============================================================
   QUICK BOOKING — brand pink band (2026-07-13 owner direction:
   solid pink, not the old light tint). Visual language ported
   from the approved #35 CTA-band prototype
   (.dev/prototypes/header-footer-soft-ui/index.html .cta-card):
   primary gradient + warm accent glow top-right + teal glow
   bottom-left, pattern ~25%, white serif heading, white inverse
   CTA, translucent outlined contact button. Adapted full-bleed:
   the band spans the viewport while .wrap boxes the content.
============================================================ */
/* NO overflow:hidden here — the Message-us tray (.qb__tray) pops below
   the actions row and must escape the band (was clipped, caught live
   2026-07-13). The pattern img clips itself via border-radius:inherit. */
.qb {
  position: relative;
  border-radius: var(--ro-radius-card); border: none;
  box-shadow: var(--ro-shadow-btn);
  background:
    radial-gradient(120% 160% at 85% -20%, rgb(var(--ro-rgb-accent) / .35) 0%, transparent 55%),
    radial-gradient(150% 140% at -10% 110%, rgb(var(--ro-rgb-secondary) / .3) 0%, transparent 50%),
    linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%);
}
/* (0,2,0) beats `.elementor img { height: auto }` — see .hero2__pattern */
.ro-section-qb .qb__pattern {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .28; pointer-events: none;
  border-radius: inherit;
}
.qb__in {
  position: relative; z-index: 2; display: grid; grid-template-columns: 7fr 5fr;
  gap: 44px; padding-block: 56px; align-items: center;
}
/* Lead copy. */
.qb__text { color: rgb(255 255 255 / .92); font-size: var(--ro-fs-lead); font-weight: 600; margin-top: var(--ro-stack-sm); max-width: var(--ro-measure-lead); }
.qb__actions { position: relative; display: flex; flex-direction: column; align-items: flex-end; }
.qb__row { display: flex; flex-wrap: wrap; gap: 14px; justify-content: flex-end; row-gap: 16px; }

/* floating dropdown — expands OVER the page, zero layout shift */
.qb__tray {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 30;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 16px; box-shadow: var(--ro-shadow-card-hover);
  padding: 12px; min-width: 240px;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease), visibility 0s linear var(--ro-dur);
}
.qb__tray.open {
  opacity: 1; visibility: visible; transform: translateY(0);
  transition: opacity var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.qb__pills { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.qb__pills .ro-contact { box-shadow: none; width: 100%; }
.qb__chev { transition: transform var(--ro-dur) var(--ro-ease); }
.qb__more[aria-expanded="true"] .qb__chev { transform: rotate(180deg); }

.qb--full { border-radius: 0; }
.qb--full .qb__in { padding-top: 96px; padding-bottom: 96px; gap: 48px; }
.qb__eyebrow { color: rgb(255 255 255 / 0.85); }
/* .ro-section-qb prefix: the Elementor Kit paints h2 color at (0,1,1),
   which beats a bare .qb__title (0,1,0) — verified live 2026-07-13
   (computed rgb(51,51,51) on the pink band). */
.ro-section-qb h2.qb__title {
  font-family: var(--ro-font-serif); font-weight: 900; font-size: var(--ro-fs-h2); color: #fff;
  margin-top: var(--ro-stack-xs); line-height: 1.2; letter-spacing: -.01em;
}
.ro-section-qb .qb__title em { color: #fff; }

/* Buttons on the pink band — the site-wide pink primary would vanish
   into it, so within this section the primary CTA inverts to the white
   surface treatment and "Message us" flips to the dark-plum button.
   Hover/focus re-assert color AND background at (0,4,0)+ per the
   standing hostile-hover-rules convention. The pink focus ring is
   invisible on pink, so it flips to white here too. */
.ro-section-qb .ro-btn.ro-btn--primary {
  background: var(--ro-surface); color: var(--ro-primary-strong);
  box-shadow: var(--ro-shadow-card);
}
.ro-section-qb .ro-btn.ro-btn--primary:focus,
.ro-section-qb .ro-btn.ro-btn--primary:active {
  background: var(--ro-surface); color: var(--ro-primary-strong);
}
.ro-section-qb .ro-btn.ro-btn--primary:hover,
.ro-section-qb .ro-btn.ro-btn--primary:focus:hover,
.ro-section-qb .ro-btn.ro-btn--primary:active:hover {
  background: var(--ro-surface); color: var(--ro-primary-strong);
  box-shadow: var(--ro-shadow-card-hover); filter: none;
}
.ro-section-qb .ro-btn.ro-btn--secondary {
  background: rgb(255 255 255 / .12); color: #fff;
  border-color: rgb(255 255 255 / .55);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  box-shadow: none;
}
.ro-section-qb .ro-btn.ro-btn--secondary:focus,
.ro-section-qb .ro-btn.ro-btn--secondary:active {
  background: rgb(255 255 255 / .12); color: #fff;
}
.ro-section-qb .ro-btn.ro-btn--secondary:hover,
.ro-section-qb .ro-btn.ro-btn--secondary:focus:hover,
.ro-section-qb .ro-btn.ro-btn--secondary:active:hover {
  background: rgb(255 255 255 / .22); color: #fff;
  border-color: #fff; box-shadow: none;
}
.ro-section-qb .ro-btn:focus-visible { outline-color: #fff; }

/* ============================================================
   FAQ ACCORDION
============================================================ */
.faq { display: flex; flex-direction: column; gap: 16px; max-width: 760px; }
.faq-item {
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 16px; box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.faq-item:hover { border-color: var(--ro-border-hover); }
.faq-item[open] { box-shadow: var(--ro-shadow-card-hover); }
/* Deliberately UNCAPPED. The plan's D4 table lists this at 110 characters,
   but that is the .pt-name artefact the same table already excludes: the
   number is the ROW's capacity, not a wrapped line. Measured at 1440 on
   /services/pedicure/spa/, every question is ONE line at 251-392px painted,
   and a 48ch cap left the painted text byte-identical while taking the row
   858px -> 505px and pulling the chevron 353px off the card edge. A summary
   is a heading at h4 rank (gate 6), not running prose. */
.faq-item summary {
  font-family: var(--ro-font-serif);
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 14px;
  padding: 18px 22px; font-weight: 700; font-size: var(--ro-fs-h4); line-height: 1.35; border-radius: 16px;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.faq-chevron {
  margin-left: auto; flex: none; width: 34px; height: 34px; border-radius: 999px;
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
  display: inline-flex; align-items: center; justify-content: center;
  transition: transform var(--ro-dur) var(--ro-ease);
}
.faq-chevron svg { width: 16px; height: 16px; }
.faq-item[open] .faq-chevron { transform: rotate(180deg); }
/* Body copy. */
.faq-body { padding: 0 60px 20px 22px; color: var(--ro-muted-fg); font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); line-height: var(--ro-lh-prose); overflow: hidden; }
/* The card is the measure: capping the body as well put a 48ch box, minus its
   own 82px of padding, inside an 860px card. Below 640 the chevron gutter is
   given back to the copy. */
.faq-body > :first-child { margin-top: 0; }
.faq-body > :last-child { margin-bottom: 0; }
@media (max-width: 640px) { .faq-body { padding-right: 22px; } }

/* ============================================================
   CATEGORY LISTING
============================================================ */
.cat-rows { display: flex; flex-direction: column; gap: 64px; }
.cat-row { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.cat-row--rev .cat-row__media { order: 2; }
.cat-row__media .frame { display: block; margin-left: 16px; margin-top: 16px; }
.cat-row--rev .cat-row__media .frame { margin-left: 0; margin-right: 16px; }
.cat-row__media img, .cat-row__media .frame-fallback {
  width: 100%; aspect-ratio: 5 / 4; object-fit: cover;
}
.cat-row__media .frame-fallback { display: flex; align-items: center; justify-content: center; color: #fff; }
.cat-row__media .frame-fallback svg { width: 64px; height: 64px; opacity: .9; }
.cat-row__body h3 { font-family: var(--ro-font-serif); font-weight: 900; font-size: var(--ro-fs-h3); line-height: 1.3; margin: var(--ro-stack-xs) 0 var(--ro-stack-sm); }
/* Lead copy. */
.cat-row__body p { color: var(--ro-muted-fg); font-size: var(--ro-fs-lead); font-weight: var(--ro-fw-body); max-width: var(--ro-measure); margin: 0 0 var(--ro-stack-sm); }
.cat-row__cta { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: var(--ro-stack-md); }
.cat-row__cta .price-row b { font-size: 28px; }

.subcat-badges { display: flex; gap: 6px; min-height: 22px; flex-wrap: wrap; }
.subcat-badges .ro-badge { font-size: var(--ro-fs-ui-micro); padding: 3px 10px; }
.cat-row--term .cat-row__media .frame-fallback--term {
  overflow: hidden;
  background-color: rgb(var(--ro-rgb-primary) / .2);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0%200%20800%20534' fill='none'%3E%3Cpath d='M-40%20150C120%2040%20215%20330%20380%20215S635%2018%20840%20130' stroke='%23fff' stroke-width='2' stroke-opacity='.34'/%3E%3Cpath d='M-20%20370C130%20280%20250%20520%20430%20370s260-90%20410%2020' stroke='%23fff' stroke-width='1.5' stroke-opacity='.22'/%3E%3Ccircle cx='636' cy='120' r='80' stroke='%23fff' stroke-width='1.5' stroke-opacity='.2'/%3E%3C/svg%3E"),
    linear-gradient(135deg, color-mix(in srgb, var(--ro-primary) 24%, white), color-mix(in srgb, var(--ro-secondary) 32%, white));
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}
/* Variant gradients consume the seasonal --ro-skin-* tokens (not the raw
   brand hues) so the weekly Skin Engine flip re-colours every fallback tile —
   per skins.css: joining the rotation = reading var(--ro-skin-lead/comp).
   Variation across v-1..v-4 comes from pattern geometry + gradient angle +
   lead/comp mix ratios, so all four re-skin together while staying distinct. */
/* v3.31.0 (F_3.31.0 item 1a): re-saturated into the 66–84% band + hero-style
   twin radial highlights (lead top-left, comp bottom-right) so image-less tiles
   read as genuinely bright brand pink like .hero-media--fallback — while STILL
   reading var(--ro-skin-lead/comp[-rgb]) so the weekly Skin Engine keeps
   re-colouring them. Never hardcode the hero's literal #FBDCE4 here: that would
   silently drop /services/, /deals/ and category rows off the rotation. SVG
   geometry + gradient angle + lead/comp mix keep v-1..v-4 distinct. */
.cat-row--term .cat-row__media .frame-fallback--term.v-1,
.frame-fallback--term.v-1,
.deal-media--fallback.v-1 {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0%200%20800%20534' fill='none'%3E%3Cpath d='M-40%20150C120%2040%20215%20330%20380%20215S635%2018%20840%20130' stroke='%23fff' stroke-width='2' stroke-opacity='.34'/%3E%3Cpath d='M-20%20370C130%20280%20250%20520%20430%20370s260-90%20410%2020' stroke='%23fff' stroke-width='1.5' stroke-opacity='.22'/%3E%3Ccircle cx='636' cy='120' r='80' stroke='%23fff' stroke-width='1.5' stroke-opacity='.2'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-skin-lead-rgb) / .32) 0%, transparent 55%),
    radial-gradient(130% 110% at 85% 90%, rgb(var(--ro-skin-comp-rgb) / .28) 0%, transparent 55%),
    linear-gradient(135deg, color-mix(in srgb, var(--ro-skin-lead) 78%, white), color-mix(in srgb, var(--ro-skin-comp) 70%, white));
}
.cat-row--term .cat-row__media .frame-fallback--term.v-2,
.frame-fallback--term.v-2,
.deal-media--fallback.v-2 {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0%200%20800%20534' fill='none'%3E%3Ccircle cx='100' cy='400' r='200' stroke='%23fff' stroke-width='1.5' stroke-opacity='.24'/%3E%3Ccircle cx='100' cy='400' r='120' stroke='%23fff' stroke-width='1.2' stroke-opacity='.18'/%3E%3Cpath d='M200%2050C350%20150%20450%200%20650%20120S750%20320%20850%20280' stroke='%23fff' stroke-width='2' stroke-opacity='.28'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-skin-comp-rgb) / .32) 0%, transparent 55%),
    radial-gradient(130% 110% at 85% 90%, rgb(var(--ro-skin-lead-rgb) / .28) 0%, transparent 55%),
    linear-gradient(45deg, color-mix(in srgb, var(--ro-skin-comp) 80%, white), color-mix(in srgb, var(--ro-skin-lead) 66%, white));
}
.cat-row--term .cat-row__media .frame-fallback--term.v-3,
.frame-fallback--term.v-3,
.deal-media--fallback.v-3 {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0%200%20800%20534' fill='none'%3E%3Cpath d='M-50%20100L850%20450' stroke='%23fff' stroke-width='1.5' stroke-opacity='.2'/%3E%3Cpath d='M-50%20180L850%20530' stroke='%23fff' stroke-width='2' stroke-opacity='.26'/%3E%3Cpath d='M-50%2020L850%20370' stroke='%23fff' stroke-width='1' stroke-opacity='.15'/%3E%3Ccircle cx='700' cy='150' r='100' stroke='%23fff' stroke-width='1.5' stroke-opacity='.22'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-skin-lead-rgb) / .34) 0%, transparent 55%),
    radial-gradient(130% 110% at 85% 90%, rgb(var(--ro-skin-comp-rgb) / .24) 0%, transparent 55%),
    linear-gradient(225deg, color-mix(in srgb, var(--ro-skin-lead) 84%, white), color-mix(in srgb, var(--ro-skin-lead) 62%, white));
}
.cat-row--term .cat-row__media .frame-fallback--term.v-4,
.frame-fallback--term.v-4,
.deal-media--fallback.v-4 {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0%200%20800%20534' fill='none'%3E%3Cpath d='M-80%20480C120%20280%20400%20480%20880%20180' stroke='%23fff' stroke-width='2' stroke-opacity='.24'/%3E%3Cpath d='M-80%20380C120%20180%20400%20380%20880%2080' stroke='%23fff' stroke-width='1.5' stroke-opacity='.18'/%3E%3Ccircle cx='400' cy='120' r='50' stroke='%23fff' stroke-width='1.5' stroke-opacity='.2'/%3E%3Ccircle cx='480' cy='160' r='30' stroke='%23fff' stroke-width='1.2' stroke-opacity='.15'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-skin-lead-rgb) / .30) 0%, transparent 55%),
    radial-gradient(130% 110% at 85% 90%, rgb(var(--ro-skin-comp-rgb) / .30) 0%, transparent 55%),
    linear-gradient(180deg, color-mix(in srgb, var(--ro-skin-lead) 72%, white), color-mix(in srgb, var(--ro-skin-comp) 68%, white), color-mix(in srgb, var(--ro-skin-lead) 80%, white));
}
.subcat-media--fallback {
  display: flex; align-items: center; justify-content: center; color: #fff;
  background: radial-gradient(120% 90% at 15% 10%, rgb(var(--ro-rgb-secondary) / .25) 0%, transparent 50%), linear-gradient(150deg, #FBDCE4 0%, var(--ro-primary) 130%);
}
.subcat-media--fallback svg { width: 54px; height: 54px; opacity: .9; }

.price-row { display: flex; align-items: baseline; gap: 10px; font-size: 17px; color: var(--ro-muted-fg); }
.price-row b { font-size: 34px; font-weight: 800; color: var(--ro-foreground); letter-spacing: -.01em; }
.price-row s { font-size: 20px; color: var(--ro-muted-fg); opacity: .75; font-weight: 600; }

/* ============================================================
   SERVICES GRID (issue #54)
============================================================ */
.ro-services-grid {
  padding-block: calc(var(--ro-section-gap) / 2);
}
.ro-services-grid__container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 240px;
  gap: 24px;
}
.ro-services-grid__tile {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  border-radius: var(--ro-radius-card);
  overflow: hidden;
  text-decoration: none;
  background-color: var(--ro-surface);
  border: 1px solid var(--ro-border);
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-services-grid__tile:hover {
  box-shadow: var(--ro-shadow-card-hover);
  border-color: var(--ro-border-hover);
}
.ro-services-grid__tile:active {
  transform: scale(0.98);
}
.ro-services-grid__tile:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-services-grid__media {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.ro-services-grid__media img,
.ro-services-grid__media .frame-fallback {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Centre the decorative orchid mark on image-less (fallback) tiles. */
.ro-services-grid__media .frame-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
}
.ro-services-grid__media .orchid-mark {
  text-align: center;
  color: #fff;
  opacity: 0.9;
}
.ro-services-grid__media .orchid-mark svg {
  width: 44px;
  height: 44px;
  margin: 0 auto 6px;
  display: block;
}
.ro-services-grid__media .orchid-mark span {
  font-family: var(--ro-font-serif);
  font-size: 11px; /* brand wordmark at tile scale */
  letter-spacing: 0.28em;
  text-transform: uppercase;
  opacity: 0.85;
}
/* Scrim softened for the brighter v3.31.0 fallback tiles — darkness now
   concentrated at the very bottom where the title/price sit (still clears AA
   for white text) and fully clear by ~68% up so the tile reads bright. */
.ro-services-grid__tile::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.68) 0%, rgba(0, 0, 0, 0.28) 42%, transparent 68%);
  pointer-events: none;
}
.ro-services-grid__content {
  position: relative;
  z-index: 3;
  padding: var(--ro-stack-md);
  color: #fff;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ro-stack-xs);
}
.ro-services-grid__info {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
h3.ro-services-grid__title {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h3);
  color: #fff;
  margin: 0;
  line-height: 1.3;
}
/* Two-part price: small muted "from" label + large bold figure, in the
   white-on-dark tile palette. Deliberately NOT reusing .price-row (light-
   surface colours, 34px figure would overwhelm a 240px tile). */
.ro-services-grid__price {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.ro-services-grid__price-label {
  font-size: var(--ro-fs-ui-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgb(255 255 255 / 0.72);
}
.ro-services-grid__price-figure {
  font-size: 22px;
  font-weight: 800;
  color: #fff;
  letter-spacing: -0.01em;
}
.ro-services-grid__tile .ro-badge {
  font-size: var(--ro-fs-ui-micro);
  padding: 3px 8px;
  background: var(--ro-skin-lead);
  color: #fff;
  border-radius: 6px;
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.05em;
}

/* Bento grid-column/row spans — scoped to the grid container so the generic
   tile--* names can't leak onto other markup */
.ro-services-grid__container > .tile--large {
  grid-column: span 2;
  grid-row: span 2;
}
.ro-services-grid__container > .tile--tall {
  grid-column: span 1;
  grid-row: span 2;
}
.ro-services-grid__container > .tile--small {
  grid-column: span 1;
  grid-row: span 1;
}
.ro-services-grid__container > .tile--span-1 {
  grid-column: span 1;
  grid-row: span 1;
}
.ro-services-grid__container > .tile--span-2 {
  grid-column: span 2;
  grid-row: span 1;
}
.ro-services-grid__container > .tile--span-3 {
  grid-column: span 3;
  grid-row: span 1;
}

@media (max-width: 768px) {
  .ro-services-grid__container {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
    gap: 16px;
  }
  .ro-services-grid__tile {
    grid-column: span 1 !important;
    grid-row: span 1 !important;
    aspect-ratio: 16 / 10;
  }
  .ro-services-grid__price-figure {
    font-size: 20px;
  }
}

/* ============================================================
   VALUES SECTION
============================================================ */
.values-head { max-width: 640px; margin-bottom: var(--ro-stack-lg); }
h1.values-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h1); line-height: 1.15; letter-spacing: -.01em;
  margin-top: var(--ro-stack-xs);
}
h2.values-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h2); line-height: 1.2; letter-spacing: -.01em;
  margin-top: var(--ro-stack-xs);
}
h2.values-title em { font-style: italic; color: var(--ro-primary-strong); }

.value-coin {
  width: 52px; height: 52px; border-radius: 16px;
  display: inline-flex; align-items: center; justify-content: center;
}
.value-coin svg { width: 26px; height: 26px; }
.value-coin--primary    { background: rgb(var(--ro-rgb-primary) / 0.13);   color: var(--ro-primary-strong); }
.value-coin--secondary  { background: rgb(var(--ro-rgb-secondary) / 0.16); color: var(--ro-secondary-strong); }
.value-coin--accent     { background: rgb(var(--ro-rgb-accent) / 0.16);    color: var(--ro-accent-strong); }
.value-coin--foreground { background: rgb(var(--ro-rgb-foreground) / 0.08); color: var(--ro-foreground); }

/* R4: narrow-first. The card survives (A-4: 1065px on a 390px phone is
   1.26 viewports, so its contents still read as one object) but below the
   threshold it goes FULL-BLEED — negative gutter margin out, the same
   gutter back as padding — so its inset IS the page gutter instead of a
   second one on top of it. That is what puts the text column on the same
   left edge as every other section: measured 83.5% of viewport with a
   nested card inset, 91% full-bleed, against an 84% budget. */
.values-split {
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-inline: 0; border-radius: 0; box-shadow: var(--ro-shadow-card);
  display: grid; grid-template-columns: 1fr; gap: var(--ro-stack-md);
  margin-inline: calc(-1 * var(--ro-gutter));
  padding-block: var(--ro-stack-lg); padding-inline: var(--ro-gutter);
}
.values-split--no-stats { grid-template-columns: 1fr; }
/* R4: centring is rejected as a general rule. It was applied to the whole
   text column up to 900px, which centred the intro paragraph AND the
   check-list — so each check coin sat hard left while its label floated
   centre and no two list items shared a left edge. Heads may centre;
   body copy and lists do not. The head centring is the NARROW default and
   is undone in the wide state below, where the head sits over a 7fr text
   column and reads as a left-aligned block head — which is what it was. */
.values-split__text { text-align: left; }
.values-split__text h2.values-title { text-align: center; }
.values-split__text .hero-eyebrow { justify-content: center; }
.values-intro { color: var(--ro-muted-fg); font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); line-height: var(--ro-lh-prose); margin-top: var(--ro-stack-sm); max-width: var(--ro-measure); }
.values-link { margin-top: var(--ro-stack-sm); padding-left: 0; }

/* R4: `padding-left: 0`. The list carried the UA's 40px ul indent, so its
   check coins sat 40px right of the intro paragraph above them and nothing
   in the column shared a left edge. Invisible while the whole column was
   centre-aligned; the first thing you see once it is not. The coin is the
   marker and it hangs on the text edge. */
.check-list { list-style: none; margin-top: var(--ro-stack-md); padding-left: 0; display: flex; flex-direction: column; gap: 16px; }
.check-list li {
  display: flex; gap: 12px; align-items: flex-start; text-align: left;
  font-size: var(--ro-fs-prose-dense); font-weight: var(--ro-fw-body); color: var(--ro-foreground);
  max-width: var(--ro-measure-tight); line-height: 1.6;
}

/* Threshold 740px. The rule is unchanged — two columns are permitted only
   while the text column still holds >= 45 real characters — but the floor
   grows with --ro-fs-prose, so a faster ramp moves the threshold. Solving
   for the container width C (viewport V = C + 2*gutter):
     text col = 7/12 * (C - 104 padding - 2 border - 48 gap)
     floor    = 45 * 6.955px * fs/15.5,  fs = the --ro-fs-prose ramp
   which at the v3.126.0 ramp gave C >= 736. This derivation is trustworthy
   because its old form reproduces the old documented C >= 722 EXACTLY.
   730 could not stay: MEASURED on the v3.126.0 build, the Values intro at
   C = 730 held 44 real characters — under this block's own 45 floor — and
   first reached 45 at C = 740. Indications takes the same 740 to stay in
   step; see the note on that block, where the number is a rhythm decision
   rather than a floor it fails.
   v3.127.0 lowered the ramp cap to 16px, which moves this threshold DOWN
   (smaller type, more characters per column), so 740 now clears the floor
   with room to spare. It is deliberately NOT re-solved downward: the floor
   is satisfied either way, and moving a column threshold to chase it would
   be a layout change made for no reader. */
@container ro-values (min-width: 740px) {
  .values-split {
    grid-template-columns: 7fr 5fr; gap: 48px;
    margin-inline: 0; padding: 48px 52px;
    border-inline: 1px solid var(--ro-border); border-radius: var(--ro-radius-card);
  }
  .values-split--no-stats { grid-template-columns: 1fr; }
  .values-split__text h2.values-title { text-align: left; }
  .values-split__text .hero-eyebrow { justify-content: flex-start; }
}
.check-coin {
  width: 26px; height: 26px; border-radius: 999px; flex: none; margin-top: -1px;
  background: rgb(var(--ro-rgb-primary) / 0.13); color: var(--ro-primary-strong);
  display: inline-flex; align-items: center; justify-content: center;
}
.check-coin svg { width: 14px; height: 14px; }

.values-split__stats { display: flex; flex-direction: column; gap: 16px; justify-content: center; }
.stat-tile {
  display: flex; align-items: center; gap: 16px;
  background: var(--ro-surface-2); border: 1px solid var(--ro-border);
  border-radius: 16px; padding: 18px 20px;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.stat-tile:hover { box-shadow: var(--ro-shadow-card); border-color: var(--ro-border-hover); }
.stat-tile .value-coin { width: 46px; height: 46px; border-radius: 14px; flex: none; }
.stat-tile .value-coin svg { width: 22px; height: 22px; }
.stat-tile b { display: block; font-size: 19px; font-weight: 800; line-height: 1.2; }
.stat-tile span:not(.value-coin) { font-size: var(--ro-fs-ui-sm); color: var(--ro-muted-fg); font-weight: 500; }

/* ============================================================
   READING CONTENT & INDICATIONS
============================================================ */
.ro-prose { max-width: 900px; }

/* ------------------------------------------------------------
   R4 · CENTRED EDITORIAL COLUMN (Owner decision Q1, v3.76.0)
   Two alignments, deliberately separated:
     1. the OUTER section canvas — 1200px .wrap, one shared content
        edge for every ro-* section. Unchanged by this block.
     2. the EDITORIAL COLUMN — the bounded object --ro-measure creates
        inside that canvas.
   R3 alone pinned (2) to the left of (1), leaving ~625px of a 1152px
   canvas empty on one side. The column is now centred in its canvas
   while the TEXT INSIDE IT STAYS LEFT-ALIGNED — this is `margin-inline:
   auto` on a bounded block, never `text-align: center`.

   Scoped to standalone editorial surfaces only: Reading Content here,
   and the dissolved single-column Service Detail in its own block.
   Pricing, the Values card and the wide two-column Service Detail keep
   their full canvas and are explicitly NOT touched.

   `font-size: var(--ro-fs-prose)` is load-bearing, not cosmetic:
   --ro-measure is stated in `ch` so it tracks the type scale, and `ch`
   resolves against the element's OWN font. Without this the wrapper
   would resolve 48ch at the document's 16px (468px) while its own `p`
   resolves it at 18px (527px) — the wrapper would clip the paragraph it
   is supposed to bound, dropping desktop prose from 65 to 58 real
   characters. Every text descendant declares its own size, so this
   changes nothing but the unit basis.
   v3.206.0: a text-only column (direct child of .wrap) is re-widened and
   re-centred by the W5 editorial-width rule. */
.ro-reading-content .ro-prose {
  font-size: var(--ro-fs-prose);
  max-width: var(--ro-measure);
  margin-inline: auto;
}

/* Optional media stays a block until the existing wide Reading Content
   threshold admits a portrait rail. Figure's UA margin is 1em 40px; zero it
   here or the landscape image loses the prose's page-edge contract. DOM order
   remains prose first, figure second in every state. Landscape has no
   wide-state override by design: it remains one 5:4 figure at the prose edge. */
.ro-reading-content .rc-layout { display: block; }
.ro-reading-content .rc-figure { width: 100%; margin: 0; }
/* The figure is bounded and centred by the SAME three declarations as `.ro-prose`
   above, and all three are load-bearing, because the figure is a SIBLING of the
   prose rather than a descendant and inherits none of them:

     font-size    - `--ro-measure` is stated in `ch`, which resolves against the
                    element's OWN font. Without this the figure resolved 48ch at the
                    document's 16px and sat ~468px wide beside a 697px prose column.
     max-width    - the same bounded editorial column the prose gets.
     margin-inline- the same CENTRING. Measured 2026-09-14: with the prose centred and
                    the figure flush-left, the figure hung up to 211.67px to the LEFT of
                    the text it belongs to across the whole 560-920px band (it only
                    looked correct at 420, where the column fills the canvas, and at
                    943+, where the wide query sets both to 0). Browser-verified, and
                    invisible to every source-level gate that preceded it.

   Portrait caps the IMAGE at 320px rather than the figure, so the figure box keeps the
   prose's left edge and the smaller photo sits flush to it instead of being centred
   under the text. */
.ro-reading-content .rc-figure {
  font-size: var(--ro-fs-prose);
  max-width: var(--ro-measure);
  margin-inline: auto;
}
.ro-reading-content .rc-figure img {
  display: block;
  width: 100%;
  object-fit: cover;
}
.ro-reading-content .rc-layout--portrait .rc-figure img { aspect-ratio: 4 / 5; max-width: 320px; }
.ro-reading-content .rc-layout--landscape .rc-figure img { aspect-ratio: 5 / 4; }

@container ro-rc (min-width: 880px) {
  /* Landscape figure stays in this selector list so it shares the prose edge.
     Portrait is deliberately absent: its figure is the rail below, bounded in
     px, and never in `ch`. Text-only prose (direct child of .wrap) is
     NOT governed by this reset any more: the W5 editorial-width rule wins. */
  .ro-reading-content .ro-prose,
  .ro-reading-content .rc-layout--landscape .rc-figure {
    margin-inline: 0;
  }

  /* The portrait rail reuses this existing threshold; no second query. 880
     HOLDS at the ramp and is unchanged — it held at the v3.126.0 19px cap,
     and the v3.127.0 16px cap only gives the column more characters.
     Measured, not derived, because the derivation is misleading here: it
     solves with the rail at its 280px MINIMUM, but the declared track is
     minmax(280px, 360px) and the rendered rail takes its 360px MAXIMUM at
     every container from 826 up (rail-tracks.mjs). So at C = 880 the prose
     TRACK is 476px, not the 556px the 280px-rail solve predicts, the 48ch
     cap (508px at 17.34px) is NOT binding there — the track is — and the
     column holds ~60 real characters, essentially what it held before.
     Against the 45-character floor the prose track binds at about C >= 750,
     so 880 carries ~130px of slack rather than the 53.7px the rail-minimum
     solve reports.
     Standing caveat: .rc-layout--portrait renders on ZERO live pages (swept
     all 10 in the typo harness), so none of this is observable in
     production and the track figures come from a two-track fixture. */
  .ro-reading-content .rc-layout--portrait {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
    column-gap: var(--ro-stack-lg);
    align-items: start;
  }
  /* The rail owns its own width, so the narrow bounds come off - including the
     320px image cap, which would otherwise starve a 360px track. */
  .ro-reading-content .rc-layout--portrait .rc-figure { max-width: none; margin-inline: 0; }
  .ro-reading-content .rc-layout--portrait .rc-figure img { max-width: none; }
}

/* h1 joined the group in v3.67.0: the simple-page template has no title widget,
   so a page's only heading is the one its own copy opens with. */
.ro-prose h1 {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h1); line-height: 1.15; letter-spacing: -.01em;
  margin-bottom: var(--ro-stack-sm);
}
.ro-prose h2 {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h2); line-height: 1.2; letter-spacing: -.01em;
  margin-bottom: var(--ro-stack-sm);
}
.ro-prose h3 {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h3); line-height: 1.3; letter-spacing: -.01em;
  margin-bottom: var(--ro-stack-sm);
}
.ro-prose h1:not(:first-child), .ro-prose h2:not(:first-child), .ro-prose h3:not(:first-child) { margin-top: var(--ro-stack-md); }
/* R2: `78ch` rendered 106 real characters (1ch = 1.36 chars in Manrope), which
   is why desktop long-form read as a wall. --ro-measure is 48ch = 65 real
   characters, and --ro-fs-prose grows the type instead of the column so a
   1200px canvas is used by larger text rather than by longer lines. */
.ro-prose p {
  color: var(--ro-muted-fg); font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure); margin-bottom: 16px;
}
.ro-prose p:last-child { margin-bottom: 0; }
.ro-prose strong { color: var(--ro-foreground); font-weight: var(--ro-fw-semibold); }
.ro-prose ul { margin: 0 0 16px; padding-left: 22px; max-width: var(--ro-measure); }
.ro-prose li {
  color: var(--ro-muted-fg); font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); line-height: var(--ro-lh-prose); max-width: var(--ro-measure-tight); margin-bottom: 6px;
}
.ro-prose li:last-child { margin-bottom: 0; }

.ro-flourish { width: 64px; height: 14px; display: block; margin: 8px 0 18px; }
.ro-flourish--center { margin: 22px auto; }

/* R3/R4: narrow-first single column; two columns arrive on the CONTAINER
   query below, not on a viewport breakpoint. `align-items: stretch` (was
   `center`) because a centred flex item cannot be left-aligned by
   `text-align` — the h3 box itself was centre-placed, so left-aligning it
   needs the box to fill the column first. The h3 and its flourish are
   left-aligned at EVERY width, including the two-column desktop state.
   v3.127.0 removed the desktop re-centre on Owner review: the argument for
   it was that a centred head over one of two columns reads as that column's
   label, but on the live page the centred h3 and flourish float off the left
   edge the list below them runs from, so each column read as two pieces
   rather than one. One shared left edge per column is the composition. */
.indications { display: grid; grid-template-columns: 1fr; gap: var(--ro-stack-lg) 28px; margin-top: var(--ro-stack-lg); }
.indications--single { grid-template-columns: 1fr; max-width: 560px; margin-left: auto; margin-right: auto; }
.term-688 .ro-section-indications .indications--single {
  grid-template-columns: 1fr;
  max-width: calc(var(--ro-measure) + 540px + 56px);
  margin-inline: auto;
}
.term-688 .ro-section-indications .indications--single .indications__card {
  border-top: 0;
  border-inline-start: 2px solid var(--ro-primary);
  padding: 0 0 0 var(--ro-pad-inset);
}
.indications__col { display: flex; flex-direction: column; align-items: stretch; }
.indications__col h3 {
  font-family: var(--ro-font-serif); font-weight: 900; font-size: var(--ro-fs-h3); line-height: 1.3;
  text-align: left; margin-bottom: 6px;
}
.indications__col .ro-flourish { margin: 4px auto 18px 0; }

/* R4: the 10px inline padding is pure loss on a phone — it is a second
   inset inside the page gutter buying nothing, and it was the difference
   between this list and the reading column beside it. The top rule stays;
   it is what carries the grouping now. */
.indications__card {
  border-top: 1px solid var(--ro-border);
  padding: var(--ro-stack-lg) 0 0; width: 100%; flex: 1;
}
.indications__card ul { list-style: none; display: flex; flex-direction: column; gap: 14px; margin: 0; padding: 0; }
.indications__card li {
  position: relative; padding-left: 24px;
  color: var(--ro-muted-fg); font-size: var(--ro-fs-prose-dense); font-weight: var(--ro-fw-body); line-height: 1.6;
  max-width: var(--ro-measure-tight);
}
/* The bullet lead-in had NO rule of its own: it took `bolder` against the
   inherited 700 and computed 900, differing from its own body text by weight
   alone and by no colour at all. Same emphasis contract as .ro-prose strong. */
.indications__card li strong { color: var(--ro-foreground); font-weight: var(--ro-fw-semibold); }
.indications__card li::before {
  content: ""; position: absolute; left: 2px; top: 7px;
  width: 0; height: 0; border-style: solid;
  border-width: 5px 0 5px 8px;
  border-color: transparent transparent transparent var(--ro-secondary-strong);
}

/* 740px matches the Values threshold; the derivation is on that block.
   Unlike Values, Indications does NOT need to move: MEASURED on the build,
   its column holds 47 real characters at C = 730 and 48 at C = 740, so it
   clears the 45 floor either way. It takes 740 to stay in step with Values
   — one number for two sections in the same page rhythm — not because 730
   fails it.
   Do not trust the superseded comment that stood here: it claimed
   (C - 28 gap) / 2 minus a 24px bullet indent solves to C >= 718, but
   those stated terms solve to 740.4. An indent of ~14px reproduces 718.3,
   so the stated 24px was never the effective value. Measure this one. */
@container ro-ind (min-width: 740px) {
  .indications { grid-template-columns: 1fr 1fr; }
}

/* R4: re-designed as a lightweight note, at EVERY width.
   What it was: a short-warning affordance — tint, full border, radius,
   warning icon — carrying 286-507 characters of operational policy. Four
   stacked insets (page gutter, card, callout padding, icon column) left
   its prose 157px wide inside a 390px viewport: 21 real characters, 40%
   of the screen, against prose beside it at 91%. The tint, the border and
   the icon all signalled an urgency the copy does not have.
   What it is now: one lead rule in the section's colour, prose that
   matches the copy around it, and nothing else. The icon column and the
   26px horizontal padding are reclaimed outright; only --ro-pad-inset
   stays, as trim between the rule and the text.
   No box at wide either — a bordered tint box is no better at 1200px than
   at 390px for a five-sentence paragraph, and one treatment across all
   widths is one thing to maintain (Owner decision).
   Markup is FROZEN (`div.ro-callout > p`, authored across 28 content meta
   rows on posts and terms), so this is CSS only — no DOM change. */
.ro-callout {
  display: block;
  background: none;
  border: 0;
  border-left: 3px solid var(--ro-secondary-strong);
  border-radius: 0;
  padding: 0 0 0 var(--ro-pad-inset);
  margin: var(--ro-stack-md) 0;
}
.ro-callout::before { content: none; }
/* Class doubled to (0,3,0). `.ro-callout p` is (0,2,0) and so is
   `.ro-service-description p`, which is declared LATER in this file — so a
   callout authored into a description block (content_block_1 does exactly
   that on other services) took the description's contract instead of its
   own, decided by print order. Same reason as the .deal-ribbon note above.
   `opacity: .85` is gone: opacity is not a colour — it made the result
   depend on whatever sat behind it, which used to be a tint. --ro-muted-fg
   carries 5.08:1 on its own. */
.ro-callout.ro-callout p {
  color: var(--ro-muted-fg); opacity: 1; margin: 0;
  font-size: var(--ro-fs-prose); font-weight: var(--ro-fw-body); line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure);
}
.ro-callout.ro-callout p + p { margin-top: var(--ro-stack-sm); }
.ro-callout.ro-callout p strong { color: var(--ro-foreground); font-weight: var(--ro-fw-semibold); }

@media (max-width: 900px) {
  .hero-card { grid-template-columns: 1fr; }
  .hero-body { padding: 28px 22px; }
  .hero-ctas .ro-btn { flex: 1 1 100%; }

  .qb__in { grid-template-columns: 1fr; text-align: center; }
  .qb__actions, .qb__row { align-items: center; justify-content: center; width: 100%; }
  .qb__tray { left: 50%; right: auto; transform: translateX(-50%) translateY(-6px); }
  .qb__tray.open { transform: translateX(-50%) translateY(0); }
  .qb__in { gap: 32px; padding-block: 40px; }
  .qb--full .qb__in { padding-top: 64px; padding-bottom: 64px; }

  /* R3: the Values and Indications collapses that used to live here moved to
     container queries on their own .wrap — see those blocks above. A viewport
     breakpoint fired them at different real column widths depending on which
     Elementor container the section sat in. */

  .cat-row { grid-template-columns: 1fr; gap: 32px; }
  .cat-row--rev .cat-row__media { order: unset; }
  .cat-row__media .frame, .cat-row--rev .cat-row__media .frame { margin: 0; }

  /* Pricing: collapse the two internal columns to one on mobile. */
  .price-card--cols { padding: 20px 22px; }
  .pt-list--rows, .pt-list--groups { column-count: 1; column-rule: none; }
  .pt-list--groups .price-group { margin-bottom: 14px; }

  .price-card { padding: 6px 18px 16px; }
  .price-row-line { grid-template-columns: 1fr auto; }
  .price-row-line .ro-btn { grid-column: 1 / -1; justify-self: start; }

  .hero2 { height: auto; min-height: 0; }
  .hero2__slide { position: static; display: none; transform: none; flex-direction: column; }
  .hero2__slide--active { display: flex; }
  .hero2__media { position: relative; }
  .ro-hero-banner .hero2__media img { width: 100%; height: auto; object-position: center; }
  .ro-hero-banner .hero2__pattern-layer--media { display: block; position: absolute; inset: 0; z-index: 0; }
  .ro-hero-banner .hero2__pattern-layer--media .hero2__pattern { position: static; height: 100%; }
  .ro-hero-banner .hero2__media img:not(.hero2__pattern) { position: relative; z-index: 1; }
  .hero2:has(.hero2__slide--active .hero2__media) > .hero2__pattern-layer--global { display: none; }
  .hero2__content { padding: 26px 24px 22px; }
  /* mobile: center-justify banner + section heads (locked global rule) */
  .hero2__box { max-width: 100%; align-items: center; text-align: center; margin: 0 auto; }
  .hero2__box .hero-eyebrow, .hero2__box .price-row { justify-content: center; }
  .hero2__slide--plain { min-height: 380px; justify-content: center; }
  .hero2-tiles { grid-template-columns: 1fr 1fr; gap: 12px; }
  /* Narrow 2-up tiles: trim the coin + tighten type so a wrapped label
     (e.g. "Therapeutic Med-Pedi services") fits in 2 lines instead of 4. */
  .hero2-tile { gap: 10px; padding: 12px 13px; align-items: flex-start; }
  .hero2-tile .value-coin { width: 32px; height: 32px; border-radius: 10px; }
  .hero2-tile .value-coin svg { width: 16px; height: 16px; }
  .hero2-tile b { line-height: 1.2; }
  .deal-ribbon span { display: none; }
  .deal-ribbon__in { flex-wrap: nowrap; }
}

/* ============================================================
   FLOATING CONTACT (issue #43)
============================================================ */
.fab-container {
  position: fixed; bottom: 24px; right: 24px; z-index: 60;
}
@media (max-width: 599px) {
  .fab-container {
    bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    right: calc(16px + env(safe-area-inset-right, 0px));
  }
}
/* The calculator's own booking bar is fixed to the bottom of the viewport and
   carries the primary CTA; the FAB sits on top of it (z-60 vs z-50) and was
   measured covering 56x33px of the "Book Service" button, with
   elementFromPoint returning .fab-btn. While that bar is up, the FAB stands
   down. 768, matching .ro-mobile-bar's own rule - keep the two numbers equal.
   They were both 767 while the rest of the mobile layer sat at 768, which left
   exactly 768px (iPad portrait) showing the mobile sheets with no bar and no FAB
   suppression; the bar moved to 768 and this follows it. The body class is only
   set when the bar actually has height, so a width where the bar is hidden still
   cannot hide the FAB. */
@media (max-width: 768px) {
  body.ro-calc-bar-active .fab-container { display: none; }
}
/* Hide mini-cart only: opening it reaches Remove controls for the service under review,
   and it is the header's only state-mutating control. */
body.ro-calc-review-active .ro-header .acct:has(> .cart-btn[data-ro-cart-toggle]) { display: none; }
@keyframes fabRipple {
  0% { box-shadow: var(--ro-shadow-card), 0 0 0 0 rgb(var(--ro-rgb-secondary) / 0.15); }
  100% { box-shadow: var(--ro-shadow-card), 0 0 0 20px rgb(var(--ro-rgb-secondary) / 0); }
}

.fab-btn {
  height: 56px;
  padding: 0 20px 0 16px;
  border-radius: 999px;
  background: var(--ro-surface);
  color: var(--ro-secondary-strong);
  border: 1px solid var(--ro-border);
  box-shadow: var(--ro-shadow-card);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
  animation: fabRipple 3s infinite;
}
.fab-btn.fab-btn:focus, .fab-btn.fab-btn:active {
  background: var(--ro-surface);
  color: var(--ro-secondary-strong);
}
.fab-btn.fab-btn:hover, .fab-btn.fab-btn:focus:hover, .fab-btn.fab-btn:active:hover {
  box-shadow: var(--ro-shadow-card-hover);
  border-color: var(--ro-border-hover);
  background: var(--ro-surface-2);
  color: var(--ro-secondary-strong);
  animation: none;
}
.fab-btn.fab-btn:focus-visible { outline: 2px solid rgb(var(--ro-rgb-secondary)); outline-offset: 2px; }
.fab-btn svg { width: 22px; height: 22px; flex-shrink: 0; transition: opacity var(--ro-dur) var(--ro-ease); }

.fab-icon-open { position: absolute; opacity: 0; }
.fab-container.is-open .fab-btn .fab-icon-closed { opacity: 0; }
.fab-container.is-open .fab-btn .fab-icon-open { opacity: 1; }

.fab-text {
  font-size: var(--ro-fs-ui);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ro-foreground);
  transition: color var(--ro-dur) var(--ro-ease);
}
.fab-btn:hover .fab-text { color: var(--ro-primary-strong); }
.fab-container.is-open .fab-btn { width: 56px; padding: 0; }
.fab-container.is-open .fab-btn .fab-text { display: none; }
@media (max-width: 599px) {
  .fab-btn { width: 56px; padding: 0; }
  .fab-btn .fab-text { display: none; }
}

.fab-popover {
  position: absolute; bottom: calc(100% + 16px); right: 0; width: max-content; min-width: 220px;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 16px; box-shadow: var(--ro-shadow-card-hover);
  padding: 12px; display: flex; flex-direction: column; gap: 4px;
  opacity: 0; visibility: hidden;
  transition: opacity 240ms var(--ro-ease), visibility 240ms;
}
.fab-container.is-open .fab-popover { opacity: 1; visibility: visible; }

.fab-pill {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 20px; border-radius: 12px; margin-bottom: 8px;
  background: linear-gradient(135deg, var(--ro-secondary) 0%, var(--ro-secondary-strong) 100%);
  color: #fff; font-size: var(--ro-fs-ui); font-weight: 700; text-decoration: none;
  box-shadow: var(--ro-shadow-btn);
  transition: box-shadow var(--ro-dur) var(--ro-ease), filter var(--ro-dur) var(--ro-ease);
  min-height: 48px;
}
.fab-pill.fab-pill:focus, .fab-pill.fab-pill:active { color: #fff; }
.fab-pill.fab-pill:hover, .fab-pill.fab-pill:focus:hover, .fab-pill.fab-pill:active:hover { color: #fff; box-shadow: var(--ro-shadow-btn-hover); filter: brightness(1.05); }
.fab-pill.fab-pill:focus-visible { outline: 2px solid rgb(var(--ro-rgb-secondary)); outline-offset: 2px; }

.fab-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: 10px; min-height: 44px;
  font-size: var(--ro-fs-ui); font-weight: 600; color: var(--ro-foreground); text-decoration: none;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.fab-row { position: relative; }
.fab-row + .fab-row::before {
  content: ""; position: absolute; top: -2.5px; left: 12px; right: 12px;
  height: 1px; background: var(--ro-border); pointer-events: none;
}
.fab-row.fab-row:focus, .fab-row.fab-row:active { background: transparent; color: var(--ro-foreground); }
.fab-row.fab-row:hover, .fab-row.fab-row:focus:hover, .fab-row.fab-row:active:hover { background: rgb(var(--ro-rgb-secondary) / 0.1); color: var(--ro-secondary-strong); }
.fab-row.fab-row:focus-visible { outline: 2px solid rgb(var(--ro-rgb-secondary)); outline-offset: -2px; }
.fab-row .soc { width: 32px; height: 32px; box-shadow: none; pointer-events: none; }
.fab-row .soc svg { width: 16px; height: 16px; }

@media (prefers-reduced-motion: reduce) {
  .ro-hero-banner *, .ro-hero-banner *::before, .ro-hero-banner *::after,
  .fab-container, .fab-container *, .fab-popover {
    transition-duration: .01ms !important; animation: none !important;
  }
  .ro-btn:active, .ro-contact:active, .ro-iconbtn:active { transform: none; }
}

/* ============================================================
   ATOMS ADDENDUM (issue #35) — inverse button + social coins
   .soc/.socials are shared by the header drawer, footer brand
   column, and CTA-band popover (and give the FAB rows their coin
   colors — previously referenced but never defined).
============================================================ */
/* shadow ink #382E33 (56,46,51) is the tokens' own card-shadow ink
   (tokens.css --ro-shadow-card) at prototype-locked opacities — no rgb
   var exists for it, kept inline like tokens.css itself does */
.ro-btn--inverse {
  background: #fff; color: var(--ro-primary-strong);
  box-shadow: 0 2px 6px rgba(56,46,51,.18), 0 8px 20px rgba(56,46,51,.14);
}
.ro-btn.ro-btn--inverse:focus, .ro-btn.ro-btn--inverse:active { background: #fff; color: var(--ro-primary-strong); }
.ro-btn.ro-btn--inverse:hover, .ro-btn.ro-btn--inverse:focus:hover, .ro-btn.ro-btn--inverse:active:hover {
  background: #fff; color: var(--ro-primary-strong);
  box-shadow: 0 4px 10px rgba(56,46,51,.22), 0 12px 28px rgba(56,46,51,.18); filter: brightness(1.02);
}

.socials { display: flex; gap: 10px; flex-wrap: wrap; }
.soc {
  width: 44px; height: 44px; border-radius: 999px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; text-decoration: none;
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), filter var(--ro-dur) var(--ro-ease);
}
/* (0,3,0) re-assert — brand-colored coins must never take the theme's
   magenta a:hover flip; color stays white, only shadow/brightness move */
.soc.soc:hover, .soc.soc:focus:hover { color: #fff; box-shadow: var(--ro-shadow-card-hover); filter: brightness(1.08); }
.soc.soc:focus { color: #fff; }
.soc.soc:focus-visible { color: #fff; outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.soc:active { transform: scale(.97); }
.soc svg { width: 20px; height: 20px; }
.soc--insta  { background: linear-gradient(45deg,#F58529,#DD2A7B 60%,#8134AF); }
.soc--fb     { background: #1877F2; }
.soc--tiktok { background: #121212; }
.soc--wa     { background: #23A55A; }
.soc--msgr   { background: linear-gradient(135deg,#0695FF,#A334FA); }
.soc--tg     { background: #2AABEE; }
.soc--call   { background: linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%); }

/* ============================================================
   SITE HEADER (issue #35)
   Ported from .dev/prototypes/header-footer-soft-ui/index.html.
   Every interactive atom re-asserts color/background at (0,3,0)
   on :hover/:focus (hostile-rule convention, section-library.md).
============================================================ */
.ro-header {
  --hdr-utility-h: 54px;
  --hdr-nav-h: 62px;
  position: sticky; top: 0; z-index: 50;
  background: var(--ro-surface);
  border-bottom: 1px solid var(--ro-border);
  transition: box-shadow 300ms var(--ro-ease);
}
.ro-header.is-condensed { box-shadow: var(--ro-shadow-card); }
.ro-header .wrap,
.ro-footer .wrap,
.ro-footer-cta .wrap { max-width: var(--ro-content-max); margin-inline: auto; padding-inline: var(--ro-gutter); }

.ro-header .hdr-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 40px; align-items: center;
}
.ro-header .hdr-logo {
  grid-row: 1 / 3; align-self: center;
  display: inline-flex; border-radius: 8px;
}
/* fixed logo height must sit at (0,2,0)+ — Elementor's own
   `.elementor img { height:auto }` (0,1,1) collapses it otherwise */
.ro-header .hdr-logo img {
  height: 58px; width: auto; max-width: none;
  transition: height 400ms var(--ro-ease);
}
.ro-header .hdr-logo:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 4px; }

.ro-header .hdr-utility {
  grid-column: 2; grid-row: 1;
  display: flex; align-items: center; gap: 26px;
  height: var(--hdr-utility-h);
  border-bottom: 1px solid var(--ro-border);
  overflow: visible;
  transition: height 400ms var(--ro-ease), opacity 200ms var(--ro-ease),
              visibility 400ms, border-bottom-color 400ms var(--ro-ease);
}
.ro-header.is-condensed .hdr-utility {
  height: 0; opacity: 0; border-bottom-color: transparent;
  pointer-events: none; visibility: hidden;
  overflow: clip; /* row contents clip while the height animates, no overlap flash */
}
.ro-header.is-condensed .hdr-logo img { height: 40px; }

.ro-header .hdr-fact {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--ro-fs-ui-sm); font-weight: 600; color: var(--ro-muted-fg);
  text-decoration: none; border-radius: 8px; padding: 4px 6px;
  white-space: nowrap;
  transition: color 220ms var(--ro-ease);
}
.ro-header .hdr-fact svg { width: 16px; height: 16px; color: var(--ro-secondary-strong); flex: none; }
.ro-header a.hdr-fact.hdr-fact:hover { color: var(--ro-foreground); }
.ro-header a.hdr-fact.hdr-fact:focus-visible { color: var(--ro-muted-fg); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header a.hdr-fact--phone.hdr-fact--phone:focus-visible { color: var(--ro-foreground); }
.ro-header .hdr-fact--phone { font-size: var(--ro-fs-ui); font-weight: 800; color: var(--ro-foreground); }
.ro-header .hdr-fact--phone svg { color: var(--ro-primary-strong); }
.ro-header a.hdr-fact--phone.hdr-fact--phone:hover { color: var(--ro-primary-strong); }
.ro-header .hdr-utility__spacer { flex: 1; }

.ro-header .hdr-nav {
  grid-column: 2; grid-row: 2;
  display: flex; align-items: center;
  height: var(--hdr-nav-h); gap: 4px;
}
.ro-header .hdr-nav ul { display: flex; align-items: center; gap: 2px; list-style: none; margin: 0; padding: 0; }
.ro-header .nav-item { position: relative; display: flex; align-items: center; white-space: nowrap; }
.ro-header .nav-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--ro-fs-ui); font-weight: 700; color: var(--ro-foreground);
  text-decoration: none; padding: 10px 14px; border-radius: 10px;
  background: none; border: 0; cursor: pointer; font-family: inherit; min-height: 0;
  transition: color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
}
.ro-header button.nav-link svg { width: 14px; height: 14px; transition: transform var(--ro-dur) var(--ro-ease); }
.ro-header .nav-item.is-open > button.nav-link svg { transform: rotate(180deg); }
.ro-header .nav-link.nav-link:focus, .ro-header .nav-link.nav-link:active { color: var(--ro-foreground); background: none; }
.ro-header .nav-link.nav-link:hover, .ro-header .nav-link.nav-link:focus:hover, .ro-header .nav-link.nav-link:active:hover {
  color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-primary) / 0.07);
}
.ro-header .nav-link:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header .nav-item.is-open > .nav-link { color: var(--ro-primary-strong); }

.ro-header .dd-caret {
  width: 26px; height: 26px; margin-left: -8px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ro-muted-fg); cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header .dd-caret.dd-caret:focus, .ro-header .dd-caret.dd-caret:active { background: transparent; color: var(--ro-muted-fg); }
.ro-header .dd-caret.dd-caret:hover, .ro-header .dd-caret.dd-caret:focus:hover, .ro-header .dd-caret.dd-caret:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
}
.ro-header .dd-caret:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header .dd-caret svg { width: 14px; height: 14px; transition: transform var(--ro-dur) var(--ro-ease); }
.ro-header .nav-item.is-open .dd-caret svg { transform: rotate(180deg); }

.ro-header .dd-panel {
  position: absolute; top: calc(100% + 8px); left: 0; min-width: 230px;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 16px; box-shadow: var(--ro-shadow-card-hover);
  padding: 8px; z-index: 5;
  opacity: 0; visibility: hidden; translate: 0 -4px;
  transition: opacity var(--ro-dur) var(--ro-ease), visibility var(--ro-dur), translate var(--ro-dur) var(--ro-ease);
}
.ro-header .nav-item.is-open .dd-panel, .ro-header .acct.is-open .dd-panel { opacity: 1; visibility: visible; translate: 0 0; }
.ro-header .dd-panel a {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-radius: 10px; min-height: 42px;
  font-size: var(--ro-fs-ui); font-weight: 600; color: var(--ro-foreground); text-decoration: none;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header .dd-panel a:hover, .ro-header .dd-panel a:focus:hover {
  background: rgb(var(--ro-rgb-primary) / 0.07); color: var(--ro-primary-strong);
}
.ro-header .dd-panel a:focus-visible { color: var(--ro-foreground); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-header .dd-panel a.dd-all { color: var(--ro-primary-strong); font-weight: 700; }
.ro-header .dd-panel a.dd-all:hover { color: var(--ro-primary-strong); }
.ro-header .dd-panel hr { border: 0; border-top: 1px solid var(--ro-border); margin: 6px 10px; }
.ro-header .dd-panel--2col { min-width: 440px; }
.ro-header .dd-panel--2col .dd-cols { display: grid; grid-template-columns: 1fr 1fr; column-gap: 4px; }
.ro-header .dd-panel a svg { width: 17px; height: 17px; color: var(--ro-muted-fg); flex: none; }
.ro-header .dd-panel a:hover svg { color: var(--ro-primary-strong); }
.ro-header .dd-signout, .ro-header .dd-panel a.dd-signout:hover { color: var(--ro-primary-strong); }
.ro-header .acct-hello { padding: 10px 14px 4px; font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); font-weight: 600; }

.ro-header .nav-cta {
  display: flex; align-items: center; gap: 10px; margin-left: auto;
  opacity: 0; visibility: hidden; translate: 0 -6px; pointer-events: none;
  transition: opacity 260ms var(--ro-ease) 120ms, translate 300ms var(--ro-ease) 120ms, visibility 300ms;
}
.ro-header.is-condensed .nav-cta {
  opacity: 1; visibility: visible; translate: 0 0; pointer-events: auto;
}

.ro-header .acct { position: relative; }
.ro-header .acct-btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--ro-surface); color: var(--ro-foreground);
  border: 1px solid var(--ro-border); border-radius: 999px;
  min-height: 40px; padding: 6px 14px 6px 8px;
  font: inherit; font-size: var(--ro-fs-ui-sm); font-weight: 700; cursor: pointer;
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-header .acct-btn.acct-btn:focus, .ro-header .acct-btn.acct-btn:active { background: var(--ro-surface); color: var(--ro-foreground); }
.ro-header .acct-btn.acct-btn:hover, .ro-header .acct-btn.acct-btn:focus:hover, .ro-header .acct-btn.acct-btn:active:hover {
  background: var(--ro-surface); color: var(--ro-foreground);
  box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover);
}
.ro-header .acct-btn:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header .acct-btn:active { transform: scale(.97); }
.ro-header .acct-avatar {
  width: 28px; height: 28px; border-radius: 999px; flex: none;
  background: linear-gradient(135deg, var(--ro-secondary) 0%, var(--ro-secondary-strong) 100%);
  color: #fff; display: inline-flex; align-items: center; justify-content: center;
}
.ro-header .acct-avatar svg { width: 15px; height: 15px; }
.ro-header .acct--authed .acct-avatar {
  background: linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%);
  font-size: var(--ro-fs-meta); font-weight: 800;
}
.ro-header .acct .dd-panel { left: auto; right: 0; min-width: 240px; }
.ro-header .acct-name { max-width: 120px; overflow: hidden; text-overflow: ellipsis; }

.ro-header .cart-btn { position: relative; padding: 6px 10px; }
.ro-header .cart-badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 19px; height: 19px; border-radius: 999px; padding: 0 5px;
  background: linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%);
  color: #fff; font-size: var(--ro-fs-ui-micro); font-weight: 800; line-height: 19px; text-align: center;
  box-shadow: 0 2px 6px rgb(var(--ro-rgb-primary-strong) / 0.4);
}
.ro-header .cart-badge[hidden] { display: none; }
.ro-header .cart-btn > svg { width: 19px; height: 19px; }
.ro-header .cart-dd { min-width: 300px; padding: 12px; }
.ro-header .cart-empty { font-size: var(--ro-fs-ui-sm); font-weight: 600; color: var(--ro-muted-fg); padding: 10px 6px; margin: 0; }
.ro-header .cart-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 6px; border-radius: 10px;
}
.ro-header .cart-row + .cart-row { border-top: 1px solid var(--ro-border); border-radius: 0 0 10px 10px; }
.ro-header .cart-row__name { flex: 1; font-size: var(--ro-fs-ui); font-weight: 600; }
.ro-header .cart-row__price { font-size: var(--ro-fs-ui); font-weight: 800; color: var(--ro-primary-strong); }
.ro-header .cart-remove {
  width: 30px; height: 30px; border: 0; border-radius: 8px; cursor: pointer; padding: 0;
  background: transparent; color: var(--ro-muted-fg);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header .cart-remove.cart-remove:focus, .ro-header .cart-remove.cart-remove:active { background: transparent; color: var(--ro-muted-fg); }
.ro-header .cart-remove.cart-remove:hover, .ro-header .cart-remove.cart-remove:focus:hover, .ro-header .cart-remove.cart-remove:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
}
.ro-header .cart-remove:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-header .cart-remove svg { width: 15px; height: 15px; }
.ro-header .cart-total {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 6px 12px; font-size: var(--ro-fs-ui); font-weight: 700;
  border-top: 1px solid var(--ro-border); margin-top: 4px;
}
.ro-header .cart-total[hidden] { display: none; }
.ro-header .cart-dd .ro-btn { width: 100%; }
.ro-header .cart-dd .ro-btn[hidden] { display: none; }

/* ---- P5 global appointment cart (#240 P5, v3.117.0) ----
   The legacy .cart-dd panels above are still SERVER-RENDERED on purpose: they are the
   fallback for a visitor holding new HTML and a cached old sections.js. When the new
   controller runs it hides them and owns the cart itself, so these two rules have to
   out-rank .dd-panel's own visibility/display declarations - [hidden] alone loses to
   them. Note .ro-header .cart-dd's min-width:300px never applied on any surface:
   .ro-header .acct .dd-panel (0,3,0) beats it (0,2,0) and every panel is inside .acct.
   It is inert, it is not the geometry owner, and it is not what this release changes. */
.ro-header .acct[hidden], .ro-header .cart-dd[hidden] { display: none !important; }

.ro-cart-dialog {
  /* Right-anchored drawer. The old dropdown was 240px wide at EVERY width, which gave
     the service name 120px and wrapped a real title to four lines on a 1440 screen as
     surely as on a phone - a panel-width defect, never a mobile one. */
  width: min(420px, 92vw);
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0 0 0 auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--ro-surface);
  color: var(--ro-foreground);
  box-shadow: -18px 0 46px rgb(0 0 0 / 0.16);
  overflow: hidden;
}
.ro-cart-dialog::backdrop { background: rgb(0 0 0 / 0.42); }
.ro-cart-dialog[open] { display: flex; flex-direction: column; }

.ro-cart-dialog.ro-cart-dialog--confirm {
  width: min(420px, 92vw);
  max-width: 100%;
  /* fit-content, not auto: a modal dialog is inset:0, so auto height stretches it
     to the viewport (the UA default is fit-content for exactly this reason). */
  height: fit-content;
  max-height: calc(100% - 32px);
  margin: auto;
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  opacity: 0;
}
.ro-cart-dialog--confirm .ro-cart-dialog__body p { margin: 0; }
.ro-cart-dialog--confirm .ro-cart-dialog__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ro-stack-xs);
}
/* Stacked at every width: the labels carry full service names, which clip in a 2-up row. */
.ro-cart-dialog--confirm .ro-cart-dialog__foot .ro-btn { width: 100%; min-height: 44px; white-space: normal; }
.ro-cart-dialog.ro-cart-dialog--confirm[open] { opacity: 1; animation: none; }

@media (prefers-reduced-motion: no-preference) {
  .ro-cart-dialog.ro-cart-dialog--confirm {
    transition:
      opacity var(--ro-dur) var(--ro-ease),
      display var(--ro-dur) allow-discrete,
      overlay var(--ro-dur) allow-discrete;
  }
  @starting-style {
    .ro-cart-dialog.ro-cart-dialog--confirm[open] { opacity: 0; }
  }
}
@media (prefers-reduced-motion: reduce) {
  .ro-cart-dialog.ro-cart-dialog--confirm { transition: none; }
}

.ro-cart-dialog__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 12px 16px 20px;
  border-bottom: 1px solid var(--ro-border);
  flex: none;
}
.ro-cart-dialog__title { font-size: 18px; font-weight: 800; margin: 0; }
.ro-cart-dialog__close {
  /* 44px because showModal() puts the three header toggles behind the top layer:
     the control that opened the cart cannot close it, and Esc is not a touch
     affordance. */
  width: 44px; height: 44px; flex: none;
  border: 0; border-radius: 12px; padding: 0; cursor: pointer;
  background: transparent; color: var(--ro-muted-fg);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
/* Hostile-Kit counter, R6's rule: answer EVERY property the hostile rule sets, not
   just colour. Hello's `button:hover { background-color: #CC3366 }` and its :focus
   pair otherwise ambush a keyboard user with magenta-on-magenta - measured 1.016:1
   when v3.99.0 re-asserted colour alone. Written at (0,3,0), NOT (0,2,0): (0,2,0)
   merely ties Hello and a tie is decided by print order, which a CSS-combining plugin
   can flip. :focus-visible is not a defence against a hostile :focus. */
.ro-cart-dialog__close.ro-cart-dialog__close:focus,
.ro-cart-dialog__close.ro-cart-dialog__close:active {
  background: transparent; color: var(--ro-muted-fg);
}
.ro-cart-dialog__close.ro-cart-dialog__close:hover,
.ro-cart-dialog__close.ro-cart-dialog__close:focus:hover,
.ro-cart-dialog__close.ro-cart-dialog__close:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
}
.ro-cart-dialog__close:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-cart-dialog__close svg { width: 18px; height: 18px; }

.ro-cart-dialog__body { flex: 1 1 auto; overflow-y: auto; padding: 8px 20px 16px; }
.ro-cart-dialog__empty { font-size: var(--ro-fs-ui); font-weight: 600; color: var(--ro-muted-fg); padding: 24px 0; margin: 0; }

.ro-cart-item { position: relative; padding: 16px 44px 16px 0; }
.ro-cart-item + .ro-cart-item { border-top: 1px solid var(--ro-border); }
.ro-cart-item__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0; }
/* The name gets the room the 240px panel never gave it. */
.ro-cart-item__name { font-size: var(--ro-fs-ui); font-weight: 700; line-height: 1.3; margin: 0; flex: 0 1 auto; min-width: 0; }
.ro-cart-item__price { font-size: var(--ro-fs-ui); font-weight: 800; color: var(--ro-primary-strong); flex: none; }
.ro-cart-item__price.is-discounted,
.ro-cart-addon__value.is-discounted,
.ro-cart-total-row__value.is-discounted { color: var(--ro-success-text); }
.ro-cart-item__price.is-discounted,
.ro-cart-addon__value.is-discounted,
.ro-cart-total-row__value.is-discounted {
  display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap;
}
.ro-cart-price__old {
  color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); font-weight: 500;
  text-decoration: line-through;
}
.ro-cart-leader {
  flex: 1 1 0; min-width: 0; align-self: baseline; margin-inline: 6px;
  border-bottom: 1px dotted var(--ro-border); overflow: hidden;
}
.ro-cart-item__meta { font-size: var(--ro-fs-meta); font-weight: 600; color: var(--ro-muted-fg); margin: 4px 0 0; }
.ro-cart-item__note { font-size: var(--ro-fs-meta); font-weight: 600; color: var(--ro-muted-fg); margin: 8px 0 0; }
.ro-cart-item__edit {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; margin-top: 8px; padding: 0 8px;
  border: 0; border-radius: 12px; background: transparent; color: var(--ro-muted-fg);
  font: inherit; font-size: var(--ro-fs-meta); font-weight: 700; text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
/* Same hostile-Kit counter as the Close and Remove controls in this block, and it
   NEUTRALISES rather than styles: :focus/:active re-assert the resting pair so the Kit
   cannot repaint them, and hover is the only state that moves. Both properties are
   re-asserted, never colour alone. The moved-to colour is the -text tier, not -strong:
   -strong is the decoration tier and this is the one new piece of TEXT here (R6). */
.ro-cart-item__edit.ro-cart-item__edit:focus,
.ro-cart-item__edit.ro-cart-item__edit:active {
  background: transparent; color: var(--ro-muted-fg);
}
.ro-cart-item__edit.ro-cart-item__edit:hover,
.ro-cart-item__edit.ro-cart-item__edit:focus:hover,
.ro-cart-item__edit.ro-cart-item__edit:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-text);
}
.ro-cart-item__edit:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-cart-item__remove {
  position: absolute; top: 12px; right: 0;
  width: 44px; height: 44px; border: 0; border-radius: 12px; padding: 0; cursor: pointer;
  background: transparent; color: var(--ro-muted-fg);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
/* Same hostile-Kit counter as the Close control above, and for the same reason. */
.ro-cart-item__remove.ro-cart-item__remove:focus,
.ro-cart-item__remove.ro-cart-item__remove:active {
  background: transparent; color: var(--ro-muted-fg);
}
.ro-cart-item__remove.ro-cart-item__remove:hover,
.ro-cart-item__remove.ro-cart-item__remove:focus:hover,
.ro-cart-item__remove.ro-cart-item__remove:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
}
.ro-cart-item__remove:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-cart-item__remove svg { width: 15px; height: 15px; }

.ro-cart-addons { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.ro-cart-addon { display: flex; align-items: baseline; justify-content: space-between; gap: 0; font-size: var(--ro-fs-ui-sm); }
.ro-cart-addon__name { color: var(--ro-muted-fg); font-weight: 600; flex: 0 1 auto; min-width: 0; }
.ro-cart-addon__value { font-weight: 700; flex: none; }
/* "Included" is a duration statement, not a price of zero - the distinction is keyed
   on the addon's GROUP, resolved server-side, never on the number being 0. */
.ro-cart-addon__value.is-included { color: var(--ro-muted-fg); font-weight: 600; }

.ro-cart-dialog__foot { flex: none; padding: 14px 20px 20px; border-top: 1px solid var(--ro-border); }
.ro-cart-total-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: var(--ro-fs-ui); font-weight: 800; margin-bottom: 12px; }
.ro-cart-total-row__value { color: var(--ro-primary-strong); }
.ro-cart-dialog__note { font-size: var(--ro-fs-meta); font-weight: 600; color: var(--ro-muted-fg); margin: 0 0 12px; }
.ro-cart-dialog__cta { width: 100%; }

@media (max-width: 768px) {
  /* Full-height sheet. The 768/769 boundary is the calculator's own, reused rather
     than re-invented. */
  .ro-cart-dialog { width: 100%; max-width: 100%; margin: 0; }
  .ro-cart-dialog__head { padding-left: 16px; }
  .ro-cart-dialog__body { padding-left: 16px; padding-right: 16px; }
  .ro-cart-dialog__foot { padding-left: 16px; padding-right: 16px; }
}

@media (prefers-reduced-motion: no-preference) {
  .ro-cart-dialog[open] { animation: roCartSlideIn var(--ro-dur-slow, .28s) var(--ro-ease) both; }
  @keyframes roCartSlideIn { from { transform: translateX(3%); opacity: .4; } to { transform: none; opacity: 1; } }
}

.ro-header .hdr-mobile { display: none; }
.ro-header .burger {
  width: 48px; height: 48px; border-radius: 12px; padding: 0;
  border: 1px solid var(--ro-border); background: var(--ro-surface);
  color: var(--ro-foreground); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-header .burger.burger:focus, .ro-header .burger.burger:active { background: var(--ro-surface); color: var(--ro-foreground); }
.ro-header .burger.burger:hover, .ro-header .burger.burger:focus:hover, .ro-header .burger.burger:active:hover {
  background: var(--ro-surface); color: var(--ro-foreground);
  box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover);
}
.ro-header .burger:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header .burger:active { transform: scale(.97); }
.ro-header .burger svg { width: 22px; height: 22px; }

/* Priority+ tier 1024–1279: fold collapsible items into "More",
   tighten gaps; burger only below 1024 */
.ro-header .nav-more { display: none; }
@media (min-width: 1024px) and (max-width: 1279px) {
  .ro-header .nav-more { display: flex; }
  .ro-header .nav-item--collapsible { display: none; }
  .ro-header .hdr-grid { column-gap: 26px; }
  .ro-header .hdr-utility { gap: 16px; }
  .ro-header .nav-link { padding: 10px 10px; }
}
@media (max-width: 1023px) {
  .ro-header .hdr-grid { display: none; }
  .ro-header .hdr-mobile {
    display: flex; align-items: center; gap: 12px;
    height: 64px;
  }
  /* The logo is the ONLY shrinkable item in this row - everything beside it is a
     touch target or a nowrap CTA. The base rule at :1439 sets `max-width: none`
     (it is there to survive Elementor's `.elementor img { height:auto }`, see the
     comment above it) and that inherited straight into the mobile row, so the row
     had an intrinsic 382px - logo 185 + Book 72 + cart 41 + burger 48 + 3x12 gap -
     against a container of `viewport - 48`. Every viewport under ~430px therefore
     overflowed: measured `document.scrollWidth` 381 at BOTH 360 and 320 CSS px,
     logged in and logged out alike. That is a 21px horizontal page scroll on every
     phone, on every page; in the logged-in run Android Chrome additionally shrank
     the whole document to fit (`visualViewport.scale` 0.945 at 360, 0.840 at 320),
     which re-anchors every `position: fixed` surface - the calculator's mobile bar
     and its sheets included - to a 381px ICB.
     Constrain by max-height rather than a fixed height so the aspect ratio survives
     the shrink; a fixed `height` plus a binding `max-width` squashes the image. */
  .ro-header .hdr-mobile .hdr-logo { margin-right: auto; min-width: 0; }
  .ro-header .hdr-mobile .hdr-logo img {
    height: auto; max-height: 40px; width: auto; max-width: 100%;
  }
  /* Nothing else may absorb the deficit. The burger declares 48px and was measured
     at 24px wide purely as flex-shrink fallout - a touch target halved by a layout
     accident. */
  .ro-header .hdr-mobile > :not(.hdr-logo) { flex: none; }
}
@media (max-width: 480px) {
  /* Without this the fix above trades an overflow for a 16px-tall logo at 320px:
     the row's fixed cost leaves it only 75px. Buying 24px back from the gaps and
     8px/side from the header's own gutter lets the logo reach full 40px height by
     ~412px and keeps it >=22px at 320. Scoped to `.ro-header .wrap` so the footer
     surfaces that share the `.wrap` class keep their 24px gutter. */
  .ro-header .wrap { padding-inline: 16px; }
  .ro-header .hdr-mobile { gap: 8px; }
}

/* ---- mobile drawer ---- */
.ro-header-scrim {
  position: fixed; inset: 0; z-index: 70;
  background: rgb(var(--ro-rgb-sidebar) / .45);
  opacity: 0; visibility: hidden;
  transition: opacity var(--ro-dur) var(--ro-ease), visibility var(--ro-dur);
}
.ro-header-scrim[hidden] { display: none; }
.ro-header-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 71;
  width: min(360px, 88vw);
  background: var(--ro-surface);
  box-shadow: -12px 0 40px rgba(56,46,51,.18);
  border-radius: 20px 0 0 20px;
  display: flex; flex-direction: column;
  translate: 100% 0;
  transition: translate 340ms var(--ro-ease);
}
.ro-header-drawer[hidden] { display: none; }
body.ro-drawer-open .ro-header-scrim { opacity: 1; visibility: visible; }
body.ro-drawer-open .ro-header-drawer { translate: 0 0; }
body.ro-drawer-open { overflow: hidden; }

.ro-header-drawer .drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 14px 14px 20px; border-bottom: 1px solid var(--ro-border);
}
.ro-header-drawer .drawer-head img { height: 34px; width: auto; }
.ro-header-drawer .drawer-close {
  width: 44px; height: 44px; border-radius: 12px; border: 0; padding: 0;
  background: var(--ro-surface-2); color: var(--ro-muted-fg); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header-drawer .drawer-close.drawer-close:focus, .ro-header-drawer .drawer-close.drawer-close:active { background: var(--ro-surface-2); color: var(--ro-muted-fg); }
.ro-header-drawer .drawer-close.drawer-close:hover, .ro-header-drawer .drawer-close.drawer-close:focus:hover, .ro-header-drawer .drawer-close.drawer-close:active:hover {
  background: rgb(var(--ro-rgb-primary) / 0.1); color: var(--ro-primary-strong);
}
.ro-header-drawer .drawer-close:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header-drawer .drawer-close svg { width: 20px; height: 20px; }

.ro-header-drawer .drawer-body { flex: 1; overflow-y: auto; padding: 10px 12px 20px; }
.ro-header-drawer .drawer-nav ul { list-style: none; margin: 0; padding: 0; }
.ro-header-drawer .dn-row { display: flex; align-items: center; }
.ro-header-drawer .dn-link {
  flex: 1; display: flex; align-items: center; min-height: 48px;
  padding: 10px 12px; border-radius: 12px;
  font-size: var(--ro-fs-ui); font-weight: 700; color: var(--ro-foreground); text-decoration: none;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header-drawer .dn-link.dn-link:hover, .ro-header-drawer .dn-link.dn-link:focus:hover {
  background: rgb(var(--ro-rgb-primary) / 0.07); color: var(--ro-primary-strong);
}
.ro-header-drawer .dn-link:focus-visible { color: var(--ro-foreground); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-header-drawer .dn-caret {
  width: 48px; height: 48px; border: 0; border-radius: 12px; flex: none; padding: 0;
  background: transparent; color: var(--ro-muted-fg); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
}
.ro-header-drawer .dn-caret.dn-caret:focus, .ro-header-drawer .dn-caret.dn-caret:active { background: transparent; color: var(--ro-muted-fg); }
.ro-header-drawer .dn-caret.dn-caret:hover, .ro-header-drawer .dn-caret.dn-caret:focus:hover, .ro-header-drawer .dn-caret.dn-caret:active:hover {
  background: var(--ro-surface-2); color: var(--ro-primary-strong);
}
.ro-header-drawer .dn-caret:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }
.ro-header-drawer .dn-caret svg { width: 16px; height: 16px; transition: transform var(--ro-dur) var(--ro-ease); }
.ro-header-drawer .dn-item.is-open .dn-caret svg { transform: rotate(180deg); }

.ro-header-drawer .dn-sub {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 260ms var(--ro-ease);
}
.ro-header-drawer .dn-sub > div { overflow: hidden; }
.ro-header-drawer .dn-item.is-open .dn-sub { grid-template-rows: 1fr; }
.ro-header-drawer .dn-sub a {
  display: flex; align-items: center; min-height: 44px;
  margin-left: 14px; padding: 8px 12px; border-left: 2px solid var(--ro-border);
  font-size: var(--ro-fs-ui); font-weight: 600; color: var(--ro-muted-fg); text-decoration: none;
  transition: color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
}
.ro-header-drawer .dn-sub a:hover, .ro-header-drawer .dn-sub a:focus:hover {
  color: var(--ro-primary-strong); border-left-color: var(--ro-primary); background: rgb(var(--ro-rgb-primary) / 0.05);
}
.ro-header-drawer .dn-sub a:focus-visible { color: var(--ro-muted-fg); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px; }

.ro-header-drawer .drawer-divider { border: 0; border-top: 1px solid var(--ro-border); margin: 12px 8px; }
.ro-header-drawer .drawer-label {
  font-size: var(--ro-fs-ui-micro); font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ro-muted-fg); padding: 4px 12px 6px;
}
.ro-header-drawer .drawer-contact { padding: 0 8px; display: flex; flex-direction: column; gap: 10px; }
.ro-header-drawer .drawer-hours {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: var(--ro-fs-ui-sm); font-weight: var(--ro-fw-body); color: var(--ro-muted-fg); padding: 2px 4px;
}
.ro-header-drawer .drawer-hours svg { width: 16px; height: 16px; color: var(--ro-secondary-strong); flex: none; margin-top: 4px; }
.ro-header-drawer .drawer-hours b { color: var(--ro-foreground); font-weight: 700; }
.ro-header-drawer .drawer-phone {
  display: inline-flex; align-items: center; gap: 10px; min-height: 48px;
  padding: 8px 12px; border-radius: 12px; text-decoration: none;
  font-size: 17px; font-weight: 800; color: var(--ro-foreground);
  background: var(--ro-surface-2); border: 1px solid var(--ro-border);
  transition: border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease);
}
.ro-header-drawer .drawer-phone.drawer-phone:hover {
  color: var(--ro-foreground); border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card);
}
.ro-header-drawer .drawer-phone:focus-visible { color: var(--ro-foreground); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-header-drawer .drawer-phone svg { width: 18px; height: 18px; color: var(--ro-primary-strong); }

/* ============================================================
   SITE FOOTER (issue #35) — CTA band + columns + legal bar
============================================================ */
.ro-footer-cta { padding: var(--ro-section-gap) 0 64px; }
.ro-footer-cta .cta-card {
  position: relative; overflow: hidden;
  border-radius: 24px;
  background:
    radial-gradient(120% 160% at 85% -20%, rgb(var(--ro-rgb-accent) / .35) 0%, transparent 55%),
    radial-gradient(150% 140% at -10% 110%, rgb(var(--ro-rgb-secondary) / .3) 0%, transparent 50%),
    linear-gradient(135deg, var(--ro-primary) 0%, var(--ro-primary-strong) 100%);
  box-shadow: var(--ro-shadow-btn);
  padding: 52px 56px;
  display: flex; align-items: center; justify-content: space-between; gap: 32px; flex-wrap: wrap;
}
/* height at (0,2,0) — beats Elementor's `.elementor img{height:auto}` */
.ro-footer-cta .cta-pattern {
  position: absolute; inset: 0; width: 100%; height: 100%; max-width: none;
  object-fit: cover; opacity: .28; pointer-events: none;
}
.ro-footer-cta .cta-card > :not(.cta-pattern) { position: relative; z-index: 2; }
/* section-root prefix beats the Kit's (0,1,1) h2 color re-point */
.ro-footer-cta .cta-card h2 {
  font-family: var(--ro-font-serif); font-weight: 900; color: #fff;
  font-size: var(--ro-fs-h2); line-height: 1.2; letter-spacing: -.01em; margin: 0;
}
/* Lead copy. */
.ro-footer-cta .cta-card p { color: rgb(255 255 255 / .85); font-size: var(--ro-fs-lead); font-weight: 500; margin: 6px 0 0; max-width: var(--ro-measure-lead); }
.ro-footer-cta .cta-actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.ro-footer-cta .cta-contact { position: relative; display: inline-flex; }
.ro-footer-cta .cta-contact-btn {
  background: rgb(255 255 255 / .12); color: #fff;
  border-color: rgb(255 255 255 / .55); backdrop-filter: blur(2px);
}
.ro-footer-cta .cta-contact-btn.cta-contact-btn:focus, .ro-footer-cta .cta-contact-btn.cta-contact-btn:active {
  background: rgb(255 255 255 / .12); color: #fff;
}
.ro-footer-cta .cta-contact-btn.cta-contact-btn:hover, .ro-footer-cta .cta-contact-btn.cta-contact-btn:focus:hover, .ro-footer-cta .cta-contact-btn.cta-contact-btn:active:hover {
  background: rgb(255 255 255 / .22); border-color: #fff; color: #fff;
}
.ro-footer-cta .cta-contact-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.ro-footer-cta .cta-contact-btn svg { transition: transform var(--ro-dur) var(--ro-ease); }
.ro-footer-cta .cta-contact.is-open .cta-contact-btn svg { transform: rotate(45deg); }
.ro-footer-cta .cta-messengers {
  position: absolute; bottom: calc(100% + 12px); left: 50%; z-index: 5;
  display: flex; gap: 8px; padding: 8px;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: 999px; box-shadow: var(--ro-shadow-card-hover);
  opacity: 0; visibility: hidden; translate: -50% 8px;
  transition: opacity 240ms var(--ro-ease), translate 280ms var(--ro-ease), visibility 280ms;
}
.ro-footer-cta .cta-contact.is-open .cta-messengers { opacity: 1; visibility: visible; translate: -50% 0; }

.ro-footer { background: var(--ro-surface); border-top: 1px solid var(--ro-border); }
.ro-footer .ftr-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1.3fr;
  gap: 48px;
  padding: 56px 0 48px;
}
.ro-footer .ftr-brand img { height: 46px; width: auto; max-width: none; margin-bottom: 16px; }
/* Meta copy. */
.ro-footer .ftr-brand p { color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); max-width: 30ch; margin: 0 0 20px; }
.ro-footer .ftr-col h3 {
  font-size: var(--ro-fs-ui-micro); font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ro-foreground); margin: 0 0 16px;
}
.ro-footer .ftr-acc-btn {
  /* border-radius is part of the Hello Elementor bare-<button> block (3px) — this atom
     already neutralises its colour/border/padding/hover pair, but not the radius, so the
     theme's 3px was still landing on the footer accordion headers. Declaring later is not
     enough on its own: every property the hostile rule sets has to be answered. */
  background: none; border: 0; border-radius: 0; padding: 0; cursor: default;
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  display: inline-flex; align-items: center; gap: 6px;
}
.ro-footer .ftr-acc-btn.ftr-acc-btn:hover, .ro-footer .ftr-acc-btn.ftr-acc-btn:focus, .ro-footer .ftr-acc-btn.ftr-acc-btn:active,
.ro-footer .ftr-acc-btn.ftr-acc-btn:focus:hover, .ro-footer .ftr-acc-btn.ftr-acc-btn:active:hover {
  background: none; color: inherit;
}
.ro-footer .ftr-acc-btn:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-footer .ftr-acc-btn svg { display: none; width: 14px; height: 14px; transition: transform var(--ro-dur) var(--ro-ease); }
.ro-footer .ftr-acc-body { display: grid; grid-template-rows: 1fr; }
.ro-footer .ftr-acc-body > ul { overflow: hidden; }
.ro-footer .ftr-col ul { list-style: none; display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; }
.ro-footer .ftr-col ul a {
  display: inline-flex; align-items: center; min-height: 34px;
  font-size: var(--ro-fs-ui); font-weight: 600; color: var(--ro-muted-fg); text-decoration: none;
  border-radius: 8px; padding: 2px 8px; margin-left: -8px;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat; background-position: 8px calc(100% - 5px);
  background-size: 0 1.5px;
  transition: color 220ms var(--ro-ease), background-size 260ms var(--ro-ease);
}
.ro-footer .ftr-col ul a:hover, .ro-footer .ftr-col ul a:focus:hover {
  color: var(--ro-primary-strong); background-size: calc(100% - 16px) 1.5px;
}
.ro-footer .ftr-col ul a:focus-visible { color: var(--ro-muted-fg); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 0; }

.ro-footer .ftr-visit { display: flex; flex-direction: column; gap: 14px; }
.ro-footer .ftr-fact {
  display: flex; align-items: flex-start; gap: 12px;
  font-size: var(--ro-fs-ui); color: var(--ro-muted-fg); font-weight: 500;
}
.ro-footer .ftr-fact svg { width: 17px; height: 17px; flex: none; margin-top: 3px; color: var(--ro-primary-strong); }
.ro-footer .ftr-fact a {
  color: var(--ro-foreground); font-weight: 700; text-decoration: none; border-radius: 6px;
  transition: color 220ms var(--ro-ease);
}
.ro-footer .ftr-fact a:hover, .ro-footer .ftr-fact a:focus:hover { color: var(--ro-primary-strong); }
.ro-footer .ftr-fact a:focus-visible { color: var(--ro-foreground); outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-footer .ftr-hours-rows { display: flex; flex-direction: column; gap: 2px; }
.ro-footer .ftr-hours-rows div { display: flex; justify-content: space-between; gap: 18px; }
.ro-footer .ftr-hours-rows b { color: var(--ro-foreground); font-weight: 700; }
.ro-footer .ftr-hours-note { font-size: var(--ro-fs-meta); font-style: italic; color: var(--ro-muted-fg); margin-top: 4px; }

.ro-footer .ftr-legal {
  background: linear-gradient(180deg, rgb(var(--ro-rgb-sidebar)) 0%, rgb(var(--ro-rgb-sidebar-deep)) 100%);
  color: rgb(var(--ro-rgb-sidebar-muted));
  font-size: var(--ro-fs-meta); font-weight: 500;
}
.ro-footer .ftr-legal .wrap {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding-top: 18px; padding-bottom: 18px;
}
.ro-footer .ftr-legal nav { display: flex; gap: 20px; }
.ro-footer .ftr-legal a {
  color: rgb(var(--ro-rgb-sidebar-fg)); text-decoration: none; font-weight: 600;
  border-radius: 6px; min-height: 32px; display: inline-flex; align-items: center;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat; background-position: 0 calc(100% - 5px);
  background-size: 0 1.5px;
  transition: color 220ms var(--ro-ease), background-size 260ms var(--ro-ease);
}
.ro-footer .ftr-legal a:hover, .ro-footer .ftr-legal a:focus:hover { color: var(--ro-primary); background-size: 100% 1.5px; }
.ro-footer .ftr-legal a:focus-visible { color: rgb(var(--ro-rgb-sidebar-fg)); outline: 2px solid var(--ro-primary); outline-offset: 3px; }

@media (max-width: 1023px) {
  .ro-footer .ftr-grid { grid-template-columns: 1fr 1fr 1.3fr; gap: 32px 28px; padding: 48px 0 44px; }
  .ro-footer .ftr-brand {
    grid-column: 1 / -1;
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 40px;
    padding-bottom: 28px; border-bottom: 1px solid var(--ro-border);
  }
  .ro-footer .ftr-brand img { margin-bottom: 0; }
  .ro-footer .ftr-brand p { margin-bottom: 0; flex: 1; min-width: 220px; max-width: none; }
  .ro-footer .ftr-brand .socials { width: 100%; margin-top: 10px; }
}
@media (max-width: 599px) {
  .ro-footer .ftr-grid { grid-template-columns: 1fr; gap: 26px; padding: 44px 0 40px; text-align: center; }
  .ro-footer .ftr-brand { display: block; border-bottom: 0; padding-bottom: 8px; }
  .ro-footer .ftr-brand img { margin: 0 auto 16px; }
  .ro-footer .ftr-brand p { margin: 0 auto 20px; }
  .ro-footer .ftr-brand .socials { margin-top: 0; }
  .ro-footer .socials { justify-content: center; }
  .ro-footer .ftr-col ul a { justify-content: center; margin-left: 0; }
  .ro-footer .ftr-fact { justify-content: center; text-align: left; }
  .ro-footer .ftr-fact--hours { flex-direction: column; align-items: center; gap: 8px; }
  .ro-footer .ftr-fact--hours svg { margin-top: 0; }
  .ro-footer .ftr-hours-rows div { justify-content: center; gap: 14px; }
  .ro-footer .ftr-hours-rows .ftr-hours-note { text-align: center; }
  /* Services + Explore become accordions (mobile only) */
  .ro-footer .ftr-acc-btn { cursor: pointer; min-height: 44px; }
  .ro-footer .ftr-acc-btn svg { display: inline-block; }
  .ro-footer .ftr-col--acc h3 { margin-bottom: 2px; }
  .ro-footer .ftr-col--acc .ftr-acc-body {
    grid-template-rows: 0fr;
    transition: grid-template-rows 300ms var(--ro-ease);
  }
  .ro-footer .ftr-col--acc.is-open .ftr-acc-body { grid-template-rows: 1fr; }
  .ro-footer .ftr-col--acc.is-open .ftr-acc-btn svg { transform: rotate(180deg); }
  .ro-footer-cta .cta-card { padding: 36px 28px; text-align: center; }
  .ro-footer-cta .cta-card p { margin-left: auto; margin-right: auto; }
  .ro-footer-cta .cta-card .ro-btn { width: 100%; }
  .ro-footer-cta .cta-actions { width: 100%; justify-content: center; }
  .ro-footer-cta .cta-contact { width: 100%; }
  .ro-footer .ftr-legal .wrap { justify-content: center; text-align: center; }
}

@media (prefers-reduced-motion: reduce) {
  .ro-header, .ro-header *, .ro-header *::before, .ro-header *::after,
  .ro-header-drawer, .ro-header-drawer *, .ro-header-scrim,
  .ro-footer, .ro-footer *, .ro-footer-cta, .ro-footer-cta * {
    transition-duration: .01ms !important; animation: none !important;
  }
  .ro-header .acct-btn:active, .ro-header .burger:active, .soc:active { transform: none; }
}

/* ============================================================
   WORKS SLIDER (issue #58 v2 carousel)
============================================================ */

.rws-head { max-width: 680px; margin-bottom: 28px; }
.rws-eyebrow {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ro-muted-fg); margin-bottom: 14px;
}
.rws-eyebrow svg { width: 14px; height: 14px; flex: none; }
.rws-eyebrow::after { content: ""; flex: 1; height: 1px; background: var(--ro-border); }
h2.rws-title {
  font-family: var(--ro-font-serif); font-weight: 900;
  font-size: var(--ro-fs-h2); line-height: 1.2; letter-spacing: -.01em;
  color: var(--ro-foreground); margin: 0;
}

.rws-stage-wrap { position: relative; }
.rws-stage {
  display: flex; align-items: stretch; gap: 20px; overflow-x: auto;
  padding: 4px max(24px, calc((100vw - 1200px) / 2 + 24px)) 24px;
  margin-inline: calc(50% - 50vw); scroll-padding-inline: max(24px, calc((100vw - 1200px) / 2 + 24px));
  scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  overscroll-behavior-inline: contain;
}
.rws-stage::-webkit-scrollbar { display: none; }

.rws-card {
  position: relative; display: flex; flex: 0 0 clamp(286px, 76vw, 520px); flex-direction: column;
  min-height: 100%; overflow: hidden; scroll-snap-align: center;
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card); box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease),
    opacity var(--ro-dur) var(--ro-ease);
}
.rws-card.is-active { border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card-hover); }
.rws-card[hidden] { display: none; }

.rws-card__media { position: relative; }
.media-stage { position: relative; overflow: hidden; aspect-ratio: 4 / 4.7; background: var(--ro-surface-2); border-radius: inherit; }
.media-slide {
  position: absolute; inset: 0; overflow: hidden; opacity: 0; visibility: hidden;
  transition: opacity var(--ro-dur) var(--ro-ease), visibility var(--ro-dur) var(--ro-ease);
  pointer-events: none;
}
.media-slide.is-active { opacity: 1; visibility: visible; z-index: 2; pointer-events: auto; }

.media-slide__poster {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0;
}
.rws-img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Elementor's `.elementor img { height: auto }` (0,1,1) out-ranks the rule above, so inside any Elementor
   widget a 5:4 photo kept its own height and left an empty band under it in the 4:4.7 card (measured
   2026-10-21: 318px image in a 453px frame on every landscape look). (0,2,0) restores the cover fill. */
.media-stage .rws-img { height: 100%; }
/* A photo wider than the frame (section-works-slider.php): the box is the painted crop, so sizes="auto"
   picks a candidate for the width actually shown instead of upscaling a card-width one ~1.47x. */
.media-stage .rws-img--wide { position: absolute; top: 0; left: 50%; width: auto; max-width: none; transform: translateX(-50%); }

.media-slide--video video {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; object-fit: cover;
  opacity: 0; background: transparent; transition: opacity var(--ro-dur) var(--ro-ease);
}
.media-slide--video.is-playing video { opacity: 1; }
.video-scrim {
  position: absolute; inset: 0; z-index: 3; background: rgb(var(--ro-rgb-sidebar) / .53);
  opacity: 0; pointer-events: none; transition: opacity var(--ro-dur) var(--ro-ease);
}
.media-slide--video.is-gated .video-scrim { opacity: 1; }

.media-badge {
  position: absolute; top: 16px; right: 16px; z-index: 8; display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 9px; border: 1px solid rgb(255 255 255 / .3); border-radius: 999px;
  color: #fff; background: rgb(var(--ro-rgb-sidebar) / .56); backdrop-filter: blur(10px);
  font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.media-badge svg { width: 14px; height: 14px; }

/* #223 S2: deleted with the markup that emitted them — .media-expand,
   .video-mute, .video-play, .video-flash, .media-counter
   and .media-dots. S1 removed all six from both card renderers (one hero
   media item per card, and no interactive control may sit inside the Work
   anchor); the rules outlived them by one release. .video-scrim and
   .media-badge above are still emitted and stay. */

.rws-card__body { display: grid; gap: 14px; padding: 16px 18px 18px; }
/* Wraps because the row is no longer only short taxonomy pills (#223 S1 added the
   service chip, which is authored prose up to 60 chars). Measured 2026-08-19 at
   360/390px on the real renderer: without `wrap` the row laid out 426.7px wide
   inside a 314px card and squeezed the service chip to 73.8x108px — a four-line
   sliver beside 27px siblings. `min-width: 0` is the other half: .rws-card__body
   is a grid, and a grid item's `auto` minimum let this row push past the card.
   Inert whenever the chips already fit, which is every desktop width. */
.card-meta { display: flex; flex-wrap: wrap; min-width: 0; align-items: center; gap: 8px; min-height: 24px; }

.rws-chip {
  display: inline-flex; align-items: center;
  padding: 5px 10px; border-radius: 999px;
  font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ro-muted-fg); background: var(--ro-surface-2);
  border: 1px solid var(--ro-border);
}
.rws-chip--premium {
  color: var(--ro-secondary-strong); background: rgb(var(--ro-rgb-secondary) / .15);
  border-color: transparent;
}
.rws-chip--standard, .rws-chip--tag {
  color: var(--ro-muted-fg); background: var(--ro-surface-2);
  border-color: var(--ro-border);
}
/* Tag chips leave the card's PRESENTATION but stay in its DOM (#223 S5d, Owner item 1).
   display:none takes them out of the accessibility tree too, which is what "removed from the
   presentation UI" means, while querySelectorAll is unaffected by CSS - and this element is the
   source of truth for the slider's "All Styles" filter (sections.js:1214), which is NOT in this
   slice's scope. The service chip is a different variant and stays visible.
   ponytail: presentational hide, ceiling named. The clean version re-homes the labels to a
   data- attribute on .rws-card and re-points the filter's reader; that is a filter refactor
   inside a presentation slice, and the filter's own future is already open as U10. Upgrade
   path if the Owner wants the element out of the DOM as well: one PHP line plus that reader. */
.rws-card .card-meta .rws-chip:not(.rws-chip--service) { display: none; }
/* The service chip (#223 S1 / #225): the Work's service identity, sitting outside
   the card anchor so it never becomes link text. Neutral by design — the promo
   variants above must stay louder than it. */
/* Keep the archive service label to one line; its title attribute keeps the full text. */
.ro-works-page .rws-chip--service {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: top;
}
.rws-chip--service {
  color: var(--ro-muted-fg); background: var(--ro-surface-2);
  border-color: var(--ro-border);
  text-transform: none; letter-spacing: .01em; font-size: var(--ro-fs-ui-micro); font-weight: 600;
}

/* Card anchor (#223 S1). Wraps media + title on both card surfaces; the chip and
   the action pad are siblings, so no interactive content sits inside the link.
   The ring is inset because .rws-card clips with overflow:hidden. */
.rws-card__link {
  display: block; color: inherit; text-decoration: none;
  border-radius: inherit;
}
.rws-card__link:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -3px; }

h3.card-title { margin: 0; color: var(--ro-foreground); font-family: var(--ro-font-serif); font-size: var(--ro-fs-h3); font-weight: 900; line-height: 1.3; }
/* .card-title now lives inside .rws-card__link, not .rws-card__body, so it no
   longer inherits the body's padding. */
.rws-card__link .card-title { padding: 16px 18px 0; }
.components { min-height: 23px; color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); }
.components strong { color: var(--ro-foreground); font-weight: 800; }
.components span { color: var(--ro-primary-strong); padding-inline: 4px; }

.action-pad { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-top: 2px; }
.action-button {
  min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 11px; border: 1px solid var(--ro-border); border-radius: var(--ro-radius-control);
  color: var(--ro-muted-fg); background: var(--ro-surface-2); cursor: pointer;
  transition: color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease),
    border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease), opacity var(--ro-dur) var(--ro-ease);
}
.action-button:hover { color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-primary) / .08); border-color: rgb(var(--ro-rgb-primary) / .38); box-shadow: var(--ro-shadow-card); }
.action-button[aria-pressed="true"] { color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-primary) / .13); border-color: rgb(var(--ro-rgb-primary) / .45); }
.action-button:active { transform: scale(.97); }
.action-button svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.action-button--buy { margin-left: auto; color: #fff; border-color: transparent; background: var(--ro-primary-strong); box-shadow: var(--ro-shadow-btn); font-weight: 800; }
.action-button.action-button--buy:hover { color: #fff; background: var(--ro-primary-strong); filter: brightness(1.05); box-shadow: var(--ro-shadow-btn-hover); }
.action-button--buy small { color: rgb(255 255 255 / .8); font-size: var(--ro-fs-ui-micro); font-weight: 700; text-transform: uppercase; margin-left: 2px; }
.action-button--buy .rws-price { font-size: var(--ro-fs-ui); font-weight: 800; }
.action-button--buy .rws-price s { font-size: var(--ro-fs-meta); color: rgb(255 255 255 / 0.7); margin-left: 4px; font-weight: 500; }
.action-button.action-button--buy.is-booked,
.action-button.action-button--buy[aria-pressed="true"] {
  color: var(--ro-foreground); background: var(--ro-surface-2);
  border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card);
}
.action-button.action-button--buy.is-booked:hover,
.action-button.action-button--buy[aria-pressed="true"]:hover {
  color: var(--ro-foreground); background: var(--ro-surface);
  border-color: var(--ro-primary); box-shadow: var(--ro-shadow-card-hover); filter: none;
}
.action-button.action-button--buy.is-booked small,
.action-button.action-button--buy[aria-pressed="true"] small,
.action-button.action-button--buy.is-booked .rws-price s,
.action-button.action-button--buy[aria-pressed="true"] .rws-price s {
  color: var(--ro-muted-fg);
}

/* S4: the host owns layout + reveal state. Its 220ms token duration stays
   below sections.js' 350ms hide fallback, so normal transitionend wins while
   the timeout still covers an unpainted or interrupted host. */
.ro-book-continue-host {
  width: 100%; min-width: 0;
  opacity: 0; transform: translateY(-4px);
  transition: opacity var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-book-continue-host.is-in { opacity: 1; transform: translateY(0); }
.rws-card__body > .ro-book-continue-host {
  grid-column: 1 / -1;
  align-self: stretch;
}
/* Our Works (rev 3): the revealed host must not grow its card - a taller card lifts that card's Like /
   price / Book line above its row siblings (Codex rev 3 code R1). It floats over the bottom of the card's
   own 5:4 photo as a pill instead; DOM and tab order (Book -> Continue) are unchanged. */
.ro-works-page .rws-card { position: relative; }
/* :not([hidden]) is load-bearing: a display value here would override the host's native [hidden] and
   leave an invisible, clickable Continue link over every unbooked card's photo (Codex rev 3 code R2). */
.ro-works-page .rws-card__body > .ro-book-continue-host:not([hidden]) {
  position: absolute; z-index: 13; inset: 0 0 auto; aspect-ratio: 5 / 4; padding: 12px;
  display: flex; align-items: flex-end; justify-content: center; pointer-events: none;
}
.ro-works-page .rws-card__body > .ro-book-continue-host .ro-book-continue {
  pointer-events: auto; text-decoration: none; padding-inline: 16px; border-radius: 999px;
  background: rgb(var(--ro-rgb-surface) / .94); box-shadow: var(--ro-shadow-card);
}
.ro-work-single .ws-buy > .ro-book-continue-host { margin-top: 10px; }

/* The anchor owns appearance only -- no reveal state, no motion, no `hidden`.
   inline-flex is its OWN box layout, not reveal state: a default-inline <a> ignores
   min-width/min-height entirely, so the 44x44 target (a11y.md:121) would not exist.

   Colour: --ro-primary-strong (#E04A6F) measures 3.90:1 on --ro-surface and 3.70:1
   on --ro-surface-2. AA needs 4.5:1 and 13px bold is NOT "large text" (that is
   18.66px bold), so the link colour is --ro-foreground at 13.07:1. The underline is
   what marks it as a link. Hover/focus therefore thickens the underline instead of
   shifting hue -- a non-colour cue, which is also the a11y.md:8 rule against
   encoding state by colour alone. Do not "restore" the pink here; it fails. */
/* Class DOUBLED throughout, per the standing hostile-hover convention (see the
   .ro-btn comment at the top of this file and the .deal-ribbon fix). Two rules
   contest an <a> here and a single-class selector loses to both:
     - Elementor Kit re-point `.elementor-kit-15 a:hover{color}`  (0,2,1)
     - the theme's style.min.css `a:hover{color + background-color:rgb(204,51,102)}`
   `.ro-book-continue.ro-book-continue:hover` is (0,3,0), which beats both on class
   count regardless of their element count. BACKGROUND is re-asserted as well as
   colour -- re-asserting colour alone was not enough for .hero2-tile and is not
   enough here either; nothing else contests that hardcoded magenta.
   This is not cosmetic: the Kit's hover colour is the pink measured at 3.90:1,
   i.e. exactly the AA failure the foreground colour below exists to avoid. */
.ro-book-continue.ro-book-continue {
  display: inline-flex; align-items: center;
  color: var(--ro-foreground); background: transparent;
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
  font-size: var(--ro-fs-meta); font-weight: 700;
  min-width: 44px; min-height: 44px; padding-inline: 8px;
  border-radius: var(--ro-radius-control);
  transition: text-decoration-thickness var(--ro-dur) var(--ro-ease);
}
.ro-book-continue.ro-book-continue:hover,
.ro-book-continue.ro-book-continue:focus,
.ro-book-continue.ro-book-continue:focus:hover,
.ro-book-continue.ro-book-continue:focus-visible {
  color: var(--ro-foreground); background: transparent;
  text-decoration-thickness: 2px;
}
.ro-book-continue.ro-book-continue:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -3px;
}
@media (prefers-reduced-motion: reduce) {
  .ro-book-continue.ro-book-continue { transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .ro-book-continue-host { transition: none; }
}
.save-slot.action-button path {
  fill: transparent; transition: fill var(--ro-dur) var(--ro-ease), opacity var(--ro-dur) var(--ro-ease);
}
.save-slot.action-button[aria-pressed="true"] path {
  fill: var(--ro-skin-lead); opacity: 1;
}
.save-slot.action-button[aria-pressed="true"] {
  color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-primary) / .13); border-color: rgb(var(--ro-rgb-primary) / .45);
}
.save-slot[hidden] { display: none; }

.rws-arrows { position: absolute; inset: 0; z-index: 20; pointer-events: none; }
.rws-arrow {
  position: absolute; top: 42%; display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; border: 1px solid var(--ro-border); border-radius: 50%;
  color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-surface) / .92); box-shadow: var(--ro-shadow-card-hover);
  cursor: pointer; pointer-events: auto; backdrop-filter: blur(8px);
  transition: opacity var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease);
}
/* Doubled-class hover/focus counter (standing UI-hygiene rule,
   .claude/docs/design-system.md). Hello's style.min.css styles bare <button> at
   (0,1,1) on :hover AND :focus with `color:#fff; background-color:#c36`. The old
   single-property `:hover { background }` answered the background and left the
   colour to Hello — measured on /services/manicure/ at 1440px: hover resolved
   color rgb(255,255,255) on background rgb(255,255,255), i.e. an INVISIBLE arrow
   glyph, and :focus resolved white-on-#c36. It never showed before #223 S2
   because the desktop arrows were display:none from #44 until this release, and
   the mobile ones are rarely hovered. Answer every property the hostile rule
   sets, by name, at a specificity that wins. */
.rws-arrow.rws-arrow:hover,
.rws-arrow.rws-arrow:focus,
.rws-arrow.rws-arrow:focus-visible {
  color: var(--ro-primary-strong);
  background: var(--ro-surface);
  border-color: var(--ro-border-hover);
  box-shadow: var(--ro-shadow-btn);
}
.rws-arrow.rws-arrow:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
}
.rws-arrow:disabled { opacity: .36; cursor: not-allowed; box-shadow: var(--ro-shadow-card); }
.rws-arrow:active { transform: scale(.94); }
.rws-arrow--prev { left: 10px; } .rws-arrow--next { right: 10px; }
.rws-arrow svg { width: 22px; height: 22px; }

/* The button label carries the service title, so it can outgrow a phone:
   wrap the row and the label rather than overflow the viewport (F-2). */
.rws-showall-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px; padding-top: 18px; }
.rws-showall { max-width: 100%; white-space: normal; text-align: center; }
.rws-showall-note { color: var(--ro-muted-fg); font-size: var(--ro-fs-meta); }
.rws-showall[aria-expanded="true"] { color: var(--ro-secondary-strong); }

.ro-work-like.action-button svg { width: 19px; height: 19px; flex: none; overflow: visible; opacity: .92; }
.ro-work-like.action-button path {
  fill: transparent; transition: fill var(--ro-dur) var(--ro-ease), opacity var(--ro-dur) var(--ro-ease);
}
.ro-work-like.action-button[aria-pressed="true"] path {
  fill: var(--ro-skin-lead); opacity: 1; animation: ro-work-like-fill var(--ro-dur) var(--ro-ease);
}
.ro-work-like.action-button[aria-pressed="true"] {
  color: var(--ro-primary-strong); background: rgb(var(--ro-rgb-primary) / .13); border-color: rgb(var(--ro-rgb-primary) / .45);
}
@keyframes ro-work-like-fill {
  from { opacity: .55; }
  to { opacity: 1; }
}

/* sr-only helper */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* Collapsed Dropdown Filter Styles */
.rws-filter {
  position: relative;
  margin-bottom: 24px;
  display: inline-block;
  z-index: 100;
}
.rws-filter__toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: var(--ro-surface-2);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-control);
  font-size: var(--ro-fs-ui-sm);
  font-weight: 700;
  color: var(--ro-foreground);
  cursor: pointer;
  transition: background-color 220ms var(--ro-ease), border-color 220ms var(--ro-ease);
}
.rws-filter__toggle:hover {
  background: rgb(var(--ro-rgb-primary) / .04);
  border-color: var(--ro-border-hover);
}
.rws-filter__toggle::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform 220ms var(--ro-ease);
  margin-left: 4px;
}
.rws-filter__toggle[aria-expanded="true"]::after {
  transform: rotate(-135deg) translateY(2px);
}
.rws-filter__panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 150;
  min-width: 200px;
  padding: 8px;
  background: var(--ro-surface);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.rws-filter__panel[hidden] {
  display: none;
}
.rws-filter__option {
  width: 100%;
  padding: 8px 12px;
  border: none;
  background: transparent;
  color: var(--ro-foreground);
  font-size: var(--ro-fs-ui-sm);
  text-align: left;
  cursor: pointer;
  border-radius: var(--ro-radius-control);
  transition: background-color 220ms var(--ro-ease), color 220ms var(--ro-ease);
}
.rws-filter__option:hover {
  background: var(--ro-surface-2);
  color: var(--ro-primary-strong);
}
.rws-filter__option.is-active {
  background: rgb(var(--ro-rgb-primary) / .1);
  color: var(--ro-primary-strong);
  font-weight: 700;
}

.rws-empty-state {
  padding: 48px 24px;
  text-align: center;
  background: var(--ro-surface-2);
  border: 1px dashed var(--ro-border);
  border-radius: var(--ro-radius-card);
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-ui);
  margin-top: 16px;
  grid-column: 1 / -1;
}

.rws-card.rws-filtered-out {
  display: none !important;
}

/* #223 S2 deleted the >=900px master-detail block that lived here: it set
   .rws-card{display:none} / .is-active{display:flex}, hid .rws-arrows, killed
   scroll-snap on .rws-stage, and turned .rws-thumbs into the 3-col tablist grid
   that navigated it. Desktop therefore showed 1 of 8 Works, and the 7 anchors S1
   had just created were display:none. The rail is now the only layout at every
   viewport; desktop card sizing lives with the other breakpoint rules further
   down, in ascending order — see the note there. */

/* Full bleed on >=1200px (reusing works page spacing layout max-width ~1500px) */
@media (min-width: 1200px) {
  .ro-works-slider {
    margin-inline: calc(50% - 50vw);
    width: 100vw;
    max-width: 100vw;
  }
  .ro-works-slider .wrap {
    max-width: 1500px;
    margin-inline: auto;
    width: 100%;
    padding-inline: 24px;
  }
  /* The section already goes full-bleed here with a 1500px .wrap, and .rws-stage
     independently breaks out via margin-inline: calc(50% - 50vw) then re-pads with
     max(24px, calc((100vw - 1200px)/2 + 24px)). At 1500px those disagree: the wrap's
     content edge is at x=24 but the first card starts at x=174, while .rws-arrows is
     positioned on .rws-stage-wrap INSIDE the wrap — so left:10px would float the prev
     arrow ~140px clear of the first card. Never rendered before, because the desktop
     arrows were display:none from #44 until S2. Collapse the double breakout. */
  .rws-stage {
    margin-inline: 0;
    padding-inline: 0;
    scroll-padding-inline: 0;
  }
}

/* ============================================================
   IMMERSIVE WORK VIEWER (#223 S3)
   Re-pointed from the retired fullscreen geometry: the native dialog owns the
   full-bleed dark surface, while the frame never enlarges an intrinsic image.
============================================================ */
.ro-viewer {
  position: fixed; inset: 0; z-index: 8000; display: grid;
  /* ONE COLUMN, AND ONE ROW FEWER (#223 S5d). The old template was `1fr 1fr` / four rows for
     exactly one reason: the between-Works pair sat in a band of its own (grid row 2) at opposite
     edges, per 04_desktop-flow.md:40. That sketch is superseded - the Look controls are now
     vertically-centred overlays INSIDE .ro-viewer__media-region, so the dialog has three children
     (topbar, layout, see-all) and no child that wants a half-width column. The `.ro-viewer > *`
     span rule that defended against the columns went with them.
     DO NOT REINTRODUCE EITHER. A second column would re-auto-place any future child into the
     leftover width, which is the defect the span rule existed to mask; and the retired row was
     worth a measured 48px of content height on the archive and slider routes (732 -> 780 at
     390x844), which is half of what makes the media share below reachable. */
  grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto;
  width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
  /* SAFE-AREA OWNERSHIP LIVES HERE AND NOWHERE ELSE (#223 S5b). Previously the insets were
     subtracted from the dialog's width/height AND consumed again in child padding, so they
     were paid for twice. Worse, subtracting from `width` while `inset: 0` pins the box to the
     left edge shrinks the dialog without ever moving content out of the left unsafe area -
     it under-delivered on the one axis it was meant to protect. Padding on the dialog is
     correct by construction: box-sizing is border-box globally (see :4998), the grid lays out
     inside the padding box, and every child inherits the protection with plain values. */
  margin: 0; border: 0; overflow: hidden; isolation: isolate;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  /* The viewer paints its own dark surface from the STABLE sidebar tokens, never from
     --ro-foreground. Custom properties inherit through the DOM regardless of the top layer,
     and the archive renders this dialog inside .ro-works-page.is-dark, which re-points
     --ro-foreground to #F3EBEE (sections.css:3041). background:var(--ro-foreground) therefore
     painted a near-white panel under near-white text on /our-works/ - invisible on the single
     most important surface, and perfectly fine on every slider page, which is exactly how a
     check on one surface would have missed it. --ro-rgb-sidebar* is not remapped by is-dark. */
  background: rgb(var(--ro-rgb-sidebar-deep)); color: rgb(var(--ro-rgb-sidebar-fg));
}
.ro-viewer:not([open]) { display: none; }
/* Author display beats UA [hidden]; keep semantic hiding out of layout. */
.ro-viewer [hidden] { display: none !important; }
.ro-viewer::backdrop { background: rgb(var(--ro-rgb-sidebar-deep) / .94); }
.ro-viewer__topbar { position: relative; z-index: 3; display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 64px; padding: 10px clamp(16px, 4vw, 52px); }
.ro-viewer__title { min-width: 0; margin: 0; overflow: hidden; color: rgb(var(--ro-rgb-sidebar-fg)); font-size: var(--ro-fs-ui); font-weight: 800; letter-spacing: .08em; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.ro-viewer__close, .ro-viewer__work-nav, .ro-viewer__media-nav, .ro-viewer__actions button, .ro-viewer__dots button {
  display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px;
  border: 1px solid rgb(var(--ro-rgb-sidebar-fg) / .3); border-radius: 999px; color: rgb(var(--ro-rgb-sidebar-fg));
  background: rgb(var(--ro-rgb-sidebar) / .82); cursor: pointer;
  transition: background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease), opacity var(--ro-dur) var(--ro-ease);
}
.ro-viewer__close:hover, .ro-viewer__work-nav:hover, .ro-viewer__media-nav:hover, .ro-viewer__actions button:hover { background: rgb(var(--ro-rgb-sidebar-fg) / .16); border-color: rgb(var(--ro-rgb-sidebar-fg) / .7); color: rgb(var(--ro-rgb-sidebar-fg)); }
/* Hello's button:focus rule is (0,2,0); :focus-visible does not defend a mouse focus.
   Re-assert the controls' own resting surface so focus alone cannot paint the viewer magenta. */
.ro-viewer.ro-viewer .ro-viewer__close:focus, .ro-viewer.ro-viewer .ro-viewer__actions button:not(.ro-viewer__book):focus { background: rgb(var(--ro-rgb-sidebar) / .82); }
.ro-viewer__close:disabled, .ro-viewer__work-nav:disabled, .ro-viewer__media-nav:disabled, .ro-viewer__dots button:disabled { cursor: default; opacity: .38; }
.ro-viewer__close .icon, .ro-viewer__work-nav .icon, .ro-viewer__media-nav .icon { width: 20px; height: 20px; flex: none; }
/* THE ARROW GUTTER IS GONE (#223 S5d). --ro-viewer-media-gutter and its data-media-axis clamp
   existed for one job: reserve clamp(56px,10vw,124px) beside the frame so the within-media
   arrows had somewhere to sit that was not the photo. S5d puts both control families ON the
   photo, so nothing is left to reserve for and the media region reclaims up to 248px of width
   on a desktop viewer. The S5a rule the gutter came from is not repealed - "a control that does
   not exist must not reserve space" still holds, trivially, now that no control reserves any. */
.ro-viewer__layout {
  /* Stack when the aside can no longer hold its measure; Phase 3 derives and toggles this
     container decision. FLOOR RAISED 320 -> 368 (#223 S5b follow-up, v3.94.1). The old comment
     claimed "the aside's clamp keeps that measure while possible" and Phase 6 measured the
     opposite: at a 890px dialog the aside held 40 real characters, not the >=45 the split
     threshold is derived from, because 32% only overtakes a 320px floor above a 1000px layout -
     so every width between 880 and 1000 was pinned at the floor no matter how wide it got.
     DERIVED, not chosen, from two live measurements of the real summary prose: 272px of content
     carried 40 characters and 362px carried 53, i.e. ~6.8px per real character (the two per-point
     ratios, 6.80 and 6.83 - NOT the 6.92 difference slope between them, which is the arithmetic
     error the first draft of the plan made). Content width is the column minus this element's
     24px x2 details padding, so 45 characters needs ~355px of column and 368px carries ~47 -
     roughly two characters of headroom for font-metric and rounding variance.
     The THRESHOLD stayed at 880 by Owner decision (v3.94.1): moving it to ~1106 instead would
     have forced the stacked layout onto iPad landscape and half-screen laptop windows, the shape
     that benefits most from two columns. 32% only overtakes this floor at a 1150px layout, so
     every layout at or above 1150px is unchanged by the raise; the whole cost is ~48px of media
     column on the 880-1150 band. */
  display: grid; grid-template-columns: minmax(0, 1fr) clamp(368px, 32%, 420px); gap: 24px;
  min-width: 0; min-height: 0;
}
/* THE MEDIA'S SHARE OF THE HEIGHT IS DECLARED HERE, ON THE TRACK, NEVER ON THE ITEM (#223 S5b
   follow-up, v3.94.1). Measured defect on production at 390x844: the photo rendered 256x320, a
   320px media region inside a 732px content row - 38% of the viewport height, and below the
   91.2%-of-the-old-lightbox that v3.92.1 had recovered. Cause: before S5b mobile used a 7-row
   template whose media row was minmax(0, 1fr). Deleting that template was right - its grid-row
   rules addressed elements that had moved into the <aside> - but nothing replaced the media's
   share, so the region fell back to content height.
   WHY THE TRACK AND NOT min-height ON .ro-viewer__media-region: a grid item's percentage block
   size resolves against its GRID AREA, not against this container. The stacked rows were
   implicit and auto, so a min-height:58% there is cyclic - it contributes nothing to sizing the
   row, the row is then sized to content (320px), and the percentage finally resolves against
   THAT: 58% x 320 = 186px, under the content height, changing nothing and reporting no error.
   Making this container's height explicit does not fix it either; the item's containing block is
   still the same auto row. Track percentages, by contrast, resolve against this element's own
   content-box height - definite here because it is stretched into the dialog's minmax(0, 1fr)
   row (measured 732px at 390x844). css-grid-2 6.2, css-sizing-3 5.2.1.
   WHY + 20px: a grid AREA contains the item's margin box, and .ro-viewer__media-region carries
   margin: 10px 0. A bare 58% would leave the region itself at 58% - 20px = 55.3%, missing the
   value that was actually chosen. This calc makes the REGION land at 58%. The 20px is that
   margin and nothing else - if the margin changes, this changes with it.
   WHY NOT dvh: this box is already inside the dialog's env(safe-area-inset-*) padding and
   already net of the topbar and work-nav rows, so a percentage of it inherits that arithmetic
   for free. dvh would re-derive it from the viewport and subtract the chrome by hand, which is
   the same class of mistake as the borrowed threshold above, and would take a dependency on
   mobile dvh/browser-chrome behaviour this project has NOT verified on a real device.
   minmax(..., auto) claims a floor without capping: the row still grows if the region's content
   ever gets taller, and the img rules below (width/height auto + max-*:100% + contain) keep a
   taller row from upscaling past intrinsic size. Two explicit tracks match the two children this
   element has; a third child would land in an implicit auto row, which is the right degradation.
   Two columns need none of this - the media region already fills the minmax(0, 1fr) column
   there, measured 692px against 310px stacked. */
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__layout {
  grid-template-columns: minmax(0, 1fr);
  /* `normal` stretches auto tracks and let hydrated aside content redistribute 2.25px of free
     height at 390x844. Start keeps each track content-sized; minmax(..., auto) still grows. */
  align-content: start;
  /* PLAN §1 (#223 S7): the floor axis changes because width-bound portrait geometry is
     H >= W / r, a function of viewport WIDTH, not layout height. The old 67% divided the
     487.5px requirement (390 / 0.800) by the 780px layout height DevTools happened to have at
     100dvh, so 67% meant 487.5px only there. It survived every check because derivation and
     verification both used that same 100dvh height; short visible viewports got a smaller floor.
     SAME S5d p10 population: n=133 viewer-reachable image slides, r discrete at 0.7503x1 /
     0.8000x92 / 1.2500x40. Thus 125vw = 1 / 0.800, with coverage 132/133; the lone 0.7503
     outlier would need 133.3vw and is deliberately not paid for. Width makes this target
     viewport-independent.
     +20px still pays for .ro-viewer__media-region's margin: 10px 0, which a grid AREA contains;
     it makes the REGION land on the derived value. If that margin changes, this changes with it.
     The MAX is a bare 100% that RESERVES NOTHING per the Owner ruling: it is the full layout
     height, so the aside and Book CTA begin below the fold rather than spending media height to
     keep them visible. `calc(100% - 68px)` was rejected at Agent02 Gate 2 because a reserve is a
     reserve whatever it is called. An uncapped max() would resolve 125vw=1055px on a 326px
     landscape layout, making one photo more than three screens tall. `calc(58% + 20px)` remains
     the MIN degradation path. The floor is width-derived, the cap reserves nothing, and the
     grid track still owns the geometry.
     STILL A FLOOR, NEVER A CAP (Owner, standing). The clamp shapes only the minmax MINIMUM; the
     maximum stays `auto`, so the row is as free to grow as it ever was, and the img rules below
     keep a taller row from upscaling past intrinsic size. Any check asserts >= floor - the
     converged share is path-dependent, measured 58.0/59.8/61.1/62.5/63.7/67.0% by route and
     history, so `== N%` is always the wrong assertion. */
  grid-template-rows: minmax(clamp(calc(58% + 20px), calc(125vw + 20px), 100%), auto) auto;
}
/* The stated coupling no longer exists: the clamp's 204px bound minus the 24px grid gap is gone.
   §1 owns the floor; Phase 2b's native media dimensions keep the final auto-sized row stable
   across hydration. Guard: the 63-Work x 2-viewport CTA-position assertion. */
/* scroll-padding belongs on the SCROLL CONTAINER, not on the sticky element - the sticky
   topbar would otherwise overlap whatever a scroll-into-view lands on. */
/* scrollbar-gutter is load-bearing, not cosmetic: stacking turns on overflow-y, a classic
   scrollbar then narrows the content box, .ro-viewer__layout's clientWidth drops, and the
   ResizeObserver re-evaluates against the same threshold - which is how a layout oscillates
   at its own breakpoint. Reserving the gutter keeps the measured width stable across the flip. */
.ro-viewer[data-ro-viewer-stacked] { overflow-y: auto; overscroll-behavior-y: contain; scroll-padding-block-start: 64px; scrollbar-gutter: stable; }
/* THE ASIDE MUST STOP BEING A SCROLLER WHEN STACKED, or the dialog's overflow-y above is a lie.
   Measured before this rule: stacked dialog carried [data-ro-viewer-scroll] with
   scrollHeight === clientHeight (844/844 - a dead scroller) while the aside quietly scrolled its
   own 1033px of content. Everything keyed to the attribute then pointed at the wrong element:
   the ArrowUp/ArrowDown gate exempts `.closest('[data-ro-viewer-scroll]')`, so arrows inside the
   aside were swallowed into Work navigation instead of scrolling; the focus handoff parked the
   keyboard on an element that could not scroll; and a vertical pan begun on the media had nowhere
   to travel. With overflow visible the aside's content feeds the dialog's scroll container, which
   is what "stacked = the dialog scrolls" was always supposed to mean. Media geometry is untouched
   by this rule - measured identical either way, 310px stacked / 692px two-column. */
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__aside { overflow-y: visible; }
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__topbar { position: sticky; top: 0; background: rgb(var(--ro-rgb-sidebar-deep)); }
.ro-viewer__media-region { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; min-width: 0; min-height: 0; margin: 10px 0; overflow: hidden; touch-action: pan-y pinch-zoom; }
/* Fills the grid's minmax(0,1fr) row - i.e. the viewport minus chrome, per C-B.8. The old
   760px cap came from .lightbox__media and is the measured defect this slice exists to fix:
   at 1440x900 it produced a 760x702 box, so a 1160x1450 source rendered at ~702px tall with
   the rest of the viewport unused. Aspect is preserved by the img rule below (width/height
   auto + max-*:100% + contain), which also prevents upscaling past intrinsic size. */
.ro-viewer__media { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; max-width: 100%; max-height: 100%; overflow: hidden; background: rgb(var(--ro-rgb-sidebar-deep)); box-shadow: 0 18px 60px rgb(0 0 0 / .3); touch-action: pan-y pinch-zoom; }
.ro-viewer__media-item, .ro-viewer__hero-source { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; min-width: 0; min-height: 0; }
.ro-viewer__media-item img, .ro-viewer__media-item video, .ro-viewer__hero-source img, .ro-viewer__hero-source video { display: block; width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: contain; }
/* TOP-right, not bottom-right (#223 S5d, Codex R1 Major). The S5d bottom-centre control cluster
   is 48px tall at bottom:8px and up to calc(100% - 16px) wide, so a bottom-right toggle sat
   INSIDE its band: measured 99.6x44.0 full occlusion at 390x844, with elementFromPoint at the
   toggle's own centre returning .ro-viewer__media-nav--next - a Play/Pause tap advanced the
   media instead. 10 of 63 published Works carry video, so this was production-reachable. Fixed
   by GEOMETRY, not by z-index: the top-right corner of the region is empty at every viewport
   (the topbar is outside the region, and the Look pill at right:12px is vertically centred), so
   the two can never collide again. It also lifts the toggle clear of the 128px bottom scrim,
   which veiled it. Do not move this back to `bottom`. */
.ro-viewer__video-toggle { position: absolute; right: 12px; top: 12px; bottom: auto; z-index: 5; display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; padding: 8px 12px; border: 1px solid rgb(var(--ro-rgb-sidebar-fg) / .35); border-radius: 999px; color: rgb(var(--ro-rgb-sidebar-fg)); background: rgb(var(--ro-rgb-sidebar-deep) / .86); cursor: pointer; }
.ro-viewer.ro-viewer .ro-viewer__video-toggle:focus { background: rgb(var(--ro-rgb-sidebar-deep) / .86); }
.ro-viewer__video-toggle:hover, .ro-viewer__video-toggle:focus-visible { color: rgb(var(--ro-rgb-sidebar-fg)); background: rgb(var(--ro-rgb-sidebar) / .96); }
.ro-viewer__hero-source { position: relative; overflow: hidden; }
.ro-viewer__hero-source .rws-img, .ro-viewer__hero-source .media-slide__poster { width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: contain; }
.ro-viewer__hero-source .media-slide__poster { position: static; }
.ro-viewer__hero-source .video-scrim, .ro-viewer__hero-source .media-badge { display: none; }
/* TWO NAVIGATION FAMILIES, ONE REGION, ONE STABLE ANCHOR (#223 S6 R).
   Both pairs anchor to the media region, a box that belongs to the layout rather than the
   content. The painted photo is not an anchor: mixed-aspect Works moved its controls by up to
   155px during ordinary media navigation. Within the region a control family is never removed
   for want of space: a responsive LABEL is allowed, a responsive AFFORDANCE is not. ONE
   EXCEPTION: the between-Works family is removed in the STACKED viewer by Owner decision because
   two navigation systems on one small touch surface produce accidental cross-Work navigation.
   This is admissible ONLY because on every origin where that family renders (archive and slider),
   the surface the viewer overlays is itself a set of Works, one dismissal away. REVISIT this
   exception whenever any affected origin stops offering page-level cross-Work navigation of its
   own - NOT merely if N11 changes, which governs the single route, where this pair is already
   hidden. Touch-drag swipe stays an accelerator, never the only path. */
.ro-viewer__work-nav { position: absolute; top: 50%; z-index: 4; width: 48px; height: 48px; padding: 0; transform: translateY(-50%); }
.ro-viewer__work-nav--prev { left: 12px; }
.ro-viewer__work-nav--next { right: 12px; }
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__work-nav { display: none; }
.ro-viewer__media-nav { position: absolute; top: 50%; z-index: 4; width: 48px; height: 48px; transform: translateY(-50%); }
.ro-viewer__media-nav--prev { left: 72px; }
.ro-viewer__media-nav--next { right: 72px; }
/* STACKED INNER PAIR (#223 S7): v3.98.0 hides .ro-viewer__work-nav when stacked, so the 12px
   slot the S6 R contract reserved for it is permanently empty. Reclaim that slot for the media
   pair. The anchor remains the media REGION, never the painted photo. */
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav--prev { left: 12px; }
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav--next { right: 12px; }
/* The bottom-centre cluster now holds only dots and counter. Absolutely positioned, so a
   control the JS hides with [hidden] reserves no space and leaves no gap on the photo.
   BUDGET: only the dots strip and counter consume cluster width; navigation is anchored to the
   region edges, and a Work with many media scrolls INSIDE the cluster. */
.ro-viewer__media-meta { position: absolute; left: 50%; bottom: 8px; z-index: 4; display: flex; align-items: center; justify-content: center; gap: 6px; width: max-content; max-width: calc(100% - 16px); min-height: 48px; padding: 0 6px; transform: translateX(-50%); }
/* WHY A SECOND RULE AND NOT A BACKGROUND ON THE ONE ABOVE: the scrim rescues only a control that
   carries its own surface. Measured live at v3.96.0 over 63 Works x 2 viewports, worst backdrop
   pure-white photo: neutral black at .65 yields 4.63:1 for the counter with its existing .82
   alpha and 5.20:1 for the inactive dot at its raised .90 resting alpha. The backing is gated
   on a real child: the cluster is emitted with no `hidden` attribute and setInnerAxis() hides
   only its children, so an ungated surface paints an empty capsule on the 28 single-media Works.
   :not(:empty) is load-bearing - pre-hydration the dots container is present, NOT hidden, empty. */
.ro-viewer__media-meta:has(> :not([hidden]):not(:empty)) {
  background: rgb(var(--ro-rgb-overlay-neutral) / .65);
  border-radius: 999px;
}
/* Legibility for controls that now sit over photographs rather than over letterbox, on every
   viewport - a gradient scrim, not an opaque bar. This is the fix for the arrow-contrast item
   owed since v3.94.0: the dots (8px when this was measured, 6px since v3.102.0) carry no
   background of their own, and the chevron and Look
   pills are translucent by design. pointer-events:none so it never eats a swipe or a tap. */
.ro-viewer__media-region::after {
  content: ""; position: absolute; inset-inline: 0; bottom: 0; z-index: 2; height: 128px; pointer-events: none;
  background: linear-gradient(to top, rgb(var(--ro-rgb-sidebar-deep) / .72), rgb(var(--ro-rgb-sidebar-deep) / 0));
}
.ro-viewer__work-nav, .ro-viewer__media-nav { background: rgb(var(--ro-rgb-sidebar) / .92); box-shadow: 0 2px 14px rgb(0 0 0 / .45); }
.ro-viewer.ro-viewer .ro-viewer__work-nav:focus, .ro-viewer.ro-viewer .ro-viewer__media-nav:focus { background: rgb(var(--ro-rgb-sidebar) / .92); }
/* STACKED ARROW PAINT (#223 S7): keep the house's 44px minimum hit target, but move the painted
   surface to a smaller disc. 36px = 20px icon + 2x8px minimum ring; inset = (44-36)/2 = 4px.
   The icon is positioned so it paints above the disc without a z-index contest. */
.ro-viewer.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav,
.ro-viewer.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav:hover,
.ro-viewer.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav:focus {
  width: 44px; height: 44px; background: transparent; border-color: transparent; box-shadow: none;
}
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav::before {
  content: ""; position: absolute; inset: 4px; border: 1px solid rgb(var(--ro-rgb-sidebar-fg) / .3);
  border-radius: 999px; background: rgb(var(--ro-rgb-sidebar) / .92); box-shadow: 0 2px 14px rgb(0 0 0 / .45);
  pointer-events: none; transition: background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease);
}
/* TWO-PART HELLO DEFENCE: the dots' `.ro-viewer__dots button:hover, .ro-viewer__dots button:focus`
   rule is precedent, and its comment records that the deletion alone is not the fix. Once this
   button stops painting its own surface, Hello's button:hover/button:focus rule at (0,2,0) is
   otherwise unopposed. Neutralise resting, hover and focus above it, then paint every state here. */
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav:hover::before {
  border-color: rgb(var(--ro-rgb-sidebar-fg) / .7); background: rgb(var(--ro-rgb-sidebar-fg) / .16);
}
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav:focus::before {
  border-color: rgb(var(--ro-rgb-sidebar-fg) / .3); background: rgb(var(--ro-rgb-sidebar) / .92);
}
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav:disabled::before {
  border-color: rgb(var(--ro-rgb-sidebar-fg) / .3); background: rgb(var(--ro-rgb-sidebar) / .92); box-shadow: 0 2px 14px rgb(0 0 0 / .45);
}
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-nav .icon { position: relative; }
/* CAPSULE PAINT (#223 S7): move only its surface, not the 44px dot hit targets. The measured ink
   spans 14.3-33.8 inside the 48px box (dot ink 21-27 since the v3.102.0 -25% resize, was 20-28;
   the counter text at 14.3-33.8 is the binding term either way), so an 8px block
   inset paints 8-40 and clears every glyph by >= 6.2px. Keep the exact child gate: the cluster is
   emitted without [hidden] and setInnerAxis() hides only children, so :not(:empty) prevents an
   empty capsule on single-media Works and pre-hydration on every Work. */
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-meta:has(> :not([hidden]):not(:empty)) {
  background: transparent;
}
.ro-viewer[data-ro-viewer-stacked] .ro-viewer__media-meta:has(> :not([hidden]):not(:empty))::before {
  content: ""; position: absolute; inset-block: 8px; inset-inline: 0; z-index: -1; border-radius: 999px;
  background: rgb(var(--ro-rgb-overlay-neutral) / .65); pointer-events: none;
}
/* flex:none + nowrap are load-bearing on the overlay cluster, not tidiness: as a shrinkable
   flex item inside a shrink-to-fit absolute box, "1 / 4" was squeezed to 24px and wrapped onto
   two lines, and the dots strip lost 16px to it and grew a visible scrollbar over the photo. */
.ro-viewer__counter { flex: none; white-space: nowrap; color: rgb(var(--ro-rgb-sidebar-fg) / .82); font-size: var(--ro-fs-meta); font-variant-numeric: tabular-nums; }
/* The strip still scrolls when a Work carries more media than the cluster can show; it just
   does not paint a scrollbar across the photograph to say so. */
.ro-viewer__dots { display: flex; align-items: center; justify-content: flex-start; min-width: 0; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.ro-viewer__dots::-webkit-scrollbar { display: none; }
.ro-viewer__dots button { flex: 0 0 44px; width: 44px; height: 44px; padding: 12px 8px; border: 0; background: transparent; }
.ro-viewer__dots button::after { content: ""; display: block; width: 6px; height: 6px; margin: 0 auto; border-radius: 50%; background: rgb(var(--ro-rgb-sidebar-fg) / .9); transition: background-color var(--ro-dur) var(--ro-ease), border-radius var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease), width var(--ro-dur) var(--ro-ease); }
/* REMOVING THE DOT FROM THE SHARED HOVER-BACKGROUND LIST ABOVE IS NOT ENOUGH — THE COUNTER HAS TO
   BE RE-ASSERTED. Hello's style.min.css ships
   `[type="button"]:focus, [type="button"]:hover, button:focus, button:hover
    { color: #fff; background-color: rgb(204,51,102) }`
   at (0,2,0), which out-specifies this button's own (0,1,1) `background: transparent`. The entry
   deleted from :2656 was the only thing contesting it, so a bare deletion hands the 44px hit
   target to a hardcoded magenta square instead of returning it to transparent. Verified live at
   v3.96.0 by removing that selector from the real sheet through CSSOM: the button then computed
   rgb(204,51,102) on hover AND on focus. This is the standing hostile-Kit rule — a control whose
   hover state was previously masked has never had its real hover state rendered.
   `:focus`, not `:focus-visible`, because Hello's rule fires on ANY focus; the dot's own visible
   cue below stays on `:focus-visible` so a mouse click does not light it. */
.ro-viewer__dots button:hover, .ro-viewer__dots button:focus { background: transparent; }
.ro-viewer__dots button:hover, .ro-viewer__dots button:focus-visible { outline: 2px solid rgb(var(--ro-rgb-sidebar-fg) / .9); outline-offset: -2px; }
.ro-viewer__dots button[aria-selected="true"]::after { width: 12px; border-radius: 999px; background: rgb(var(--ro-rgb-sidebar-fg) / .9); transform: none; }
.ro-viewer__aside { display: flex; flex-direction: column; gap: 16px; min-width: 0; min-height: 0; overflow-y: auto; padding: 24px 0; }
.ro-viewer__details { display: flex; flex-direction: column; align-items: stretch; gap: 16px; min-height: 0; padding: 0 24px; }
.ro-viewer__summary, .ro-viewer__receipt, .ro-viewer__status { width: 100%; min-width: 0; }
/* THE LOADING SKELETON IS AN AFFORDANCE AND CARRIES NO LOAD-BEARING / STABILIZING GEOMETRY
   (#223 follow-up, v3.97.0, Agent02). It does occupy a real 12px bar - measured, not nominal
   (the revert-B mutant moves the CTA by Phase 0's +12px) - but it must never participate in
   geometry stabilization and must never assume the height of the text that replaces it.
   It is a static bar - no delay, no fade, no transition and no animation - because
   the loading state is WRITTEN on every open and PAINTED only on a first open (mediaMemo
   memoises the promise, sections.js:2249/:2893), so anything with an appearance transition
   would turn today's invisible cached path into a visible flicker. Nothing here reserves
   height ON BEHALF OF THE PAYLOAD: the aside is held by the stacked min-height above and the
   actions sit above every block the payload grows, so this box's own height is free.
   KEYED ON ITS OWN STATE ATTRIBUTE, not on aria-live: the live-region policy at
   sections.js:2770 is an accessibility decision that must stay free to change without
   silently restyling the panel. The bar is decorative (::before, no content of its own);
   the element keeps its 'Loading details...' text for assistive tech. */
.ro-viewer__status[data-ro-viewer-loading] { color: transparent; font-size: 0; line-height: 0; }
.ro-viewer__status[data-ro-viewer-loading]::before {
  content: ""; display: block; width: 72%; height: 12px; border-radius: 999px;
  background: rgb(var(--ro-rgb-sidebar-fg) / .22); pointer-events: none;
}
.ro-viewer__actions { display: flex; flex-direction: column; align-items: stretch; gap: 12px; width: 100%; }
.ro-viewer__actions button { min-height: 44px; padding: 8px 12px; }
.ro-viewer__book { width: 100%; color: #fff; border-color: transparent; background: var(--ro-primary-strong); box-shadow: var(--ro-shadow-btn); font-weight: 800; }
.ro-viewer.ro-viewer .ro-viewer__book:focus { background: var(--ro-primary-strong); }
.ro-viewer__actions .ro-viewer__book:hover, .ro-viewer__actions .ro-viewer__book:focus-visible { color: #fff; background: var(--ro-primary-strong); border-color: transparent; filter: brightness(1.05); box-shadow: var(--ro-shadow-btn-hover); }
.ro-viewer__secondary-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; width: 100%; }
.ro-viewer__secondary-actions button { flex: 1 1 44px; }
.ro-viewer__actions .icon { width: 20px; height: 20px; flex: none; }
.ro-viewer__actions .ro-work-like[aria-pressed="true"] path { fill: rgb(var(--ro-rgb-sidebar-fg)); stroke: rgb(var(--ro-rgb-sidebar-fg)); }
.ro-viewer__full-page, .ro-viewer__see-all { display: inline-flex; align-items: center; min-height: 44px; padding: 8px 0; }
.ro-viewer.ro-viewer .ro-viewer__full-page, .ro-viewer.ro-viewer .ro-viewer__see-all, .ro-viewer.ro-viewer .ro-book-continue-host a { color: rgb(var(--ro-rgb-sidebar-fg)); background: transparent; text-decoration: none; }
.ro-viewer.ro-viewer .ro-viewer__full-page, .ro-viewer.ro-viewer .ro-viewer__see-all { text-decoration: underline; text-underline-offset: 3px; }
.ro-viewer.ro-viewer .ro-viewer__full-page:hover, .ro-viewer.ro-viewer .ro-viewer__full-page:focus-visible, .ro-viewer.ro-viewer .ro-viewer__see-all:hover, .ro-viewer.ro-viewer .ro-viewer__see-all:focus-visible, .ro-viewer.ro-viewer .ro-book-continue-host a:hover, .ro-viewer.ro-viewer .ro-book-continue-host a:focus-visible { color: rgb(var(--ro-rgb-sidebar-fg)); background: rgb(var(--ro-rgb-sidebar-fg) / .16); }
.ro-viewer.ro-viewer .ro-book-continue-host a { display: inline-flex; align-items: center; min-height: 44px; padding: 8px 12px; border-radius: 999px; }
.ro-viewer:open { animation: ro-viewer-open var(--ro-dur) var(--ro-ease) both; }
.ro-viewer__media-item { animation: ro-viewer-axis var(--ro-dur) var(--ro-ease) both; }
@keyframes ro-viewer-open { from { opacity: 0; } to { opacity: 1; } }
@keyframes ro-viewer-axis { from { opacity: 0; transform: scale(.985); } to { opacity: 1; transform: none; } }

@media (hover: hover) and (pointer: fine) {
  .ro-viewer__media img { cursor: zoom-in; transition: transform var(--ro-dur-base) var(--ro-ease-out); }
  .ro-viewer__media .is-zoomed img { transform: scale(2); cursor: zoom-out; }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: reduce) {
  .ro-viewer__media img { transition: none; }
}

@media (min-width: 760px) {
  .rws-card { flex-basis: clamp(400px, 45vw, 520px); }
  .media-stage { aspect-ratio: 4 / 4.55; }
}

/* Desktop rail density (#223 S2). PLACEMENT IS LOAD-BEARING: this and the
   >=760px rule above are both `.rws-card`, and a media query adds no
   specificity — they tie, so source order decides. Written above the 760 rule
   (e.g. where the deleted master-detail block was) this is a silent no-op and
   desktop keeps 520px cards. Rule: when two breakpoints target the SAME selector,
   the narrower one must come first. (The >=1200px block above targets .rws-stage
   and .ro-works-slider only, so it does not tie with either of these.) 520px gave ~2.2 cards per screen at 1440 with a ~592px
   media box; 340-400px gives 3 plus peek inside the 1200px content box at every
   desktop width, with a ~455px media box. aspect-ratio is inherited from above. */
@media (min-width: 900px) {
  .rws-card { flex-basis: clamp(340px, 26vw, 400px); }
}

@media (max-width: 900px) {
  .rws-stage {
    padding-inline: max(24px, calc((100vw - 1200px) / 2 + 24px));
    scroll-padding-inline: max(24px, calc((100vw - 1200px) / 2 + 24px));
  }
}

@media (max-width: 600px) {
  .rws-stage { gap: 12px; padding-inline: 20px; scroll-padding-inline: 20px; }
  .rws-card { flex-basis: calc(100vw - 48px); }
  .rws-arrow { top: 39%; width: 44px; height: 44px; }
  .rws-arrow--prev { left: 2px; } .rws-arrow--next { right: 2px; }
  .action-button--buy { width: 100%; margin-left: 0; }
  .ro-viewer__topbar { padding-inline: 12px; }
  .ro-viewer__media { width: 100%; height: 100%; }
  .ro-viewer__details { padding-inline: 12px; }
}

@media (max-width: 600px) {
  /* The 7-row template and the per-element grid-row assignments below it are GONE (#223 S5b).
     media-meta, details and position are no longer children of .ro-viewer - they live inside
     .ro-viewer__aside - so `grid-row` on them addressed nothing, while the 7-row template put
     the minmax(0,1fr) free row under the work-nav instead of the media. The dialog now has
     exactly three children (topbar, .ro-viewer__layout, see-all) and inherits the base
     template - the work-nav row went with the work-navs themselves (#223 S5d). */
  .ro-viewer__see-all { justify-self: center; margin-bottom: 8px; }
}


/* ============================================================
   DEALS LISTING (issue #55)
============================================================ */
.ro-deals-listing {
  padding-block: calc(var(--ro-section-gap) / 2);
}
.ro-deals-listing .deals-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.ro-deals-listing .deals-grid--rest3 {
  grid-template-columns: repeat(3, 1fr);
}
.ro-deals-listing .deals-grid--restfit {
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.ro-deals-listing .deal-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--ro-surface);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  overflow: hidden;
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-deals-listing .deal-card:hover {
  box-shadow: var(--ro-shadow-card-hover);
  border-color: var(--ro-border-hover);
}
.ro-deals-listing .deal-card:focus-within {
  border-color: var(--ro-border-hover);
}
.ro-deals-listing .deal-media {
  position: relative;
  aspect-ratio: 16 / 10;
}
.ro-deals-listing .deal-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ro-deals-listing .deal-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--ro-skin-lead);
  color: #fff;
  font-size: var(--ro-fs-ui-micro);
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 999px;
  box-shadow: 0 2px 6px rgb(var(--ro-skin-lead-rgb) / 0.35), 0 8px 20px rgb(var(--ro-skin-lead-rgb) / 0.22);
  max-width: calc(100% - 28px);
}
.ro-deals-listing .deal-value {
  position: absolute;
  left: 14px;
  bottom: 14px;
  z-index: 2;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  background: rgb(255 255 255 / 0.82);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgb(255 255 255 / 0.6);
  border-radius: 14px;
  padding: 8px 14px;
  box-shadow: 0 2px 10px rgba(56, 46, 51, 0.14);
}
.ro-deals-listing .deal-value b {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.01em;
  color: var(--ro-foreground);
  line-height: 1;
}
.ro-deals-listing .deal-value span {
  font-size: var(--ro-fs-ui-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ro-muted-fg);
}
.ro-deals-listing .deal-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 22px 26px 26px;
}
.ro-deals-listing .deal-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: var(--ro-stack-xs);
  min-height: 24px;
}
.ro-deals-listing h3.deal-title {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h2);
  line-height: 1.2;
  margin-bottom: 6px;
  overflow-wrap: anywhere;
}
.ro-deals-listing .deal-title a {
  text-decoration: none;
}
.ro-deals-listing .deal-title a:hover {
  color: var(--ro-skin-lead);
}
.ro-deals-listing .deal-title a:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 3px;
  border-radius: 4px;
}
/* Lead copy (v3.128.0): supporting line under the card heading. */
.ro-deals-listing .deal-sub {
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-lead);
  line-height: 1.6;
  max-width: var(--ro-measure-tight);
  margin-bottom: var(--ro-stack-sm);
}
/* Meta copy. */
.ro-deals-listing .deal-conditions {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-meta);
  line-height: 1.5;
  max-width: var(--ro-measure);
  padding-top: var(--ro-stack-sm);
  border-top: 1px dashed var(--ro-border);
  margin-top: auto;
}
.ro-deals-listing .deal-conditions svg {
  width: 14px;
  height: 14px;
  flex: none;
  margin-top: 3px;
  opacity: .7;
}
.ro-deals-listing .deal-ctas {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: auto;
}
.ro-deals-listing .deal-conditions + .deal-ctas {
  margin-top: var(--ro-stack-sm);
}
.ro-deals-listing .deal-media--fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  overflow: hidden;
  background-color: rgb(var(--ro-rgb-primary) / .2);
}
.ro-deals-listing .deal-media--fallback svg {
  width: 58px;
  height: 58px;
  opacity: .9;
}

/* Featured Deal (wide card) */
.ro-deals-listing .deal-feature {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  align-items: stretch;
  background: var(--ro-surface);
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  overflow: hidden;
  box-shadow: var(--ro-shadow-card);
  margin-bottom: 28px;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-deals-listing .deal-feature:hover {
  box-shadow: var(--ro-shadow-card-hover);
  border-color: var(--ro-border-hover);
}
.ro-deals-listing .deal-feature .deal-media {
  aspect-ratio: auto;
  min-height: 360px;
  height: 100%;
}
.ro-deals-listing .deal-feature .deal-body {
  padding: 40px 44px;
  justify-content: center;
}
/* Body copy. */
.ro-deals-listing .deal-feature .deal-sub {
  font-size: var(--ro-fs-prose);
  max-width: var(--ro-measure);
}
.ro-deals-listing .deal-feature .deal-value b {
  font-size: 34px;
}
.ro-deals-listing .deal-feature .deal-conditions {
  margin-top: var(--ro-stack-md);
}

/* Responsive adjustments */
@media (max-width: 1024px) {
  .ro-deals-listing .deals-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 900px) {
  .ro-deals-listing .deal-feature {
    grid-template-columns: 1fr;
  }
  .ro-deals-listing .deal-feature .deal-media {
    min-height: 0;
    aspect-ratio: 16 / 9;
  }
  .ro-deals-listing .deal-feature .deal-body {
    padding: 26px 26px 30px;
  }
}
@media (max-width: 680px) {
  .ro-deals-listing .deals-grid {
    grid-template-columns: 1fr;
  }
  .ro-deals-listing .deal-media {
    aspect-ratio: 16 / 9;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rws-card, .media-slide, .rws-img, .media-slide--video video, .rws-arrow, .ro-viewer, .ro-viewer__media-item, .ro-viewer__hero-source, .ro-toast, .ro-deals-listing .deal-card, .ro-deals-listing .deal-feature {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .rws-arrow:active, .action-button:active, .ro-viewer__close:active, .ro-viewer__work-nav:active, .ro-viewer__media-nav:active {
    transform: none !important;
  }
}

.ro-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translate(-50%, 12px);
  background: rgb(var(--ro-rgb-sidebar));
  color: rgb(var(--ro-rgb-sidebar-fg));
  padding: 10px 18px;
  border-radius: 9999px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  z-index: 7500;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ro-ease), transform 220ms var(--ro-ease);
  max-width: 90vw;
  width: max-content;
  font-family: var(--ro-font-sans);
  font-size: var(--ro-fs-ui-sm);
  font-weight: 500;
}
.ro-toast svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--ro-primary-strong);
}
.ro-toast span {
  white-space: nowrap;
}
.ro-toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
.ro-cart-undo-toast[hidden] { display: none; }
.ro-cart-undo-toast {
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 12px;
  width: max-content;
  max-width: min(90vw, 396px);
  border-radius: 16px;
  padding: 10px 12px;
}
.ro-cart-undo-toast .ro-cart-undo-toast__message { white-space: normal; }
.ro-cart-undo-toast__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.ro-cart-undo-toast__button {
  min-height: 44px;
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 0 12px;
  background: transparent;
  color: rgb(var(--ro-rgb-sidebar-fg));
  font: inherit;
  cursor: pointer;
  transition: background-color var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-cart-undo-toast__button.ro-cart-undo-toast__button:focus,
.ro-cart-undo-toast__button.ro-cart-undo-toast__button:active {
  background: transparent;
  color: rgb(var(--ro-rgb-sidebar-fg));
}
.ro-cart-undo-toast__button.ro-cart-undo-toast__button:hover,
.ro-cart-undo-toast__button.ro-cart-undo-toast__button:focus:hover,
.ro-cart-undo-toast__button.ro-cart-undo-toast__button:active:hover {
  background: rgb(var(--ro-rgb-sidebar-fg) / 0.12);
  color: rgb(var(--ro-rgb-sidebar-fg));
}
.ro-cart-undo-toast__button:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-cart-undo-toast__button:active { transform: scale(.97); }
@media (prefers-reduced-motion: reduce) {
  .ro-cart-undo-toast__button { transition-duration: .01ms; }
  .ro-cart-undo-toast__button:active { transform: none; }
}

/* ============================================================
   WORKS PORTFOLIO PAGE (v3.17.0)
============================================================ */
.ro-works-page {
  /* 1 · SEMANTIC — light "Soft UI" surface default */
  --ro-rgb-background: 246 241 242;      /* warm pink-tinted canvas #F6F1F2 */
  --ro-rgb-surface: 255 255 255;         /* cards                   #FFFFFF */
  --ro-rgb-surface-2: 251 248 249;       /* nested tiles            #FBF8F9 */
  --ro-rgb-foreground: 56 46 51;         /* warm ink                #382E33 */
  --ro-rgb-muted-fg: 113 99 106;         /* secondary text          #71636A */
  --ro-rgb-border: 237 228 231;          /* hairlines               #EDE4E7 */
  --ro-rgb-border-hover: 229 205 214;    /* card hover tint         #E5CDD6 */
  --ro-rgb-ring: 224 74 111;             /* focus ring = primary-strong */

  --ro-background: #F6F1F2;
  --ro-surface: #FFFFFF;
  --ro-surface-2: #FBF8F9;
  --ro-foreground: #382E33;
  --ro-muted-fg: #71636A;
  --ro-border: #EDE4E7;
  --ro-border-hover: #E5CDD6;

  --ro-shadow-card: 0 1px 2px rgba(56, 46, 51, 0.05), 0 6px 20px rgba(56, 46, 51, 0.07);
  --ro-shadow-card-hover: 0 2px 4px rgba(56, 46, 51, 0.06), 0 14px 32px rgba(56, 46, 51, 0.11);
  --ro-shadow-btn: 0 2px 6px rgba(224, 74, 111, 0.3), 0 8px 20px rgba(224, 74, 111, 0.18);
  --ro-shadow-btn-hover: 0 4px 10px rgba(224, 74, 111, 0.35), 0 12px 28px rgba(224, 74, 111, 0.24);

  color-scheme: light;
  position: relative;
  background: transparent;
  color: var(--ro-foreground);
  font-family: var(--ro-font-sans);
  width: 100%;
}

/* Scoped dark overrides */
.ro-works-page.is-dark {
  --ro-rgb-background: 24 18 21;       /* #181215 near-black plum   */
  --ro-rgb-surface: 42 32 38;          /* #2A2026 cards             */
  --ro-rgb-surface-2: 52 40 48;        /* #342830 nested tiles      */
  --ro-rgb-foreground: 243 235 238;    /* #F3EBEE warm off-white    */
  --ro-rgb-muted-fg: 180 163 171;      /* #B4A3AB secondary text    */
  --ro-rgb-border: 62 48 56;           /* #3E3038 hairlines         */
  --ro-rgb-border-hover: 92 70 81;     /* #5C4651 hover tint        */
  --ro-rgb-ring: 241 107 137;          /* focus ring = lighter pink */

  --ro-background: #181215;
  --ro-surface: #2A2026;
  --ro-surface-2: #342830;
  --ro-foreground: #F3EBEE;
  --ro-muted-fg: #B4A3AB;
  --ro-border: #3E3038;
  --ro-border-hover: #5C4651;

  --ro-shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35);
  --ro-shadow-card-hover: 0 2px 4px rgba(0, 0, 0, 0.35), 0 14px 32px rgba(0, 0, 0, 0.5);

  color-scheme: dark;
  /* Solid dark base on the element itself — the ::before/::after decorative
     layers are transparent, so without this the host page's (light) background
     shows through. Element is position:relative (base rule), so its bg sits
     under the absolute pattern/glow layers below, which sit under content. */
  background: var(--ro-background);
}

/* Layer 1 — full-page orchid lattice pattern (absolute so it's scoped to the
   element and immune to Elementor ancestor transforms/sticky, which would
   otherwise re-anchor a position:fixed layer) */
.ro-works-page.is-dark::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Cg stroke='%23F16B89' stroke-opacity='0.09' stroke-width='1.2'%3E%3Cpath d='M60 60c-10-16 2-32 0-44 -2 12-10 28 0 44z'/%3E%3Cpath d='M60 60c16-10 32 2 44 0 -12-2-28-10-44 0z'/%3E%3Cpath d='M60 60c10 16-2 32 0 44 2-12 10-28 0-44z'/%3E%3Cpath d='M60 60c-16 10-32-2-44 0 12 2 28 10 44 0z'/%3E%3C/g%3E%3Cg stroke='%236FC5D8' stroke-opacity='0.07' stroke-width='1.1'%3E%3Cpath d='M180 180c-8-13 2-26 0-36 -2 10-8 23 0 36z'/%3E%3Cpath d='M180 180c13-8 26 2 36 0 -10-2-23-8-36 0z'/%3E%3Cpath d='M180 180c8 13-2 26 0 36 2-10 8-23 0-36z'/%3E%3Cpath d='M180 180c-13 8-26-2-36 0 10 2 23 8 36 0z'/%3E%3C/g%3E%3Cg fill='%23F7A853' fill-opacity='0.10' stroke='none'%3E%3Ccircle cx='60' cy='60' r='1.6'/%3E%3Ccircle cx='180' cy='180' r='1.4'/%3E%3Ccircle cx='180' cy='48' r='1'/%3E%3Ccircle cx='36' cy='186' r='1'/%3E%3Ccircle cx='126' cy='120' r='0.8'/%3E%3C/g%3E%3Cg stroke='%23F3EBEE' stroke-opacity='0.025' stroke-width='0.7'%3E%3Cpath d='M0 120h240M120 0v240'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
  background-size: 240px 240px;
  height: 100%;
}

/* Layer 2 — ambient glow pools */
.ro-works-page.is-dark::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(640px 420px at 12% 6%, rgb(var(--ro-skin-lead-rgb) / 0.16), transparent 70%),
    radial-gradient(760px 520px at 88% 24%, rgb(var(--ro-skin-comp-rgb) / 0.10), transparent 70%),
    radial-gradient(560px 560px at 70% 92%, rgb(var(--ro-skin-lead-rgb) / 0.08), transparent 70%),
    radial-gradient(420px 420px at 30% 60%, rgb(var(--ro-skin-comp-rgb) / 0.06), transparent 70%);
  animation: ro-glow-breathe 16s ease-in-out infinite alternate;
}

/* Motion safety: kill the ambient glow breathe + card transitions. */
@media (prefers-reduced-motion: reduce) {
  .ro-works-page.is-dark::after { animation: none !important; }
  .ro-works-page .rws-card,
  .ro-works-page .main-image,
  .ro-works-page .card-badge {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
  }
  /* The drawer needs its own entry, not a seat on the list above: its closed state
     hides via a transition-DELAY on `visibility`, and transition-duration does not
     touch a delay. Left on the shared rule the drawer would snap off-screen instantly
     and stay focusable for --ro-dur afterwards — U6 reinstated, for reduced-motion
     visitors only. Zero both. Kept separate so the delay reset does not leak onto
     .rws-card / .main-image / .card-badge, which have no delay to reset. */
  .ro-works-page .filters-sidebar {
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }
}

.ro-works-page.is-light {
  background:
    radial-gradient(circle at 80% 10%, rgb(var(--ro-rgb-primary) / .08), transparent 45rem),
    radial-gradient(circle at 10% 40%, rgb(var(--ro-rgb-secondary) / .06), transparent 45rem),
    var(--ro-background);
}

.ro-works-page .page-hero {
  text-align: center;
  padding: 80px 24px 48px;
  max-width: 800px;
  margin: 0 auto;
}
.ro-works-page .page-eyebrow {
  display: block;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ro-skin-lead);
  margin-bottom: 12px;
}
.ro-works-page h1.page-title {
  font-family: var(--ro-font-serif);
  font-size: var(--ro-fs-h1);
  font-weight: 900;
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 16px;
  color: var(--ro-foreground);
}
.ro-works-page .page-subtitle {
  /* Lead copy. */
  font-size: var(--ro-fs-lead);
  line-height: 1.6;
  color: var(--ro-muted-fg);
  max-width: var(--ro-measure);
  margin: 0;
}

.ro-works-page .works-layout,
.ro-work-single {
  max-width: calc(var(--ro-works-max) + 2 * var(--ro-works-gutter));
  margin-inline: auto;
  padding-inline: var(--ro-works-gutter);
}
.ro-work-single { padding-block-start: var(--ro-stack-md); }
@media (min-width: 960px) {
  .ro-work-single { padding-block-start: var(--ro-stack-lg); }
}
/* Archive and single share content edges at every width by construction; no other page uses these tokens. */
.ro-works-page .works-layout {
  padding-bottom: 80px;
  display: flex;
  gap: 32px;
  align-items: flex-start;
}

.ro-works-page .filters-sidebar {
  flex: 0 0 280px;
  padding: 4px 24px 4px 0;
  position: sticky;
  top: 90px;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  background: transparent;
  border: none;
  border-right: 1px solid rgb(var(--ro-rgb-border));
  border-radius: 0;
  box-shadow: none;
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
  scrollbar-gutter: stable;
}

.ro-works-page .filter-promoted {
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgb(var(--ro-rgb-border) / 0.8);
}
.ro-works-page .filter-promoted .category-tree {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ro-works-page .filter-promoted .tree-node,
.ro-works-page .filter-promoted .tree-children,
.ro-works-page .filter-promoted .node-label {
  display: contents;
}
.ro-works-page .filter-promoted .checkbox-label {
  padding: 6px 10px;
  border: 1px solid rgb(var(--ro-rgb-border));
  border-radius: 999px;
  background: var(--ro-surface);
}
.ro-works-page .filter-promoted .checkbox-label:has(input:checked),
.ro-works-page .filter-promoted .checkbox-label:has(input:indeterminate) {
  border-color: var(--ro-primary-strong);
  background: rgb(var(--ro-rgb-primary-strong) / 0.1);
}
.ro-works-page .filter-promoted .filter-group-title {
  margin-bottom: 12px;
}
.ro-works-page .filter-disclosure {
  margin-top: 4px;
}
.ro-works-page .filter-disclosure-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 8px 0;
  border: 0;
  border-bottom: 1px solid rgb(var(--ro-rgb-border));
  color: var(--ro-foreground);
  background: transparent;
  font-size: 13px;
  font-weight: 800;
  text-align: left;
  cursor: pointer;
}
.ro-works-page .filter-disclosure-toggle:hover,
.ro-works-page .filter-disclosure-toggle:focus-visible {
  color: var(--ro-primary-strong);
}
.ro-works-page .advanced-filter-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 50%;
  color: #fff;
  background: var(--ro-primary-strong);
  font-size: 9px;
  font-weight: 800;
}
.ro-works-page .advanced-filter-count[hidden],
.ro-works-page .filter-disclosure-panel[hidden] {
  display: none;
}
.ro-works-page .filter-disclosure-panel {
  padding-top: 20px;
}

.ro-works-page .filters-sidebar:hover,
.ro-works-page .filters-sidebar:focus-within {
  scrollbar-color: rgb(var(--ro-rgb-border-hover)) transparent;
}
.ro-works-page .filters-sidebar::-webkit-scrollbar {
  width: 5px;
}
.ro-works-page .filters-sidebar::-webkit-scrollbar-track {
  background: transparent;
}
.ro-works-page .filters-sidebar::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: 999px;
}
.ro-works-page .filters-sidebar:hover::-webkit-scrollbar-thumb,
.ro-works-page .filters-sidebar:focus-within::-webkit-scrollbar-thumb {
  background: rgb(var(--ro-rgb-border-hover));
}

.ro-works-page .sidebar-mobile-header {
  display: none;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid rgb(var(--ro-rgb-border));
  padding-bottom: 14px;
  margin-bottom: 18px;
}
.ro-works-page .mobile-header-title {
  font-family: var(--ro-font-serif);
  font-size: 20px;
  font-weight: 900;
  color: var(--ro-foreground);
}
.ro-works-page .mobile-clear-btn {
  background: transparent;
  border: none;
  color: var(--ro-primary-strong);
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  padding: 4px 8px;
}
.ro-works-page .mobile-close-btn {
  background: var(--ro-surface-2);
  border: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ro-foreground);
}
.ro-works-page .mobile-close-btn .icon {
  width: 16px;
  height: 16px;
}

.ro-works-page .filter-group {
  margin-bottom: 24px;
  border-bottom: 1px solid rgb(var(--ro-rgb-border) / 0.8);
  padding-bottom: 20px;
}
.ro-works-page .filter-group:last-child {
  border-bottom: none;
  padding-bottom: 0;
  margin-bottom: 0;
}
.ro-works-page .filter-group-title {
  font-family: var(--ro-font-sans);
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ro-muted-fg);
  margin-bottom: 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.ro-works-page .category-tree {
  display: grid;
  gap: 12px;
}
.ro-works-page .tree-node {
  display: grid;
  gap: 8px;
}
.ro-works-page .node-label {
  display: flex;
  align-items: center;
  gap: 6px;
}
.ro-works-page .category-tree .parent > .node-label > .checkbox-label {
  font-weight: 800;
  font-size: 13.5px;
}
.ro-works-page .tree-children {
  margin-left: 14px;
  display: grid;
  gap: 8px;
}

.ro-works-page .checkbox-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  color: var(--ro-foreground);
}
.ro-works-page .checkbox-label input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border: 1px solid rgb(var(--ro-rgb-border-hover));
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  position: relative;
  transition: background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .checkbox-label input[type="checkbox"]:checked {
  background-color: var(--ro-primary-strong);
  border-color: var(--ro-primary-strong);
}
.ro-works-page .checkbox-label input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 2px;
  width: 5px;
  height: 8px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.ro-works-page .checkbox-label input[type="checkbox"]:indeterminate {
  background-color: var(--ro-secondary-strong);
  border-color: var(--ro-secondary-strong);
}
.ro-works-page .checkbox-label input[type="checkbox"]:indeterminate::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 7px;
  width: 8px;
  height: 2px;
  background: #fff;
}

.ro-works-page .color-swatches {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.ro-works-page .swatch-btn {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background-color: var(--swatch-color);
  border: 1px solid rgb(var(--ro-rgb-border-hover));
  cursor: pointer;
  position: relative;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
  padding: 0;
}
.ro-works-page .swatch-btn:hover {
  box-shadow: 0 0 0 2px var(--ro-surface), 0 0 0 3px rgb(var(--ro-rgb-border-hover));
}
.ro-works-page .swatch-btn:active {
  transform: scale(0.94);
}
.ro-works-page .swatch-btn[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--ro-surface), 0 0 0 4px rgb(var(--ro-rgb-primary-strong));
  border-color: transparent;
}
.ro-works-page .swatch-white {
  background: #ffffff;
  border: 1px solid rgb(var(--ro-rgb-border-hover));
}

.ro-works-page .switch-control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  cursor: pointer;
  user-select: none;
  color: var(--ro-foreground);
}
.ro-works-page .switch-label {
  font-size: 13px;
  font-weight: 600;
}
.ro-works-page .switch-control input {
  display: none;
}
.ro-works-page .switch-slider {
  position: relative;
  width: 44px;
  height: 24px;
  background-color: rgb(var(--ro-rgb-border));
  border-radius: 999px;
  transition: background-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .switch-slider::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background-color: var(--ro-surface);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  transition: transform var(--ro-dur) var(--ro-ease);
}
.ro-works-page .switch-control input:checked + .switch-slider {
  background-color: var(--ro-primary-strong);
}
.ro-works-page .switch-control input:checked + .switch-slider::before {
  transform: translateX(20px);
}

.ro-works-page .sidebar-mobile-footer {
  display: none;
  position: sticky;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--ro-surface);
  padding-top: 14px;
  margin-top: 14px;
  border-top: 1px solid rgb(var(--ro-rgb-border));
  z-index: 5;
}
.ro-works-page .mobile-apply-btn {
  width: 100%;
  min-height: 44px;
  background: var(--ro-primary-strong);
  color: #fff;
  border: none;
  border-radius: var(--ro-radius-control);
  font-weight: 800;
  font-size: 14px;
  cursor: pointer;
  box-shadow: var(--ro-shadow-btn);
  transition: background-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease);
}
.ro-works-page .mobile-apply-btn:hover {
  background: rgb(var(--ro-rgb-primary-strong) / 0.9);
  box-shadow: var(--ro-shadow-btn-hover);
}

.ro-works-page .sidebar-clear-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  min-height: 40px;
  margin-top: var(--ro-stack-md);
  background: transparent;
  border: 1px solid rgb(var(--ro-rgb-border));
  border-radius: var(--ro-radius-control);
  color: var(--ro-muted-fg);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .sidebar-clear-btn:hover {
  color: var(--ro-primary-strong);
  border-color: rgb(var(--ro-rgb-primary) / 0.5);
  background: rgb(var(--ro-rgb-primary) / 0.04);
}

.ro-works-page .works-main-content {
  flex: 1;
  min-width: 0;
  container: ro-works-grid / inline-size;
}

.ro-works-page .listing-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
  gap: 16px;
  flex-wrap: wrap;
  border-bottom: 1px solid rgb(var(--ro-rgb-border));
  padding-bottom: 14px;
}
.ro-works-page .results-count {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ro-muted-fg);
}
.ro-works-page .listing-actions-desktop {
  display: flex;
  align-items: center;
  gap: 20px;
}
.ro-works-page .sort-control-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ro-works-page .sort-label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ro-muted-fg);
}
.ro-works-page .sort-segmented {
  background: transparent;
  padding: 0;
  display: flex;
  border: none;
  gap: 16px;
}
.ro-works-page .sort-btn {
  background: transparent;
  border: none;
  color: var(--ro-muted-fg);
  font-size: 12px;
  font-weight: 700;
  padding: 6px 2px;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: color var(--ro-dur) var(--ro-ease), border-bottom-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .sort-btn.active {
  background: transparent;
  box-shadow: none;
  color: var(--ro-foreground);
  border-bottom-color: var(--ro-primary-strong);
}

.ro-works-page .theme-toggle-btn {
  background: transparent;
  border: 1px solid rgb(var(--ro-rgb-border));
  border-radius: var(--ro-radius-control);
  min-height: 38px;
  padding: 8px 14px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  color: var(--ro-foreground);
  font-size: 13px;
  font-weight: 700;
  transition: background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .theme-toggle-btn:hover {
  background: var(--ro-surface-2);
  border-color: rgb(var(--ro-rgb-border-hover));
}
.ro-works-page .theme-toggle-btn svg {
  width: 15px;
  height: 15px;
}

.ro-works-page .mobile-filter-trigger {
  display: none;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  padding: 8px 14px;
  background: var(--ro-surface);
  border: 1px solid rgb(var(--ro-rgb-border-hover));
  border-radius: var(--ro-radius-control);
  color: var(--ro-foreground);
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  box-shadow: var(--ro-shadow-card);
  transition: background-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .mobile-filter-trigger:hover {
  background-color: var(--ro-surface-2);
}
.ro-works-page .filter-count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 50%;
  background: var(--ro-primary-strong);
  color: #fff;
  font-size: 9px;
  font-weight: 800;
}
.ro-works-page .filter-count-badge[hidden] {
  display: none;
}

.ro-works-page .active-chips-container {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 24px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
}
.ro-works-page .active-chips-label {
  font-size: 11px;
  font-weight: 800;
  color: var(--ro-muted-fg);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ro-works-page .chips-list {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.ro-works-page .filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--ro-surface);
  border: 1px solid rgb(var(--ro-rgb-border-hover));
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  color: var(--ro-foreground);
}
.ro-works-page .filter-chip button {
  background: transparent;
  border: none;
  color: var(--ro-muted-fg);
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  transition: color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .filter-chip button:hover {
  color: var(--ro-primary-strong);
  background: rgb(var(--ro-rgb-primary) / 0.1);
}
.ro-works-page .clear-all-chips-btn {
  background: transparent;
  border: none;
  color: var(--ro-primary-strong);
  font-size: 12px;
  font-weight: 800;
  cursor: pointer;
  padding: 4px 8px;
}

.ro-works-page .works-grid {
  display: grid;
  /* Floor 300px: 2-up at 624px; 3-up at 948px (3 × 300 + 2 × 24). The Owner's
     maximum is 3 columns (2026-10-10), so there is no wider state. */
  --works-cols: 1;
  grid-template-columns: repeat(var(--works-cols), minmax(0, 1fr));
  gap: 16px;
  transition: opacity var(--ro-dur) var(--ro-ease);
  width: 100%;
}
@container ro-works-grid (min-width: 624px) {
  .ro-works-page .works-grid { --works-cols: 2; gap: 24px; }
}
@container ro-works-grid (min-width: 948px) {
  .ro-works-page .works-grid { --works-cols: 3; }
}

.ro-works-page .rws-card {
  background: var(--ro-surface);
  border: 1px solid rgb(var(--ro-rgb-border));
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-works-page .rws-card:hover {
  border-color: rgb(var(--ro-rgb-border-hover));
  box-shadow: var(--ro-shadow-card-hover);
}

.ro-works-page .media-stage {
  position: relative;
  overflow: hidden;
  background: var(--ro-surface-2);
  cursor: pointer;
  width: 100%;
  aspect-ratio: 5 / 4;                                             /* R8 landscape family */
  border-radius: var(--ro-radius-card) var(--ro-radius-card) 0 0;  /* round top only; bottom is flush into the body */
}
/* Stacked slide layers (video + angle images); one is-active at a time. */
.ro-works-page .media-el {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--ro-dur) var(--ro-ease);
}
.ro-works-page .media-el.is-active {
  opacity: 1;
  visibility: visible;
}
/* Scoped to .media-stage: paintCardHero() clones the card's .media-el INTO the dialog, and
   the dialog is a descendant of .ro-works-page, so an unscoped rule here also applied to the
   clone - height:100%!important beat every viewer override and cropped the hero on
   /our-works/ on open, permanently so whenever the REST hydration failed. */
.ro-works-page .media-stage .main-image {
  display: block;
  width: 100%;
  height: 100% !important;
  object-fit: cover;
  transition: filter var(--ro-dur) var(--ro-ease);
}
/* A hero wider than 5:4 is painted at k x the card width (cover scales it to the card height). The
   img box is widened to that painted width (--k) and shifted by its focus (--fx), so sizes="auto"
   stays exact; the media stage clips it at the card edges. */
.ro-works-page .media-stage .media-el--wide .main-image {
  width: calc(var(--k, 1) * 100%);
  max-width: none;
  margin-left: calc((1 - var(--k, 1)) * 100% * var(--fx, .5));
}

/* #223 S2: .hover-caption-bar and the five .nav-arrow* rules deleted with the
   markup S1 removed. The caption bar was U2 — the only label an archive tile had,
   at opacity:0 outside hover:hover, so 63 tiles were anonymous on touch; the card
   now carries a permanently visible <h3>. The arrows were U3 — two invisible 38px
   opacity:0 buttons with no pointer-events:none, swallowing taps at the left and
   right edge of every tile. Both markup sets are gone from the renderer (live
   count 0 on 2026-08-24); this is the CSS catching up. The (hover:hover) block
   that revealed them held nothing else. */

.ro-works-page .play-badge {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(24, 18, 21, 0.6);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
  pointer-events: none;
  z-index: 10;
  transition: opacity var(--ro-dur) var(--ro-ease);
}
.ro-works-page .play-badge .icon {
  width: 20px;
  height: 20px;
  margin-left: 2px;
}

.ro-works-page .media-badges {
  position: absolute;
  top: 14px;
  left: 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  pointer-events: none;
  z-index: 12;
}
.ro-works-page .card-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  border-radius: 6px;
  font-size: 9px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  width: max-content;
}
.ro-works-page .badge-primary { background: var(--ro-primary-strong); }
.ro-works-page .badge-secondary { background: var(--ro-secondary-strong); }
.ro-works-page .badge-accent { background: var(--ro-accent-strong); }
/* Rank is not tag: keep h3, at 18-20px like the reference card title below the page's h2. */
.ro-works-page h3.rws-card__title {
  margin: 0;
  padding: 12px 16px 0;
  color: var(--ro-foreground);
  font-family: var(--ro-font-serif);
  font-size: max(18px, var(--ro-fs-h4));
  font-weight: 900;
  line-height: 1.3;
  min-height: calc(2 * 1.3em + 12px);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ro-works-page .rws-card__body {
  padding: 12px 16px 16px;
  background: var(--ro-surface);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 12px;
  flex: 1;
}
.ro-works-page .card-action-row {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
}
.ro-works-page .action-left {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ro-works-page .action-right {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

/* Sane default size for every icon in the page (the .icon class carries no
   intrinsic size, so unscoped SVGs — close, clear-all, save, share — would
   otherwise balloon). Specific rules below (play, like, book) win
   on higher specificity. */
.ro-works-page .icon {
  width: 16px;
  height: 16px;
  flex: none;
}
.ro-works-page .action-btn-circle .icon {
  width: 15px;
  height: 15px;
}

.ro-works-page .action-btn-circle {
  width: 36px;
  height: 36px;
  border-radius: var(--ro-radius-control);
  border: 1px solid rgb(var(--ro-rgb-border));
  background: var(--ro-surface-2);
  color: var(--ro-muted-fg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
  padding: 0;
}
.ro-works-page .action-btn-circle:hover {
  color: var(--ro-primary-strong);
  background: rgb(var(--ro-rgb-primary) / 0.08);
  border-color: rgb(var(--ro-rgb-primary) / 0.38);
}
.ro-works-page .action-btn-circle[aria-pressed="true"] {
  color: var(--ro-primary-strong);
  background: rgb(var(--ro-rgb-primary) / 0.12);
  border-color: rgb(var(--ro-rgb-primary) / 0.45);
}
.ro-works-page .action-btn-circle:active {
  transform: scale(0.94);
}
.ro-works-page .like-btn {
  width: auto;
  height: 36px;
  border-radius: var(--ro-radius-control);
  padding-inline: 12px;
  gap: 6px;
  font-size: 12px;
  font-weight: 800;
}
.ro-works-page .like-btn .icon {
  width: 15px;
  height: 15px;
}
.ro-works-page .card-price {
  font-size: 15px;
  font-weight: 850;
  color: var(--ro-foreground);
  white-space: nowrap;
}
.ro-works-page .book-btn {
  white-space: nowrap;
  min-height: 36px;
  border: none;
  border-radius: var(--ro-radius-control);
  background: var(--ro-primary-strong);
  color: #fff;
  font-weight: 800;
  font-size: 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 18px 8px 14px;
  box-shadow: var(--ro-shadow-btn);
  transition: background-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-works-page .book-btn:hover {
  background: rgb(var(--ro-rgb-primary-strong) / 0.9);
  box-shadow: var(--ro-shadow-btn-hover);
}
.ro-works-page .book-btn.is-booked,
.ro-works-page .book-btn[aria-pressed="true"] {
  color: var(--ro-foreground); background: var(--ro-surface-2);
  border: 1px solid var(--ro-border-hover); box-shadow: var(--ro-shadow-card);
}
.ro-works-page .book-btn.is-booked:hover,
.ro-works-page .book-btn[aria-pressed="true"]:hover {
  color: var(--ro-foreground); background: var(--ro-surface);
  border-color: var(--ro-primary); box-shadow: var(--ro-shadow-card-hover);
}
.ro-works-page .book-btn:active {
  transform: scale(0.96);
}
.ro-works-page .book-btn .icon {
  width: 12px;
  height: 12px;
}

.ro-works-page .load-more-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 48px;
  gap: 12px;
}
.ro-works-page .load-more-btn {
  min-height: 48px;
  border: 1px solid rgb(var(--ro-rgb-border-hover));
  border-radius: var(--ro-radius-control);
  padding: 10px 28px;
  color: var(--ro-primary-strong);
  background: var(--ro-surface);
  font-weight: 800;
  font-size: 14px;
  box-shadow: var(--ro-shadow-card);
  cursor: pointer;
  transition: background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-works-page .load-more-btn:hover {
  border-color: rgb(var(--ro-rgb-primary) / .62);
  background: rgb(var(--ro-rgb-primary) / .07);
  box-shadow: var(--ro-shadow-card-hover);
}
.ro-works-page .load-more-btn:active {
  transform: scale(.97);
}
.ro-works-page .load-more-note {
  font-size: 12px;
  color: var(--ro-muted-fg);
  font-weight: 600;
}

.ro-works-page .empty-state {
  text-align: center;
  padding: 64px 24px;
  background: var(--ro-surface);
  border: 2px dashed rgb(var(--ro-rgb-border));
  border-radius: var(--ro-radius-card);
  box-shadow: var(--ro-shadow-card);
  max-width: 500px;
  margin: 40px auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ro-stack-sm);
}
.ro-works-page .empty-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: rgb(var(--ro-rgb-primary) / 0.1);
  color: var(--ro-primary-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 8px;
}
.ro-works-page .empty-icon .icon {
  width: 32px;
  height: 32px;
}
.ro-works-page .empty-title {
  font-size: 22px;
  font-weight: 900;
}
.ro-works-page .empty-text {
  color: var(--ro-muted-fg);
  font-size: 14px;
}
.ro-works-page .empty-btn {
  min-height: 40px;
  border: none;
  background: var(--ro-primary-strong);
  color: #fff;
  font-weight: 800;
  font-size: 13px;
  padding: 10px 24px;
  border-radius: var(--ro-radius-control);
  cursor: pointer;
  box-shadow: var(--ro-shadow-btn);
  transition: background-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease);
}
.ro-works-page .empty-btn:hover {
  background: rgb(var(--ro-rgb-primary-strong) / 0.9);
  box-shadow: var(--ro-shadow-btn-hover);
}

.ro-works-page .sidebar-backdrop {
  display: none;
}

/* Keep the sidebar while the grid beside it holds 3 × 300px cards:
   vw - 2·3vw >= 280 + 32 + 948, which solves to 1340px. */
@media (max-width: 1339px) {
  .ro-works-page .works-layout {
    gap: 0;
    padding-bottom: 40px;
  }
  .ro-works-page .mobile-filter-trigger {
    display: inline-flex;
  }
  .ro-works-page .filters-sidebar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 100;
    max-height: 80vh;
    width: 100%;
    flex: none;
    border-radius: 24px 24px 0 0;
    border: none;
    border-top: 1px solid rgb(var(--ro-rgb-border));
    box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.15);
    transform: translateY(100%);
    /* U6 (#223 S2): transform alone moves the drawer visually and leaves all 46 of
       its controls in the tab order, hit-testable, and in the a11y tree — measured
       live on /our-works/ as 9 <button> + 37 <input> reachable by Tab before the
       drawer is ever opened. visibility:hidden removes all three in one declaration
       and, unlike display:none, is transition-aware, so the slide survives. The
       closed state delays the flip by --ro-dur so the element stays visible while it
       slides out; the open state applies it immediately. */
    visibility: hidden;
    transition: transform var(--ro-dur) var(--ro-ease),
                visibility 0s linear var(--ro-dur);
    padding: 20px 24px 24px;
    background: var(--ro-surface);
  }
  .ro-works-page .filters-sidebar.is-open {
    transform: translateY(0);
    visibility: visible;
    transition: transform var(--ro-dur) var(--ro-ease),
                visibility 0s linear 0s;
  }
  .ro-works-page .sidebar-scroll-wrapper {
    overflow-y: auto;
    max-height: calc(80vh - 140px);
    padding-bottom: 20px;
  }
  .ro-works-page .sidebar-mobile-header {
    display: flex;
  }
  .ro-works-page .sidebar-mobile-footer {
    display: block;
  }
  .ro-works-page .sidebar-clear-btn {
    display: none;
  }
  .ro-works-page .drawer-handle {
    width: 40px;
    height: 4px;
    background: rgb(var(--ro-rgb-border));
    border-radius: 2px;
    margin: -8px auto 16px;
    display: block;
  }
  .ro-works-page .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(42, 32, 38, 0.5);
    z-index: 99;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--ro-dur) var(--ro-ease);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
  }
  .ro-works-page .sidebar-backdrop.is-visible {
    opacity: 1;
    pointer-events: auto;
  }
}

@media (max-width: 768px) {
  .ro-works-page .page-hero {
    padding-top: 48px;
    padding-bottom: 32px;
  }
  .ro-works-page .listing-toolbar {
    margin-bottom: 16px;
  }
}

/* Target size follows the input and drawer/touch context, never the card's width. The #223 S5a
   compact two-row body (built for 164px 2-up phone tiles) is gone: with the 300px card floor the
   Like + price + Book row fits ONE line at 44px down to a 272px card (320px viewport) - measured
   2026-10-10 (.dev/harness/bnet/probe-row.mjs), 0 wrapped, 0 overflow. */
@media (max-width: 1339px), (pointer: coarse) {
  .ro-works-page .book-btn { min-height: 44px; }
  .ro-works-page .action-btn-circle { width: 44px; height: 44px; }
}

/* ============================================================
   CONTACT (ro_section_contact) (v3.20.0)
============================================================ */

.ro-contact-grid {
  display: grid;
  grid-template-columns: 62fr 38fr;
  grid-template-areas: "media info";
  gap: 40px;
}

.ro-contact-grid--noslider {
  grid-template-columns: 1fr;
  grid-template-areas: "info";
  gap: 32px;
}

.cx-media {
  grid-area: media;
  min-width: 0;
}

.cx-info {
  grid-area: info;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* Slider */
.cx-slider {
  position: relative;
  border-radius: var(--ro-radius-card);
  overflow: hidden;
  box-shadow: var(--ro-shadow-card);
  background: var(--ro-surface);
}

.cx-ratio {
  position: relative;
  width: 100%;
  padding-top: 80%; /* 5:4 - the contact media slot follows the house 5:4 landscape media contract (16:9 came from the stock-image prototype and cropped real photos) */
}

.cx-slides {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.cx-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--ro-dur) var(--ro-ease), visibility var(--ro-dur) var(--ro-ease);
}

.cx-slide.is-active {
  opacity: 1;
  visibility: visible;
  z-index: 1;
}

.cx-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Dots */
.cx-dots {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;
  z-index: 2;
}

.cx-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  border: none;
  background: rgba(255, 255, 255, 0.4);
  padding: 0;
  cursor: pointer;
  transition: background-color var(--ro-dur) var(--ro-ease), width var(--ro-dur) var(--ro-ease);
}

.cx-dot.is-active {
  background: #fff;
  width: 16px;
}

.cx-dot:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* Info Rows & Facts */
h1.cx-title {
  margin: 0;
  font-family: var(--ro-font-serif);
  font-size: var(--ro-fs-h1);
  line-height: 1.15;
  color: var(--ro-foreground);
  font-weight: 900;
}
h2.cx-title {
  margin: 0;
  font-family: var(--ro-font-serif);
  font-size: var(--ro-fs-h2);
  line-height: 1.2;
  color: var(--ro-foreground);
  font-weight: 900;
}

.cx-eyebrow {
  margin-bottom: -12px;
}

.cx-info-rows {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.cx-fact {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  color: var(--ro-foreground);
  font-size: var(--ro-fs-ui);
  line-height: 1.5;
}

/* Plain glyph, no coin/box (owner: "plain, no boxes") — matches the approved prototype */
.cx-fact__icon {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  margin-top: 2px;
  color: var(--ro-skin-lead, var(--ro-primary-strong));
}

.cx-fact__icon svg {
  width: 20px;
  height: 20px;
}

.cx-fact__link {
  color: var(--ro-foreground);
  text-decoration: none;
  font-weight: 500;
  transition: color var(--ro-dur) var(--ro-ease);
}

.cx-fact__link:hover,
.cx-fact__link:focus-visible {
  color: var(--ro-primary-strong);
  text-decoration: underline;
}

.cx-fact__link:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
  border-radius: 4px;
}

/* Hours Rows */
.cx-hours-rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
}

.cx-hours-row {
  display: flex;
  justify-content: space-between;
  max-width: 280px;
  font-size: var(--ro-fs-ui);
}

.cx-hours-days {
  font-weight: 600;
}

.cx-hours-value {
  color: var(--ro-muted-fg);
}

/* Links & Atoms */
.cx-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* Social icon-coin colors (extend the atom's set) */
.ro-contact__icon--fb     { background: #1877F2; }
.ro-contact__icon--msgr   { background: linear-gradient(135deg,#0695FF,#A334FA); }
.ro-contact__icon--tiktok { background: #121212; }

/* Contact inline links — plain, NOT the pill atom (owner: "not buttons, not
   oversized, inline"). Scoped to .cx-links so Quick Booking's .ro-contact
   pills stay untouched. Doubled class + element on hover re-asserts color
   over Hello Elementor's magenta a:hover leak at (0,3,0). */
.cx-links .ro-contact {
  background: none; border: 0; box-shadow: none; border-radius: 0;
  padding: 8px 4px; min-height: 40px; gap: 10px;
}
.cx-links .ro-contact.ro-contact:hover,
.cx-links .ro-contact.ro-contact:focus-visible {
  background: none; box-shadow: none; border-color: transparent;
  color: var(--ro-primary-strong); text-decoration: underline; text-underline-offset: 3px;
}
.cx-links .ro-contact__icon { width: 28px; height: 28px; }
.cx-links .ro-contact__icon svg { width: 15px; height: 15px; }

/* Responsive ≤900px */
@media (max-width: 900px) {
  .ro-contact-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "media"
      "info";
    gap: 32px;
  }
  /* keep the no-slider fallback on mobile too — else the "media" track above
     reintroduces the empty-hole gap when there are 0 images */
  .ro-contact-grid--noslider {
    grid-template-areas:
      "info";
  }
}

/* ============================================================
   ARRIVAL (ro_section_arrival)
============================================================ */
.ro-section-arrival .ro-arrival__head {
  max-width: 72ch;
  margin: 0 0 var(--ro-stack-lg);
}

.ro-section-arrival .ro-arrival__eyebrow {
  display: inline-block;
  margin: 0 0 var(--ro-stack-xs);
}

.ro-section-arrival h2.ro-arrival__title,
.ro-section-arrival h3.ro-arrival__title {
  margin: 0 0 var(--ro-stack-sm);
  color: var(--ro-foreground);
  font-family: var(--ro-font-serif);
  font-weight: 900;
  line-height: 1.2;
}
.ro-section-arrival h2.ro-arrival__title { font-size: var(--ro-fs-h2); }
.ro-section-arrival h3.ro-arrival__title { font-size: var(--ro-fs-h3); }

.ro-section-arrival .ro-arrival__intro {
  max-width: 64ch;
  margin: 0;
  color: var(--ro-foreground);
  font-size: var(--ro-fs-lead);
  line-height: var(--ro-lh-prose);
}

.ro-section-arrival .ro-arrival__parking {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ro-stack-md);
  align-items: center;
  margin: var(--ro-stack-lg) 0 0;
  padding: var(--ro-stack-md);
  border: 1px solid var(--ro-border);
  border-inline-start: 4px solid var(--ro-skin-lead);
  border-radius: var(--ro-radius-card);
  background: var(--ro-surface);
  box-shadow: var(--ro-shadow-card);
}

.ro-section-arrival .ro-arrival__parking-title {
  margin: 0 0 var(--ro-stack-xs);
  color: var(--ro-foreground);
  font-family: var(--ro-font-serif);
  font-size: var(--ro-fs-h3);
  font-weight: var(--ro-fw-bold);
  line-height: 1.25;
}

.ro-section-arrival .ro-arrival__parking-text {
  max-width: 72ch;
  margin: 0;
  color: var(--ro-foreground);
  font-size: var(--ro-fs-prose-dense);
  line-height: 1.6;
}

.ro-section-arrival .ro-arrival__parking-text p { margin: 0; }
.ro-section-arrival .ro-arrival__parking-text p + p { margin-top: var(--ro-stack-xs); }
.ro-section-arrival .ro-arrival__parking-text strong { font-weight: var(--ro-fw-bold); }

/* Doubled class re-asserts colour/underline over the Kit's global link rules. */
.ro-section-arrival .ro-arrival__parking-text.ro-arrival__parking-text a {
  padding-block: 4px;
  color: var(--ro-primary-text);
  font-weight: var(--ro-fw-semibold);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-thickness var(--ro-dur) var(--ro-ease);
}

.ro-section-arrival .ro-arrival__parking-text.ro-arrival__parking-text a:hover,
.ro-section-arrival .ro-arrival__parking-text.ro-arrival__parking-text a:focus-visible {
  color: var(--ro-primary-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
}

.ro-section-arrival .ro-arrival__parking-text a:focus-visible {
  border-radius: 2px;
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
}

.ro-section-arrival .ro-arrival__parking-link {
  width: 100%;
  min-height: 48px;
}

.ro-section-arrival .ro-arrival__lead {
  display: grid;
  /* 1:2 tracks pair the 4:5 video with the 8:5 diagram at equal height. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 32px;
  align-items: start;
  width: 100%;
  max-width: none;
  margin: 0;
}

.ro-section-arrival .ro-arrival__video-figure,
.ro-section-arrival .ro-arrival__diagram-figure {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  background: var(--ro-surface);
  box-shadow: var(--ro-shadow-card);
}

.ro-section-arrival .ro-arrival__video-figure {
  width: 100%;
}

.ro-section-arrival .ro-arrival__diagram-figure {
  width: 100%;
  max-width: none;
}

.ro-section-arrival .ro-arrival__video-frame {
  position: relative;
}

.ro-section-arrival .ro-arrival__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--ro-surface);
}

.ro-section-arrival .ro-arrival__play {
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;
  display: grid;
  width: 72px;
  height: 72px;
  padding: 0;
  transform: translate(-50%, -50%);
  place-items: center;
  border: 2px solid var(--ro-primary-text);
  border-radius: 50%;
  background: var(--ro-surface);
  color: var(--ro-primary-text);
  box-shadow: var(--ro-shadow-card);
  cursor: pointer;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease);
}

.ro-section-arrival .ro-arrival__play.ro-arrival__play:hover,
.ro-section-arrival .ro-arrival__play.ro-arrival__play:focus {
  border-color: var(--ro-primary-text);
  background: var(--ro-surface);
  color: var(--ro-primary-text);
}

.ro-section-arrival .ro-arrival__play.ro-arrival__play:hover {
  box-shadow: var(--ro-shadow-card-hover);
}

.ro-section-arrival .ro-arrival__play.ro-arrival__play:focus-visible {
  outline: 2px solid var(--ro-surface);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--ro-foreground);
}

.ro-section-arrival .ro-arrival__play:active {
  transform: translate(-50%, -50%) scale(.96);
}

.ro-section-arrival .ro-arrival__play svg {
  width: 28px;
  height: 28px;
}

.ro-section-arrival .ro-arrival__play[hidden] {
  display: none;
}

.ro-section-arrival .ro-arrival__diagram {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 8 / 5;
  color: var(--ro-foreground);
  font-family: var(--ro-font-sans);
}

/* Plan colours are classes, not SVG presentation attributes: var() is not
   reliably honoured in attributes, and classes keep the plan on the skin. */
.ro-section-arrival .ro-arrival__map-ground   { fill: var(--ro-surface-2); }
.ro-section-arrival .ro-arrival__map-road     { fill: var(--ro-surface); }
.ro-section-arrival .ro-arrival__map-lane     { fill: none; stroke: var(--ro-border); stroke-width: 4; stroke-dasharray: 16 14; }
.ro-section-arrival .ro-arrival__map-building { fill: var(--ro-surface); stroke: var(--ro-border); stroke-width: 6; }
.ro-section-arrival .ro-arrival__map-zone     { fill: rgb(var(--ro-skin-lead-rgb) / .08); stroke: var(--ro-skin-lead); stroke-width: 4; stroke-dasharray: 12 10; }
.ro-section-arrival .ro-arrival__map-pin      { fill: rgb(var(--ro-skin-lead-rgb) / .16); stroke: var(--ro-skin-lead); stroke-width: 4; }
.ro-section-arrival .ro-arrival__map-pin-dot  { fill: var(--ro-skin-lead); }
.ro-section-arrival .ro-arrival__map-pin-text { fill: var(--ro-skin-lead-text); font-size: 44px; font-weight: 700; }
.ro-section-arrival .ro-arrival__map-number   { fill: currentColor; font-size: 80px; font-weight: 700; }
.ro-section-arrival .ro-arrival__map-label    { fill: currentColor; font-size: 40px; font-weight: 600; }
.ro-section-arrival .ro-arrival__map-sub,
.ro-section-arrival .ro-arrival__map-road-label { fill: var(--ro-muted-fg); font-size: 36px; font-weight: 600; }
.ro-section-arrival .ro-arrival__map-road-label { font-size: 40px; }

.ro-section-arrival .ro-arrival__caption {
  margin: 0;
  padding: 12px 16px;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-meta);
  line-height: 1.5;
}

.ro-section-arrival .ro-arrival__steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 24px;
  padding: 0;
  margin: var(--ro-stack-lg) 0 0;
  list-style: none;
  counter-reset: ro-arrival-step;
}

/* F_3.165.0: the card is media-first. Every step photo is square and
   full-bleed — measured, 1:1 is the one ratio that keeps each step's
   wayfinding content (parking signs, the 8500 numerals, the South Tower
   sign, the lit Floor 4 button) with no per-photo object-position. The
   text keeps its own padding on the body; the card itself has none. */
.ro-section-arrival .ro-arrival__step {
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card);
  background: var(--ro-surface);
  box-shadow: var(--ro-shadow-card);
  counter-increment: ro-arrival-step;
}

/* The number sits on the photo's corner on an opaque chip, so its contrast
   never depends on the photograph underneath. */
.ro-section-arrival .ro-arrival__step::before {
  position: absolute;
  z-index: 1;
  top: 12px;
  left: 12px;
  display: grid;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--ro-surface);
  box-shadow: var(--ro-shadow-card);
  color: var(--ro-skin-lead-text);
  content: counter(ro-arrival-step);
  font-size: var(--ro-fs-ui);
  font-weight: 700;
  place-items: center;
}

/* A step without a photo keeps the number in flow. The body padding lives
   on .ro-arrival__step-body, so the chip carries its own inset. */
.ro-section-arrival .ro-arrival__step:not(:has(.ro-arrival__step-media))::before {
  position: static;
  margin: 16px 20px 0;
  background: rgb(var(--ro-skin-lead-rgb) / .12);
  box-shadow: none;
}

.ro-section-arrival .ro-arrival__step-media {
  aspect-ratio: 1 / 1;
  margin: 0;
  overflow: hidden;
  background: var(--ro-surface-2);
}

.ro-section-arrival .ro-arrival__step-image {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.ro-section-arrival .ro-arrival__step-body {
  padding: 16px 20px 20px;
}

.ro-section-arrival h3.ro-arrival__step-title {
  margin: 0 0 var(--ro-stack-xs);
  color: var(--ro-foreground);
  font-family: var(--ro-font-serif);
  font-size: var(--ro-fs-h4);
  font-weight: var(--ro-fw-bold);
  line-height: 1.35;
}

/* Step copy is list copy: the body-dense role (tokens.css), as in
   .check-list and the indications cards. */
.ro-section-arrival .ro-arrival__step-text {
  margin: 0;
  color: var(--ro-foreground);
  font-size: var(--ro-fs-prose-dense);
  font-weight: var(--ro-fw-body);
  line-height: 1.6;
}

.ro-section-arrival .ro-arrival__directions {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  margin: var(--ro-stack-md) 0 0;
  padding: 8px 16px;
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-control);
  background: var(--ro-surface);
  color: var(--ro-foreground);
  font-size: var(--ro-fs-ui);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--ro-dur) var(--ro-ease), background-color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}

.ro-section-arrival .ro-arrival__directions.ro-arrival__directions:hover,
.ro-section-arrival .ro-arrival__directions.ro-arrival__directions:focus-visible {
  border-color: var(--ro-border-hover);
  background: var(--ro-surface-2);
  color: var(--ro-primary-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.ro-section-arrival .ro-arrival__directions:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
}

@media (min-width: 600px) {
  .ro-section-arrival .ro-arrival__steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 768px) {
  .ro-section-arrival .ro-arrival__parking { grid-template-columns: minmax(0, 1fr) auto; }
  .ro-section-arrival .ro-arrival__parking-link { width: auto; max-width: 100%; }
}

@media (min-width: 1100px) {
  .ro-section-arrival .ro-arrival__steps { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .ro-section-arrival .ro-arrival__lead {
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
  }
  .ro-section-arrival .ro-arrival__video-figure {
    width: min(100%, 336px);
    margin-inline: auto;
  }
  .ro-section-arrival .ro-arrival__diagram-figure {
    max-width: 760px;
    margin-inline: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ro-section-arrival .ro-arrival__directions { transition: none; }
  .ro-section-arrival .ro-arrival__play { transition: none; }
  .ro-section-arrival .ro-arrival__parking-link { transition: none; transform: none; }
  .ro-section-arrival .ro-arrival__parking-text a { transition: none; }
}

/* ============================================================
   CONTENT DIVIDER (issue #84)
============================================================ */
.ro-divider {
  --divider-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 14'%3E%3Cpath d='M4 8c21-8 35 6 56-2' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
  display: block;
  width: 64px;
  height: 14px;
  margin: 32px auto;
  background-color: var(--ro-primary);
  -webkit-mask-image: var(--divider-mask);
  mask-image: var(--divider-mask);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

/* ============================================================
   MAINTENANCE PATH (Q-3, v3.89.0)
   Wayfinding, not editorial: which appointment maintains this service,
   and what this appointment maintains. Renders on at most 3 of the 33
   pages the shared single template serves — everywhere else the renderer
   returns '' and none of this applies.
   Single column on purpose, so it is deliberately NOT in the R3 container
   -query context list above (that list is for the three two-column
   sections; an unneeded context is a silent cross-section match).
   ============================================================ */
.ro-section-maintenance-path .wrap {
  /* R2–R4 trap: `ch` resolves against the ELEMENT'S OWN font, so the
     measure cap and the prose size have to sit on the same wrapper or the
     cap silently clips at the inherited 16px. */
  font-size: var(--ro-fs-prose);
}
.ro-maintenance-path__group + .ro-maintenance-path__group {
  margin-top: var(--ro-stack-md);
}
h2.ro-maintenance-path__heading {
  font-family: var(--ro-font-serif);
  font-weight: 700;
  font-size: var(--ro-fs-h4);
  line-height: 1.35;
  letter-spacing: -.005em;
  color: var(--ro-muted-fg);
  margin: 0 0 var(--ro-stack-xs);
}
.ro-maintenance-path__list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: var(--ro-measure);
  display: flex;
  flex-direction: column;
  gap: var(--ro-stack-xs);
}
/* Self-doubled to (0,2,0) base / (0,3,0) interactive — the standing hostile-
   hover rule (section-library.md): Hello's `a{color:#c36}` and the Kit's
   `.elementor-kit-15 a:hover{color:...}` (0,2,1) both hijack a plain <a>, so
   `color` is re-asserted on hover AND focus-visible above their specificity. */
.ro-maintenance-path__link.ro-maintenance-path__link {
  display: inline-block;
  /* 44px touch target comes from padding + line-height, not a fixed height, so
     a two-line title grows instead of clipping. */
  padding: 10px 14px;
  border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-control);
  background: var(--ro-surface);
  color: var(--ro-foreground);
  font-weight: var(--ro-fw-semibold);
  line-height: 1.5;
  text-decoration: none;
  transition: transform var(--ro-dur) var(--ro-ease), opacity var(--ro-dur) var(--ro-ease);
}
.ro-maintenance-path__link.ro-maintenance-path__link:hover {
  color: var(--ro-foreground);
  background: var(--ro-surface);
  border-color: rgb(var(--ro-rgb-primary) / 0.55);
  transform: translateY(-2px);
}
.ro-maintenance-path__link.ro-maintenance-path__link:active {
  color: var(--ro-foreground);
  transform: translateY(0);
  opacity: .85;
}
.ro-maintenance-path__link.ro-maintenance-path__link:focus-visible {
  color: var(--ro-foreground);
  background: var(--ro-surface);
  outline: 2px solid rgb(var(--ro-rgb-ring));
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .ro-maintenance-path__link.ro-maintenance-path__link {
    transition: none;
  }
  .ro-maintenance-path__link.ro-maintenance-path__link:hover,
  .ro-maintenance-path__link.ro-maintenance-path__link:active {
    transform: none;
  }
}

/* ============================================================
   SERVICE DETAIL (issue #36)
   ============================================================ */
/* R4: below the threshold the card DISSOLVES into the reading column.
   A card is a promise that its contents are one perceivable object; this
   one measured 3010px on a 390x844 phone — 3.6 viewports — so the promise
   was false and the border, shadow, radius and 44px horizontal padding
   were chrome with no affordance, spending 35% of the screen. Grouping is
   carried by the heading and the rhythm instead, plus one rule between the
   two blocks when both are present. The bounded card returns at the wide
   state, where the promise is true again.
   `position: relative` is retained deliberately: it is the containing
   block the two columns' absolutely positioned step markers and connector
   lines resolve against. */
.ro-service-detail-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ro-stack-lg);
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  position: relative;
  /* Owner decision Q1: while dissolved, this is an editorial column and it
     is centred in its canvas — text inside stays left-aligned. `+ 48px` is
     the numbered-step marker gutter, so the text column still reaches the
     full measure rather than losing 48px of it. `font-size` is the same
     `ch`-basis fix documented on .ro-reading-content .ro-prose above.
     Both are undone in the wide state, where the card is the full canvas. */
  font-size: var(--ro-fs-prose);
  max-width: calc(var(--ro-measure) + 48px);
  margin-inline: auto;
}
.ro-service-detail-grid.has-description.has-procedure .ro-service-procedure {
  padding-top: var(--ro-stack-lg);
  border-top: 1px solid var(--ro-border);
}

/* Threshold 880px of CONTAINER width — around 928px of viewport, later than
   the 901px viewport breakpoint this replaces, which is the point: at 901px
   the old right-hand column held 37 real characters, so the tablet band read
   worse than the phone did.
   Columns are 1fr 1fr, not the 1.15fr / 0.85fr they were. Two reasons, both
   measured: (1) the left column's prose is now capped by --ro-measure at
   527px on a 1425px viewport, so the extra 72px that 1.15fr handed it was
   width nothing could use, while the right column's numbered list — the
   narrowest text surface here, indented 48px by its own step marker — was
   the one starved; (2) equal columns are what let the threshold stay at the
   derived 880: at 1.15/0.85 the >= 45-character floor on that list does not
   clear until roughly 1020px of container. Measured at 1425: both columns
   521px, description 65 real characters, procedure 65, steps 60 — all inside
   the 45-75 band. */
@container ro-sd (min-width: 880px) {
  .ro-service-detail-grid {
    /* the card IS the canvas here — the editorial-column cap and its
       centring belong to the dissolved state only (Owner decision Q1) */
    max-width: none;
    margin-inline: 0;
  }
  .ro-service-detail-grid.has-description.has-procedure {
    background: var(--ro-surface);
    border: 1px solid var(--ro-border);
    border-radius: var(--ro-radius-card);
    box-shadow: var(--ro-shadow-card);
    padding: var(--ro-pad-card);
    grid-template-columns: 1fr 1fr;
  }
  .ro-service-detail-grid.has-description.has-procedure .ro-service-procedure {
    padding-top: 0;
    border-top: 0;
  }

  /* `.ro-prose` is carried for SPECIFICITY, not styling: the 780px collapse at
     "Single Column Layout Collapse" below has the identical selector and prints
     LATER, so an equal-specificity rule here loses on order. Its `margin: 0 auto`
     is the load-bearing half — an auto-margined grid item stops stretching and is
     sized to fit-content, which centres the column off the page grid (measured
     x=369.1 against a 144px content edge). The class is hardcoded beside
     .ro-service-description in section-service-detail.php:72. */
  .ro-service-detail-grid:not(.has-procedure) .ro-service-description.ro-prose {
    max-width: var(--ro-measure);
    margin-inline: 0;
  }
  /* The SIZE override that used to sit here is retired (D2: the same heading
     rendered 36px or 32px depending on whether a SIBLING field was filled).
     The wide-state margin is NOT part of that defect and stays: a section head
     over a full-width editorial column needs more air under it than one over a
     half-width card column. */
  .ro-service-detail-grid:not(.has-procedure) .ro-service-description > h2 {
    margin-bottom: var(--ro-stack-md);
  }
}

/* Description Column (Left) */
.ro-service-description {
  min-width: 0;
}
.ro-service-description h2 {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h2);
  line-height: 1.2;
  letter-spacing: -.01em;
  margin-bottom: var(--ro-stack-xs);
  color: var(--ro-foreground);
}
.ro-service-description p {
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-prose);
  font-weight: var(--ro-fw-body);
  line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure);
  margin-bottom: var(--ro-stack-sm);
}
.ro-service-description strong {
  color: var(--ro-foreground);
  font-weight: var(--ro-fw-semibold);
}
.ro-service-description ul {
  list-style: none;
  padding-left: 0;
  margin-top: var(--ro-stack-sm);
}
.ro-service-description li {
  position: relative;
  padding-left: 24px;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-prose);
  font-weight: var(--ro-fw-body);
  line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure-tight);
  margin-bottom: var(--ro-stack-sm);
}
.ro-service-description li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 7px;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 5px 0 5px 8px;
  border-color: transparent transparent transparent var(--ro-secondary-strong);
}

/* Procedure Column (Right) */
.ro-service-procedure {
  min-width: 0;
}
.ro-service-procedure h2 {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h2);
  line-height: 1.2;
  margin-bottom: var(--ro-stack-sm);
  color: var(--ro-foreground);
}
.ro-service-procedure h3 {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h3);
  line-height: 1.3;
  margin-bottom: var(--ro-stack-sm);
  color: var(--ro-foreground);
}
.ro-service-procedure > p {
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-prose);
  font-weight: var(--ro-fw-body);
  line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure);
  margin-bottom: var(--ro-stack-md);
}
.ro-service-procedure strong { color: var(--ro-foreground); font-weight: var(--ro-fw-semibold); }
.ro-service-procedure ul {
  list-style: none;
  padding-left: 0;
  margin: 0 0 var(--ro-stack-md);
  counter-reset: step-counter;
  position: relative;
}
.ro-service-procedure li {
  position: relative;
  padding-left: 48px;
  margin-bottom: var(--ro-stack-md);
  counter-increment: step-counter;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-prose);
  font-weight: var(--ro-fw-body);
  line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure-tight);
}
.ro-service-procedure li:last-child {
  margin-bottom: 0;
}
.ro-service-procedure li::before {
  content: counter(step-counter);
  position: absolute;
  left: 0;
  top: -2px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgb(var(--ro-rgb-primary) / 0.12);
  color: var(--ro-primary-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--ro-font-sans);
  font-weight: 800;
  font-size: var(--ro-fs-meta);
  z-index: 2;
}
.ro-service-procedure li:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 14px;
  top: 26px;
  bottom: calc(-1 * var(--ro-stack-md));
  width: 1px;
  background: var(--ro-border);
  z-index: 1;
}

/* Single Column Layout Collapse (when one of the fields is missing).
   Below the ro-sd threshold this is the dissolved editorial column. Above
   it, the description-only case is released to the page grid and receives
   the token measure in the container query above. This remains the base
   fail-safe for a description whose heading has been emptied. */
.ro-service-detail-grid:not(.has-procedure) .ro-service-description {
  max-width: 780px;
  margin: 0 auto;
}
.ro-service-detail-grid:not(.has-description) .ro-service-procedure {
  max-width: 780px;
  margin: 0 auto;
}

/* ============================================================
   W5 EDITORIAL READING SYSTEM
   One visual language for Service Detail plus Reading Content. The component
   classes remain renderer-specific: this is a grouped presentation layer, not
   a framework abstraction. The media role is always explicit in PHP; empty
   and invalid fields stay text-only rather than reserving a blank figure.
   ============================================================ */
.ro-reading-content--text-only .ro-prose {
  min-height: 0;
  padding-inline-start: var(--ro-pad-inset);
  border-inline-start: 2px solid var(--ro-primary);
}
/* Editorial width (Owner Option B, v3.206.0): one centred column, text still
   left-aligned. Scoped BY CONSTRUCTION: the renderer emits .rc-layout only
   when a photo resolved, so a .ro-prose that is a DIRECT child of .wrap is
   text-only - plain Pages and --text-only services. A photo => .rc-layout =>
   not matched, media compositions keep their own rules. (0,3,0) beats the R4
   base and the @container ro-rc reset at every width, so this supersedes
   R7's "shared content edge" for text-only Reading Content only. Children
   are released to the column so p/ul/ol/li share one right edge; the tie
   with .ro-callout.ro-callout p (0,3,1) is won by print order, on purpose.
   A-2 trade-off: see --ro-measure-editorial in tokens.css. */
.ro-reading-content .wrap > .ro-prose {
  max-width: min(100%, var(--ro-measure-editorial));
  margin-inline: auto;
}
.ro-reading-content .wrap > .ro-prose :is(p, ul, ol, li) { max-width: none; }
.ro-service-detail-grid:not(.has-overview-image) .ro-service-description {
  min-height: 0;
  padding-inline-start: var(--ro-pad-inset);
  border-inline-start: 2px solid var(--ro-primary);
}

.ro-reading-content--media .rc-figure,
.ro-service-detail-grid.has-overview-image .ro-service-detail__figure {
  overflow: hidden;
  border-radius: 2px 2px 20px 2px;
  background: var(--ro-primary);
  box-shadow: 8px 8px 0 var(--ro-primary);
}
.ro-reading-content--media .rc-layout--landscape .rc-figure img,
.ro-service-detail-grid.has-overview-image .ro-service-detail__figure img {
  width: 100%;
  height: 100%;
  aspect-ratio: 5 / 4;
  object-fit: cover;
  object-position: center;
}

.ro-service-detail-grid.has-overview-image {
  max-width: none;
  margin-inline: 0;
  gap: var(--ro-stack-lg);
}
.ro-service-detail-grid.has-overview-image .ro-service-detail__copy {
  min-width: 0;
  max-width: var(--ro-measure);
}
.ro-service-detail-grid.has-overview-image .ro-service-procedure {
  margin-top: var(--ro-stack-lg);
  padding-top: var(--ro-stack-md);
  border-top: 1px solid var(--ro-border);
}
.ro-service-detail-grid.has-overview-image .ro-service-detail__figure {
  width: 100%;
  max-width: 540px;
  margin: 0;
  aspect-ratio: 5 / 4;
}

@container ro-rc (min-width: 880px) {
  .ro-reading-content--media .rc-layout--landscape {
    display: grid;
    grid-template-columns: minmax(0, var(--ro-measure)) minmax(320px, 540px);
    gap: 56px;
    align-items: start;
    max-width: calc(var(--ro-measure) + 540px + 56px);
    margin-inline: auto;
  }
  .ro-reading-content--media .rc-layout--block-2 {
    grid-template-columns: minmax(320px, 540px) minmax(0, var(--ro-measure));
  }
  .ro-reading-content--media .rc-layout--portrait {
    grid-template-columns: minmax(0, var(--ro-measure)) minmax(320px, 540px);
    gap: 56px;
    max-width: calc(var(--ro-measure) + 540px + 56px);
    margin-inline: auto;
  }
  .ro-reading-content--media .rc-layout--landscape .ro-prose,
  .ro-reading-content--media .rc-layout--landscape .rc-figure {
    margin-inline: 0;
  }
  .ro-reading-content--media .rc-layout--landscape .rc-figure {
    width: 100%;
    max-width: 540px;
    justify-self: start;
  }
  .ro-reading-content--media .rc-layout--portrait .rc-figure {
    width: 100%;
    max-width: 540px;
    justify-self: start;
  }
  .ro-reading-content--media .rc-layout--block-2 .ro-prose {
    grid-column: 2;
    grid-row: 1;
    justify-self: start;
  }
  .ro-reading-content--media .rc-layout--block-2 .rc-figure {
    grid-column: 1;
    grid-row: 1;
    justify-self: start;
    border-radius: 2px 2px 2px 20px;
    box-shadow: -8px 8px 0 var(--ro-primary);
  }
}

@container ro-sd (min-width: 880px) {
  .ro-service-detail-grid.has-overview-image {
    display: grid;
    grid-template-columns: minmax(0, var(--ro-measure)) minmax(320px, 540px);
    gap: 56px;
    align-items: start;
    max-width: none;
    margin-inline: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }
  /* Beats the older four-class two-column card selector: an overview is an
     editorial spread, not a third child squeezed into the procedure card. */
  .ro-service-detail-grid.has-description.has-procedure.has-overview-image {
    grid-template-columns: minmax(0, var(--ro-measure)) minmax(320px, 540px);
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }
  .ro-service-detail-grid.has-description.has-procedure.has-overview-image .ro-service-procedure {
    padding-top: var(--ro-stack-md);
    border-top: 1px solid var(--ro-border);
  }
  .ro-service-detail-grid.has-description.has-procedure:not(.has-overview-image) {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }
  .ro-service-detail-grid.has-overview-image .ro-service-detail__figure {
    justify-self: start;
  }
}



/* ============================================================
   WORK SINGLE (/works/<slug>/) — issue #60, F_3.30.0; product-page layout v3.189.0
   Composition follows the Owner's Battle.net product-page reference (measured live 2026-10-10:
   1fr | 365px (418px from 1400), 48px gap, both columns sticky + start-aligned, vertical 100px
   thumb rail left of the stage). All blocks hide-when-empty (renderer-gated).
============================================================ */
/* Shared width rule above keeps the single aligned with the archive. */

/* Column geometry, the single source: the Style Showcase page (.ro-style-guide) puts its editorial
   blocks on the same main column with these two properties (STYLE SHOWCASE block). */
.ro-work-single,
.ro-style-guide { --ro-ws-rail: 365px; --ro-ws-gap: 48px; }
@media (min-width: 1400px) {
  .ro-work-single,
  .ro-style-guide { --ro-ws-rail: 418px; }
}
.ro-work-single .ws-top { display: flex; flex-direction: column; gap: 28px; }
.ro-work-single .ws-main,
.ro-work-single .ws-rail { display: contents; }
.ro-work-single .ws-media { order: 0; min-width: 0; container: ws-gallery / inline-size; }
.ro-work-single .ws-buy { order: 1; }
.ro-work-single .ws-content { order: 2; }
.ro-work-single .ws-guide { order: 3; }

/* Sticky pin line = the sticky .ro-header (117px, condensed 64px once scrolled) + 24px. sections.js
   writes --ws-col-top per column from measured heights: min(header + 24, viewport - column - 24), so a
   column taller than the viewport pins by its bottom instead of hiding it. 88px (64 + 24) is the
   no-JS fallback. Below 960px the columns dissolve and the four blocks stack in reference order. */
@media (min-width: 960px) {
  .ro-work-single .ws-top {
    display: grid; grid-template-columns: minmax(0, 1fr) var(--ro-ws-rail); column-gap: var(--ro-ws-gap); align-items: start;
  }
  .ro-work-single .ws-main,
  .ro-work-single .ws-rail { position: sticky; top: var(--ws-col-top, 88px); align-self: start; min-width: 0; }
  .ro-work-single .ws-main { display: flex; flex-direction: column; gap: 32px; container: ws-main / inline-size; }
  .ro-work-single .ws-rail { display: flex; flex-direction: column; gap: 16px; }
}

/* media viewer */
.ro-work-single .ws-gallery {
  display: grid; grid-template-columns: 100px minmax(0, 1fr);
  grid-template-areas: "thumbs stage"; column-gap: 8px;
}
.ro-work-single .ws-gallery--one {
  grid-template-columns: minmax(0, 1fr); grid-template-areas: "stage";
}
/* 112px = condensed header 64px + 24px above and below. This constant must not use
   --ws-col-top, which depends on column height; inline-size keeps the stage filling its track. */
.ro-work-single .ws-stage {
  grid-area: stage; position: relative; overflow: hidden; aspect-ratio: 5 / 4;
  inline-size: 100%; max-inline-size: calc((100svh - 112px) * 1.25); justify-self: start;
  border-radius: var(--ro-radius-card); background: var(--ro-surface-2);
  border: 1px solid var(--ro-border); box-shadow: var(--ro-shadow-card);
}
.ro-work-single .ws-slides { display: flex; height: 100%; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
.ro-work-single .ws-slides::-webkit-scrollbar { display: none; }
.ro-work-single .ws-slide { flex: 0 0 100%; scroll-snap-align: center; position: relative; height: 100%; overflow: hidden; }
.ro-work-single .ws-slide img,
.ro-work-single .ws-slide video {
  position: relative; z-index: 1; width: 100%; height: 100%; display: block; object-fit: cover;
  /* A mouse drag on the stage scrolls it (sections.js); image drag and text selection would compete. */
  -webkit-user-drag: none; user-select: none;
}
.ro-work-single .ws-slide--contain img,
.ro-work-single .ws-slide--contain video { object-fit: contain; }
.ro-work-single .ws-slide--contain::before {
  content: ""; position: absolute; z-index: 0; inset: -24px;
  background: var(--ws-bg, none) center / cover no-repeat;
  filter: blur(24px) saturate(1.1); opacity: .55; transform: scale(1.06);
}
.ro-work-single .ws-slide--contain::after {
  content: ""; position: absolute; z-index: 0; inset: 0; background: rgb(var(--ro-rgb-surface) / .35);
}
/* Mouse drag (v3.160.0). Touch keeps native snap scrolling and vertical page panning. */
@media (hover: hover) and (pointer: fine) {
  .ro-work-single .ws-slides { cursor: grab; }
}
.ro-work-single .ws-slides.is-dragging,
.ro-work-single .ws-thumbs.is-dragging { cursor: grabbing; user-select: none; }
.ro-work-single .ws-slides.is-dragging,
.ro-work-single .ws-slides.is-settling { scroll-snap-type: none; }

/* Counter stays centred on the 5:4 media region; expand owns its bottom-right band. */
.ro-work-single .ws-counter {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 2;
  padding: 5px 12px; border-radius: 999px; background: rgb(var(--ro-rgb-sidebar) / .78);
  color: #fff; font-size: var(--ro-fs-ui-micro); font-weight: 700; letter-spacing: .04em;
  font-variant-numeric: tabular-nums; white-space: nowrap; pointer-events: none; backdrop-filter: blur(6px);
}
/* Arrows stay centred on the stage. Keep glass colours explicit: Hello paints [type=button]:hover. */
.ro-work-single .ws-nav {
  position: absolute; top: 50%; z-index: 2; width: 44px; height: 44px; margin-top: -22px; padding: 0;
  border: none; border-radius: 50%; cursor: pointer;
  background: rgb(var(--ro-rgb-surface) / .92); color: var(--ro-foreground);
  display: inline-flex; align-items: center; justify-content: center; box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), background var(--ro-dur) var(--ro-ease),
    opacity var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-nav--prev { left: 12px; }
.ro-work-single .ws-nav--next { right: 12px; }
.ro-work-single .ws-nav svg { width: 20px; height: 20px; }
.ro-work-single .ws-nav:hover,
.ro-work-single .ws-nav:focus {
  background: var(--ro-surface); color: var(--ro-foreground); box-shadow: var(--ro-shadow-card-hover);
}
.ro-work-single .ws-nav:focus-visible,
.ro-work-single .ws-expand:focus-visible,
.ro-work-single .ws-play:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; }
.ro-work-single .ws-nav:active { transform: scale(.94); }
.ro-work-single .ws-nav:disabled { opacity: .38; cursor: default; box-shadow: none; pointer-events: none; }
@media (hover: hover) and (pointer: fine) {
  .ro-work-single .ws-nav { opacity: 0; }
  .ro-work-single .ws-nav:disabled { opacity: 0; }
  .ro-work-single .ws-stage:hover .ws-nav,
  .ro-work-single .ws-stage:focus-within .ws-nav { opacity: 1; }
  .ro-work-single .ws-stage:hover .ws-nav:disabled,
  .ro-work-single .ws-stage:focus-within .ws-nav:disabled { opacity: .38; }
}
.ro-work-single .ws-play {
  position: absolute; left: 50%; top: 50%; z-index: 2; width: 60px; height: 60px; margin: -30px 0 0 -30px;
  padding: 0; border: none; border-radius: 50%; cursor: pointer;
  background: rgb(var(--ro-rgb-sidebar) / .62); color: #fff; backdrop-filter: blur(6px);
  display: inline-flex; align-items: center; justify-content: center;
  transition: opacity var(--ro-dur) var(--ro-ease), background var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-play svg { width: 26px; height: 26px; margin-left: 3px; }
.ro-work-single .ws-play:hover,
.ro-work-single .ws-play:focus { background: rgb(var(--ro-rgb-sidebar) / .82); color: #fff; }
.ro-work-single .ws-play:active { transform: scale(.94); }
.ro-work-single .ws-slide.is-playing .ws-play { opacity: 0; pointer-events: none; }
.ro-work-single .ws-slide.is-playing .ws-play:focus-visible { opacity: 1; }
.ro-work-single .ws-expand {
  position: absolute; right: 12px; bottom: 12px; z-index: 2; width: 40px; height: 40px;
  border: none; border-radius: var(--ro-radius-control); cursor: pointer;
  background: rgb(var(--ro-rgb-surface) / .92); color: var(--ro-foreground);
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--ro-shadow-card); transition: box-shadow var(--ro-dur) var(--ro-ease), background var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-expand svg { width: 18px; height: 18px; }
.ro-work-single .ws-expand:hover { box-shadow: var(--ro-shadow-card-hover); background: var(--ro-surface); }
.ro-work-single .ws-expand:active { transform: scale(.94); }

/* The rail scrolls inside the stage-height grid row, so ten photos never grow the gallery. Edge fades
   are 44px on both axes, kept in step with RAIL_FADE (52) in sections.js, which parks the active thumb
   clear of them. */
.ro-work-single .ws-thumbs {
  grid-area: thumbs; position: relative; height: 0; min-height: 100%; padding: 2px;
  overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 8px;
  scrollbar-width: none; overscroll-behavior: contain;
}
.ro-work-single .ws-thumbs::-webkit-scrollbar { display: none; }
.ro-work-single .ws-thumbs.has-more-start {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 44px, #000 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 44px, #000 100%);
}
.ro-work-single .ws-thumbs.has-more-end {
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 44px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 44px), transparent 100%);
}
.ro-work-single .ws-thumbs.has-more-start.has-more-end {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
}
.ro-work-single .ws-thumb {
  position: relative; flex: 0 0 auto; width: 100%; aspect-ratio: 5 / 4; border-radius: 8px; overflow: hidden;
  padding: 0; border: 2px solid transparent; background: none; opacity: .6; cursor: pointer;
  transition: opacity var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-thumb:hover,
.ro-work-single .ws-thumb:focus { opacity: .85; background: none; }
.ro-work-single .ws-thumb.is-active,
.ro-work-single .ws-thumb.is-active:hover,
.ro-work-single .ws-thumb.is-active:focus { opacity: 1; border-color: var(--ro-primary-strong); }
.ro-work-single .ws-thumb:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: -2px;
}
.ro-work-single .ws-thumb__play {
  position: absolute; right: 5px; bottom: 5px; width: 20px; height: 20px; border-radius: 50%;
  background: rgb(var(--ro-rgb-sidebar) / .78); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
}
.ro-work-single .ws-thumb__play svg { width: 10px; height: 10px; margin-left: 1px; }
.ro-work-single .ws-thumb:active { transform: scale(.94); }
.ro-work-single .ws-thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block; -webkit-user-drag: none;
}
@container ws-gallery (max-width: 559px) {
  .ro-work-single .ws-gallery {
    grid-template-columns: minmax(0, 1fr); grid-template-areas: "stage" "thumbs"; row-gap: 10px;
  }
  .ro-work-single .ws-thumbs {
    height: auto; min-height: 0; flex-direction: row; overflow-x: auto; overflow-y: hidden;
    overscroll-behavior-x: contain; max-inline-size: calc((100svh - 112px) * 1.25);
  }
  .ro-work-single .ws-thumb { width: 88px; }
  .ro-work-single .ws-thumbs.has-more-start {
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 100%);
  }
  .ro-work-single .ws-thumbs.has-more-end {
    -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 44px), transparent 100%);
    mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 44px), transparent 100%);
  }
  .ro-work-single .ws-thumbs.has-more-start.has-more-end {
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
  }
}

/* Purchase card */
.ro-work-single .ws-buy {
  background: var(--ro-surface); border: 1px solid var(--ro-border);
  border-radius: var(--ro-radius-card); box-shadow: var(--ro-shadow-card); padding: 24px;
}
.ro-work-single .ws-eyebrow {
  font-size: var(--ro-fs-ui-micro); font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ro-primary-strong); margin-bottom: 8px;
}
.ro-work-single h1.ws-title {
  font-family: var(--ro-font-serif); font-weight: 900; font-size: var(--ro-fs-h1); line-height: 1.15;
  letter-spacing: -.01em; margin: 0 0 12px; overflow-wrap: break-word;
}
/* In the 365/418px purchase column the H1 takes the h2 size step (the tag and its rank in the
   document are unchanged): at h1 size a typical look title broke into four or five lines. */
@media (min-width: 960px) {
  .ro-work-single h1.ws-title { font-size: var(--ro-fs-h2); }
}
/* Service chip (#225 §1.3): the H1 is Work-specific now, so this is the only
   service signal above the fold. It must render whenever a service resolves.

   Its own class, deliberately NOT .ws-chip. The taxonomy BADGE that used to own
   .ro-work-single .ws-chip — an <a> inside .ws-tax with :hover and
   :active { transform: scale(.97) } — is gone with the Style-tags section (#223
   S5d), but the reason this class exists is not: same selector later in the file
   won every conflicting property here AND handed this static <div> a button's
   press affordance. Static by contract: no hover state, no active state, no
   transition, no shadow. Do not add one, and do not rename this to .ws-chip. */
.ro-work-single .ws-service-chip {
  display: inline-flex; align-items: center; margin: 0 0 14px; padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--ro-border); background: var(--ro-surface-2); color: var(--ro-muted-fg);
  font-size: var(--ro-fs-meta); font-weight: 600; letter-spacing: .01em;
}

/* Receipt */
.ro-work-single .ws-rcpt {
  margin: 18px 0 16px; padding: 14px 16px 14px 18px; border-radius: 12px;
  background: var(--ro-surface-2); border: 1px solid var(--ro-border); position: relative;
}
.ro-work-single .ws-rcpt::before {
  content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 4px;
  border-radius: 0 4px 4px 0; background: var(--ro-primary-strong);
}
.ro-work-single .ws-rcpt-h {
  font-size: var(--ro-fs-ui-micro); font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ro-muted-fg); margin-bottom: 12px;
}
.ro-work-single .ws-rcpt-row { display: flex; align-items: baseline; gap: 10px; padding: 9px 0; border-bottom: 1px dashed var(--ro-border); }
.ro-work-single .ws-rcpt-row .nm { flex: 1; min-width: 0; }
.ro-work-single .ws-rcpt-row .nm .t { font-size: var(--ro-fs-ui); font-weight: 600; }
.ro-work-single .ws-rcpt-row .nm .t a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; transition: border-color var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease); }
.ro-work-single .ws-rcpt-row .nm .t a:hover { color: var(--ro-primary-strong); border-bottom-color: rgb(var(--ro-rgb-primary) / .4); }
.ro-work-single .ws-rcpt-row .nm .d { font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); }
.ro-work-single .ws-rcpt-row .pr { font-size: var(--ro-fs-ui); font-weight: 700; white-space: nowrap; min-width: 46px; text-align: right; }
.ro-work-single .ws-rcpt-row .pr .was { display: block; font-size: var(--ro-fs-meta); font-weight: 500; color: var(--ro-muted-fg); text-decoration: line-through; }
.ro-work-single .ws-rcpt-tag { font-size: 10px; /* receipt row geometry: 1px vertical padding */ font-weight: 800; padding: 1px 6px; border-radius: 999px; background: rgb(var(--ro-rgb-success) / .16); color: var(--ro-success-strong); margin-left: 6px; }
.ro-work-single .ws-rcpt-total { display: flex; align-items: baseline; justify-content: space-between; padding-top: 14px; margin-top: 2px; }
.ro-work-single .ws-rcpt-total .lbl { font-size: var(--ro-fs-ui); font-weight: 700; }
.ro-work-single .ws-rcpt-total .lbl a { color: inherit; text-decoration: none; }
.ro-work-single .ws-rcpt-total .lbl a:hover { color: var(--ro-primary-strong); }
.ro-work-single .ws-rcpt-total .lbl small { display: block; font-size: var(--ro-fs-meta); font-weight: 500; color: var(--ro-muted-fg); }
.ro-work-single .ws-rcpt-total .big { font-size: 30px; font-weight: 800; color: var(--ro-primary-strong); }
.ro-work-single .ws-rcpt-as { margin: 10px 0 0; font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); line-height: 1.5; }
.ro-work-single .ws-rcpt-as a { color: var(--ro-primary-strong); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; transition: color var(--ro-dur) var(--ro-ease); }
.ro-work-single .ws-rcpt-as a:hover { color: var(--ro-foreground); }

.ro-work-single .ws-book {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  padding: 15px 20px; border: none; border-radius: var(--ro-radius-control); cursor: pointer;
  background: linear-gradient(135deg, var(--ro-primary), var(--ro-primary-strong));
  color: #fff; font-size: var(--ro-fs-ui); font-weight: 800; font-family: var(--ro-font-sans);
  box-shadow: var(--ro-shadow-btn); transition: background var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease), box-shadow var(--ro-dur) var(--ro-ease), filter var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-book:hover { box-shadow: var(--ro-shadow-btn-hover); filter: brightness(1.03); }
.ro-work-single .ws-book.is-booked,
.ro-work-single .ws-book[aria-pressed="true"] {
  color: var(--ro-foreground); background: var(--ro-surface-2);
  border: 1px solid var(--ro-border-hover); box-shadow: var(--ro-shadow-card);
}
.ro-work-single .ws-book.is-booked:hover,
.ro-work-single .ws-book[aria-pressed="true"]:hover {
  color: var(--ro-foreground); background: var(--ro-surface);
  border-color: var(--ro-primary); box-shadow: var(--ro-shadow-card-hover); filter: none;
}
.ro-work-single .ws-book:active { transform: scale(.985); }

.ro-work-single .ws-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 10px; }
.ro-work-single .ws-act {
  min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 11px; border: 1px solid var(--ro-border); border-radius: var(--ro-radius-control);
  background: var(--ro-surface-2); color: var(--ro-foreground); font-size: var(--ro-fs-ui-sm); font-weight: 700;
  cursor: pointer; transition: border-color var(--ro-dur) var(--ro-ease), background var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease);
  font-family: var(--ro-font-sans);
}
.ro-work-single .ws-act:hover { border-color: var(--ro-border-hover); background: var(--ro-surface); }
.ro-work-single .ws-act:active { transform: scale(.96); }
.ro-work-single .ws-act[aria-pressed="true"] { color: var(--ro-primary-strong); border-color: var(--ro-border-hover); }
.ro-work-single .ws-act svg { width: 17px; height: 17px; }
.ro-work-single .ws-act.ro-work-like[aria-pressed="true"] path { fill: var(--ro-primary-strong); stroke: var(--ro-primary-strong); }

/* Booking guidance */
.ro-work-single .ws-guide {
  padding: 18px 20px; border-radius: var(--ro-radius-card);
  background: var(--ro-surface-2); border: 1px solid var(--ro-border);
}
.ro-work-single .ws-guide__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.ro-work-single .ws-guide__list li {
  display: flex; gap: 10px; font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); line-height: 1.5;
}
.ro-work-single .ws-guide__list svg { width: 16px; height: 16px; color: var(--ro-secondary-strong); flex: none; margin-top: 2px; }
/* Owner override (2026-10-10): description uses the full left column like the reference.
   This surface deliberately exceeds the ARCHI measure rule. */
.ro-work-single .ws-content .ws-lede {
  font-size: var(--ro-fs-lead); line-height: 1.6; color: var(--ro-foreground);
  font-weight: var(--ro-fw-semibold); max-width: none; margin: 0 0 8px;
}
.ro-work-single .ws-content .ws-section { margin-top: 28px; min-width: 0; }
.ro-work-single .ws-content .ro-prose { font-size: var(--ro-fs-prose); max-width: none; }
.ro-work-single .ws-content .ro-prose p { max-width: none; }
.ro-work-single .ws-content .ro-prose p:last-child { margin-bottom: 0; }
.ro-work-single .ws-content .ro-prose strong { color: var(--ro-foreground); font-weight: 700; }
.ro-work-single .ws-breadcrumbs { min-width: 0; margin-block-end: var(--ro-stack-sm); font-family: var(--ro-font-sans); }
/* Reserve the sticky edge fade so it never masks the final crumb. */
.ro-work-single .ws-breadcrumbs .hero-crumbs__pill { padding-inline-end: 38px; }
.ro-work-single .ws-breadcrumbs p,
.ro-work-single .ws-breadcrumbs span { display: inline; margin: 0; padding: 0; }
.ro-work-single .ws-breadcrumbs a {
  color: var(--ro-primary-text);
  line-height: 1.6;
  text-underline-offset: 2px;
  transition: color var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-breadcrumbs a:hover,
.ro-work-single .ws-breadcrumbs a:focus-visible { color: var(--ro-foreground); background: transparent; }
.ro-work-single .ws-breadcrumbs a:focus-visible { outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px; border-radius: 4px; }
.ro-work-single .ws-breadcrumbs [aria-current="page"],
.ro-work-single .ws-breadcrumbs .breadcrumb_last { color: var(--ro-muted-fg); }
@media (min-width: 960px) {
  .ro-work-single .ws-breadcrumbs { margin-block-end: var(--ro-stack-md); }
}
.ro-work-single .ws-content .ws-section--technique .ro-callout {
  max-width: none; font-size: var(--ro-fs-prose);
}
.ro-work-single h2.ws-h { font-family: var(--ro-font-serif); font-weight: 900; font-size: var(--ro-fs-h3); line-height: 1.3; margin-bottom: 18px; }
.ro-work-single > .ws-section { margin-top: 44px; }

@media (max-width: 959px) {
  .ro-work-single .ws-buy { padding: 20px; }
}
@media (max-width: 559px) {
  .ro-work-single .ws-buy,
  .ro-work-single .ws-guide { margin-inline: -24px; border-radius: 0; border-inline: 0; }
}
/* related works */
.ro-work-single .ws-related { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
@media (min-width: 720px) { .ro-work-single .ws-related { grid-template-columns: repeat(4, 1fr); } }
.ro-work-single .ws-rcard {
  display: block; border-radius: var(--ro-radius-card); overflow: hidden; text-decoration: none;
  background: var(--ro-surface); border: 1px solid var(--ro-border); box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-rcard:hover { box-shadow: var(--ro-shadow-card-hover); border-color: var(--ro-border-hover); }
.ro-work-single .ws-rcard:active { transform: scale(.985); }
.ro-work-single .ws-rcard .thumb { aspect-ratio: 4 / 5; overflow: hidden; }
.ro-work-single .ws-rcard img { width: 100%; height: 100%; object-fit: cover; }
.ro-work-single .ws-rcard .cap { padding: 12px 14px; }
.ro-work-single .ws-rcard .cap .n { font-size: var(--ro-fs-ui); font-weight: 700; color: var(--ro-foreground); }
.ro-work-single .ws-rcard .cap .m { font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); margin-top: 2px; }
/* No-image rows retain .ws-rcard, so border/radius/shadow/hover/active behavior stays shared;
   the caption becomes the deliberate text tile instead of leaving an empty thumb frame.
   The ratio is a FLOOR, not a fixed size, and that distinction is measured: aspect-ratio on the
   card gives the grid item a DEFINITE cross-size, which suppresses the default stretch, so the
   text tile came out 43px shorter than its image siblings at every width (measured 2026-08-27).
   A zero-width ::before carrying padding-top: 125% (= 4 / 5) contributes CONTENT height instead:
   an all-text row still gets the ratio, and in a mixed row stretch wins and the heights match. */
.ro-work-single .ws-rcard--noimg { display: flex; }
.ro-work-single .ws-rcard--noimg::before { content: ""; width: 0; padding-top: 125%; }
.ro-work-single .ws-rcard--noimg .cap {
  flex: 1; display: flex; flex-direction: column; justify-content: center;
}

/* Page-level Work axis. It is independent of the viewer's hidden-on-single controls. */
/* Image-led since v3.160.0: each anchor previews its destination. A lone neighbour (first or last
   Work in the pool) keeps its own column - Previous left, Next right - so position still says
   direction. Below 560px the pair stacks and both read image-first. */
.ro-work-single .ws-looknav {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 40px;
}
.ro-work-single .ws-looknav__link {
  min-width: 0; display: flex; align-items: stretch; overflow: hidden;
  border: 1px solid var(--ro-border); border-radius: var(--ro-radius-card);
  background: var(--ro-surface); color: var(--ro-foreground); box-shadow: var(--ro-shadow-card);
  text-decoration: none;
  transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease),
    background var(--ro-dur) var(--ro-ease), color var(--ro-dur) var(--ro-ease), transform var(--ro-dur) var(--ro-ease);
}
.ro-work-single .ws-looknav__link:hover {
  color: var(--ro-foreground) !important; background: var(--ro-surface);
  border-color: var(--ro-border-hover); box-shadow: var(--ro-shadow-card-hover);
}
.ro-work-single .ws-looknav__link:focus-visible {
  outline: 2px solid rgb(var(--ro-rgb-ring)); outline-offset: 2px;
}
.ro-work-single .ws-looknav__link:active { transform: scale(.985); }
/* The preview keeps the Works portrait ratio; its width is the only responsive dial. */
.ro-work-single .ws-looknav__media {
  flex: 0 0 clamp(84px, 22vw, 120px); aspect-ratio: 4 / 5; overflow: hidden; background: var(--ro-surface-2);
}
.ro-work-single .ws-looknav__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: filter var(--ro-dur) var(--ro-ease);
}
/* Approved hover vocabulary: a vividness lift, never a zoom. */
.ro-work-single .ws-looknav__link:hover .ws-looknav__media img { filter: saturate(1.18) brightness(1.03); }
.ro-work-single .ws-looknav__copy {
  flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 6px;
  padding: 16px 20px;
}
.ro-work-single .ws-looknav__label {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--ro-muted-fg); font-size: var(--ro-fs-ui-micro); font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase;
}
.ro-work-single .ws-looknav__icon { width: 16px; height: 16px; flex: 0 0 auto; color: var(--ro-primary-strong); }
/* Two lines, then clamp: Work titles are authored phrases and a one-line ellipsis cut most of
   them (it measured clipped at every width - RISK-ACCEPTED WS-LOOKNAV-700, retired by this). */
.ro-work-single .ws-looknav__title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  color: var(--ro-foreground); font-family: var(--ro-font-serif); font-size: var(--ro-fs-h4);
  font-weight: 700; line-height: 1.35;
}
@media (min-width: 560px) {
  .ro-work-single .ws-looknav { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
  .ro-work-single .ws-looknav__link--next { grid-column: 2; flex-direction: row-reverse; text-align: right; }
  .ro-work-single .ws-looknav__link--next .ws-looknav__label { justify-content: flex-end; }
}
@media (min-width: 960px) {
  .ro-work-single .ws-main > .ws-looknav { order: 4; margin-top: 0; grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .ro-work-single .ws-main > .ws-looknav .ws-looknav__link--next { grid-column: auto; flex-direction: row; text-align: left; }
  .ro-work-single .ws-main > .ws-looknav .ws-looknav__link--next .ws-looknav__label { justify-content: flex-start; }
}
@container ws-main (min-width: 640px) {
  .ro-work-single .ws-main > .ws-looknav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
  .ro-work-single .ws-main > .ws-looknav .ws-looknav__link--next { grid-column: 2; flex-direction: row-reverse; text-align: right; }
  .ro-work-single .ws-main > .ws-looknav .ws-looknav__link--next .ws-looknav__label { justify-content: flex-end; }
}
/* The related card and the look-nav link are the only two press-scale affordances in this block,
   and scale is the one genuinely MOTION property either of them animates. Covering both in one
   rule keeps them from drifting apart; the shadow/border transitions stay, since colour is not
   motion. */
@media (prefers-reduced-motion: reduce) {
  .ro-work-single .ws-looknav__link,
  .ro-work-single .ws-rcard { transition: box-shadow var(--ro-dur) var(--ro-ease), border-color var(--ro-dur) var(--ro-ease); }
  .ro-work-single .ws-breadcrumbs .hero-crumbs__pill::before,
  .ro-work-single .ws-breadcrumbs .hero-crumbs__pill::after { animation-timing-function: steps(1, end); }
  .ro-work-single .ws-looknav__link:active,
  .ro-work-single .ws-rcard:active { transform: none; }
  /* v3.160.0 viewer controls: colour changes stay. Thumb/arrow fades stop too; opacity is not
     motion by itself, but the reveal is. */
  .ro-work-single .ws-nav:active,
  .ro-work-single .ws-play:active,
  .ro-work-single .ws-thumb:active { transform: none; }
  .ro-work-single .ws-play { transition: none; }
  .ro-work-single .ws-nav { transition: box-shadow var(--ro-dur) var(--ro-ease), background var(--ro-dur) var(--ro-ease); }
  .ro-work-single .ws-thumb { transition: border-color var(--ro-dur) var(--ro-ease); }
}

/* ============================================================
   STYLE SHOWCASE (v3.207.0) — the Work single canvas, columns and gallery reused for a style guide page; only the rail content is new.
============================================================ */
.ro-style-showcase .ss-card { display: flex; flex-direction: column; gap: 14px; }
.ro-style-showcase .ss-card > * { margin: 0; }
.ro-style-showcase h1.hero-title { font-size: var(--ro-fs-h1); }
.ro-style-showcase .hero-desc,
.ro-style-showcase .hero-tagline { max-width: none; }
.ro-style-showcase .hero-ctas { flex-direction: column; align-items: stretch; gap: 10px; margin-top: 4px; }
.ro-style-showcase .hero-ctas .ro-btn { width: 100%; justify-content: center; }
/* Full-width card below the gallery (tablet): two 340px buttons read as a pair, not two bars. */
@media (min-width: 600px) and (max-width: 959px) {
  .ro-style-showcase .hero-ctas { flex-direction: row; }
  .ro-style-showcase .hero-ctas .ro-btn { flex: 1 1 0; width: auto; }
}
/* A contained photo's box is its painted width (stage height x own ratio, centred over the blur), so
   Chrome's sizes="auto" on the lazy slides agrees with the painted_sizes list instead of fetching originals. */
.ro-style-showcase .ws-slide--contain img { width: auto; max-width: 100%; margin-inline: auto; }
/* Prices sit under the gallery (see the renderer); below 960px the columns dissolve and they follow the title card. */
.ro-style-showcase .ss-price { order: 2; }
.ro-style-showcase .ss-price-note { margin: 10px 0 0; font-size: var(--ro-fs-meta); color: var(--ro-muted-fg); line-height: 1.5; }
@container ws-main (min-width: 640px) {
  .ro-style-showcase .ss-price { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; }
  .ro-style-showcase .ss-price > .ws-rcpt-h,
  .ro-style-showcase .ss-price > .ss-price-note { grid-column: 1 / -1; }
}
@media (min-width: 960px) {
  .ro-style-showcase h1.hero-title { font-size: var(--ro-fs-h2); }
}
@media (min-width: 1200px) {
  .ro-style-guide .ro-works-slider .wrap {
    max-width: calc(var(--ro-works-max) + 2 * var(--ro-works-gutter));
    padding-inline: var(--ro-works-gutter);
  }
}
/* v3.207.1 (Owner): the editorial blocks follow the gallery's main column, not the centred 720px W5
   column - left edge = gallery edge, width = .ws-main. Same canvas as .ro-work-single; from 960px the
   inline-end padding also reserves the rail + gap, so the content box equals .ws-main by construction. */
.ro-style-guide :is(.ro-reading-content, .ro-section-faq) .wrap {
  max-width: calc(var(--ro-works-max) + 2 * var(--ro-works-gutter));
  padding-inline: var(--ro-works-gutter);
}
@media (min-width: 960px) {
  .ro-style-guide :is(.ro-reading-content, .ro-section-faq) .wrap {
    padding-inline-end: calc(var(--ro-works-gutter) + var(--ro-ws-rail) + var(--ro-ws-gap));
  }
}
.ro-style-guide .ro-reading-content .wrap > .ro-prose { max-width: none; margin-inline: 0; }
/* The first block continues the main column under the price card: the 20px container gap + h2 margin
   (~28px) matches the .ws-main rhythm instead of opening a new 64px section beat. */
.ro-style-guide .elementor-widget-ro-style-showcase + .elementor-widget-ro-reading-content .ro-reading-content { padding-block-start: 0; }
.ro-style-guide .ro-section-faq .faq { max-width: none; }

/* ============================================================
   ABOUT PAGE (/about/, .ro-about)  —  #203, v3.79.0
   The page is composed entirely from existing sections; this block is the
   only About-specific CSS, and all of it concerns the ONE section that
   appears twice — Service Hero, as the page hero and again as "Meet Olga
   Palamarenco". Scoped to .ro-about per the standing ro-<surface> rule.
   ============================================================ */

/* Meet Olga reads as a distinct block, not a repeat of the hero: the card
   mirrors (media right), and its photo-less state uses the seeded, skin-aware
   frame-fallback art instead of a second identical .hero-media--fallback panel.
   The seed comes from the widget's fallback_seed control. */
.ro-about .ro-about-olga .hero-card  { grid-template-columns: 1fr 460px; }
.ro-about .ro-about-olga .hero-media { grid-column: 2; grid-row: 1; }
.ro-about .ro-about-olga .hero-body  { grid-column: 1; grid-row: 1; }

/* A portrait is not a service photo. .hero-media--framed's 4/3.4 crop is built
   for a hand/nail shot and would cut a head off; 4/5 is the portrait ratio the
   owner-supplied photo should be cropped to. */
.ro-about .ro-about-olga .hero-media--framed .frame img { aspect-ratio: 4 / 5; }

/* The seeded fallback paints its own background (v-1..v-4 in the branded
   fallback block above), so the flat panel background is cleared and the
   .frame-fallback child becomes the media box itself. */
.ro-about .ro-about-olga .hero-media--fallback { background: none; padding: 0; }
.ro-about .ro-about-olga .hero-media--fallback .frame-fallback {
  width: 100%; height: 100%; min-height: 420px;
  display: flex; align-items: center; justify-content: center;
  background-position: center; background-repeat: no-repeat; background-size: cover;
}

@media (max-width: 900px) {
  .ro-about .ro-about-olga .hero-card  { grid-template-columns: 1fr; }
  .ro-about .ro-about-olga .hero-media { grid-column: 1; grid-row: 1; }
  .ro-about .ro-about-olga .hero-body  { grid-column: 1; grid-row: 2; }
  .ro-about .ro-about-olga .hero-media--fallback .frame-fallback { min-height: 260px; }
}


/* ============================================================
   IMAGE FEATURE CARD (v3.87.0) — .ro-ifc

   CARD tier, not section tier: no .wrap, no section padding-block, no grid.
   The card fills the width it is given and stacks its own internals; how many
   cards exist and how they are arranged is the Elementor container's job.

   NOTE ON NESTING: Elementor wraps every widget as
   .elementor-widget > .elementor-widget-container > .ro-ifc, so the card is a
   grandchild of the container's flex item, never the flex item itself. The
   flex declaration below governs the card's internals only — it cannot and is
   not meant to stretch the card to its column's height. Cards in a row align
   at the top and at the image bottom (aspect-ratio lock); ragged description
   bottoms are the intended editorial result.

   PORTED FROM the prototype at .dev/prototypes/image-feature-card/, which
   carried a demo `* { margin: 0; padding: 0; box-sizing: border-box }` reset
   that production does NOT have. box-sizing is already global here (both Hello
   and Elementor declare it); the paragraph margin is not, so .ro-ifc__desc
   writes the full shorthand below — same as every other <p> rule in this file.
   ============================================================ */
.ro-ifc {
  display: flex;
  flex-direction: column;
  /* Editorial radius. Materially smaller than --ro-radius-card (20px), which
     reads as a generic app tile; still a Red Orchid curve, not a square.
     Component-local on purpose — promoting it is a design-system decision. */
  --ifc-radius: 8px;
}

.ro-ifc__media {
  position: relative;
  aspect-ratio: 5 / 4;                       /* same landscape crop as .cat-row__media */
  border-radius: var(--ifc-radius);
  overflow: hidden;
  background: var(--ro-surface-2);
  box-shadow: var(--ro-shadow-card);
  transition: box-shadow var(--ro-dur-base) var(--ro-ease-out);
}

/* Card-root prefix, not a bare `img`: `.elementor img { height: auto }` is
   (0,1,1) and would otherwise tie and win on order, collapsing the crop.
   No transform and no transition here — motion.md:71, "Never attach transform
   motion to :hover". The hover state is the shadow lift and the tab darkening. */
.ro-ifc .ro-ifc__media img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}

/* The heading element carries no visual weight of its own — the tab does.
   Tag is an input (h2/h3/h4); never h1. */
.ro-ifc__title {
  position: absolute; left: 0; right: 0; bottom: 0;
  margin: 0; font-size: inherit; font-weight: inherit; line-height: 1.3;
}

/* The editorial tab. Opaque ink plate flush into the lower-left corner, so it
   reads as a tab cut out of the photo rather than a chip resting on it —
   ink-on-photo inverts the site's white-chip idiom and cannot be mistaken for
   a button. Opaque means contrast is structural: no upload can degrade it.
   Root-prefixed at (0,2,0) to beat Hello's `a { color: #c36 }` at (0,1,1). */
.ro-ifc .ro-ifc__label {
  display: inline-flex; align-items: center; gap: 9px;
  max-width: 100%;
  padding: 12px 20px;
  background: var(--ro-foreground);
  color: rgb(var(--ro-rgb-surface));              /* #FFFFFF — 13.07:1 */
  border-radius: 0 var(--ifc-radius) 0 var(--ifc-radius);
  text-decoration: none;
  font-size: var(--ro-fs-ui);
  font-weight: var(--ro-fw-bold);
  letter-spacing: .005em;
  transition: background var(--ro-dur-base) var(--ro-ease-out);
}
.ro-ifc .ro-ifc__label svg { flex: none; width: 15px; height: 15px; }

/* Linked state. Every affordance here exists iff a target exists; an unlinked
   card renders the identical <span> tab and responds to nothing.

   Driven by :has(.ro-ifc__label:hover) — (0,4,0) — and NOT by :hover on the
   article: only the title is clickable, so hovering the photo or the
   description must not light the card up and imply a whole-card target.
   Keyboard gets the same treatment through :focus-visible.

   The repaint pair below is (0,3,0) and re-asserts BOTH color and background,
   because `.elementor-kit-15 a:hover` (0,2,1) and Hello's hover rule would
   otherwise repaint the white tab text mid-hover — the standing hover
   re-assert rule. The two specificity figures differ because the selectors
   differ; neither is a typo. */
.ro-ifc--linked:has(.ro-ifc__label:hover) .ro-ifc__media,
.ro-ifc--linked:has(.ro-ifc__label:focus-visible) .ro-ifc__media {
  box-shadow: var(--ro-shadow-card-hover);
}
.ro-ifc--linked .ro-ifc__label:hover,
.ro-ifc--linked .ro-ifc__label:focus-visible {
  background: rgb(var(--ro-rgb-sidebar-deep));    /* #241B20 — 16.76:1 */
  color: rgb(var(--ro-rgb-surface));
}

/* Ring INSIDE the opaque tab, not outside it. The tab is flush to the media's
   left and bottom edges and the media is overflow:hidden, so a positive offset
   is clipped on two sides; an inset ring is also the only version whose
   contrast is deterministic — pink on the tab's ink measures 3.35:1, where a
   ring over arbitrary photography guarantees nothing. */
.ro-ifc .ro-ifc__label:focus-visible {
  outline: 3px solid rgb(var(--ro-rgb-ring));
  outline-offset: -3px;
}

/* Full margin shorthand, not margin-top: Hello sets a bottom margin on <p>
   that the prototype's global reset was hiding. */
.ro-ifc .ro-ifc__desc {
  margin: var(--ro-stack-sm) 0 0;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-prose); line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure-tight);
}

/* No local prefers-reduced-motion block. The card animates no transform and no
   opacity — only box-shadow and background, which have no end state to cancel
   — so motion.css collapsing every --ro-dur-* to 1ms is the whole contract. */


/* ============================================================
   DEAL SINGLE (issue #229)
   The /deals/<slug>/ body. Delivered by the `RO Deal Single` widget
   inside the Deals-Single-V21 theme-builder template (the_content is a
   fallback and does not run on that template). It owns no page heading —
   the template's hero prints the <h1>.
============================================================ */
.ro-deal-single {
  padding-block: calc(var(--ro-section-gap) / 2);
}
.ro-deal-single .deal-single__facts {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: var(--ro-stack-sm);
}
/* Rides .ro-chip rather than a solid skin-lead fill. White on --ro-skin-lead
   measures 3.90 / 3.37 / 2.50 across the three skins against a 4.5 requirement
   for 12px text, and no single ink passes on all three (dark ink gives
   3.35 / 3.88 / 5.23). --ro-foreground on --ro-surface-2 is 12.38. Codex R1. */
.ro-deal-single .deal-single__badge {
  font-size: var(--ro-fs-ui-micro);
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 6px 12px;
}
.ro-deal-single .deal-single__pct b,
.ro-deal-single .deal-single__pct {
  font-weight: 800;
}
.ro-deal-single .deal-single__lede {
  /* Lead copy. */
  font-size: var(--ro-fs-lead);
  line-height: 1.6;
  color: var(--ro-foreground);
  margin-bottom: var(--ro-stack-sm);
  max-width: var(--ro-measure);
}
.ro-deal-single .deal-single__body {
  color: var(--ro-muted-fg);
  /* Body copy. */
  font-size: var(--ro-fs-prose);
  line-height: var(--ro-lh-prose);
  max-width: var(--ro-measure);
  margin-bottom: var(--ro-stack-md, var(--ro-stack-sm));
}
.ro-deal-single h2.deal-single__h2 {
  font-family: var(--ro-font-serif);
  font-weight: 900;
  font-size: var(--ro-fs-h3);
  line-height: 1.3;
  margin-bottom: var(--ro-stack-sm);
}
.ro-deal-single .deal-single__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 8px 24px;
  list-style: none;
  padding: 0;
  margin: 0 0 var(--ro-stack-sm);
}
.ro-deal-single .deal-single__list li {
  position: relative;
  padding-left: 22px;
  line-height: 1.5;
}
.ro-deal-single .deal-single__list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: .55em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ro-skin-lead);
}
.ro-deal-single .deal-single__conditions {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  color: var(--ro-muted-fg);
  font-size: var(--ro-fs-meta);
  line-height: 1.5;
  padding-top: var(--ro-stack-sm);
  border-top: 1px dashed var(--ro-border);
}
.ro-deal-single .deal-single__conditions svg {
  width: 14px;
  height: 14px;
  flex: none;
  margin-top: 3px;
  opacity: .7;
}
.ro-deal-single .deal-single__ctas {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: var(--ro-stack-sm);
}

/* ------------------------------------------------------------
   EDITORIAL GALLERY (F_NEXT editorial media contract, rev 8 §6.4)
   A static grid, not the Works slider: reusing that strip would mean
   extracting a mixed image/video primitive out of a shipped, verified
   surface (#223). Nothing here is shared with .ws-slides.

   The breakpoint is a VIEWPORT media query on purpose, even though the
   neighbouring reading sections use container queries: the `sizes`
   attribute this grid ships ("(max-width: 719px) 100vw, 430px") is
   resolved by the browser against the viewport before layout exists, so
   a container-based column switch could disagree with it and make the
   srcset lie. One rule decides both, or neither is honest.
   ------------------------------------------------------------ */
.ro-editorial-gallery { margin-block: var(--ro-stack-lg); }

.eg-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px; /* literal: tokens.css has --ro-gutter/--ro-pad-* and no generic gap token */
  /* The cap is load-bearing, not cosmetic. The shared .wrap rule above resolves to
     --ro-content-max, which is 1200px - NOT the 880px reading column the geometry
     contract assumed. Uncapped, a column would be ~564px at a wide viewport while the
     renderer declares 428px, and an understated `sizes` is worse than no srcset at all.
     Capping here is what makes the renderer's number true. Change one, change both. */
  max-width: 880px;
  margin-inline: auto;
}

@media (min-width: 720px) {
  .eg-grid {
    /* repeat(2), NOT auto-fit: auto-fit collapses the empty track, so a
       one-item gallery would stretch to the full 880px while `sizes`
       declares a 428px column. minmax(0, ...) because a bare 1fr starves
       a capped sibling. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.eg-item { margin: 0; }

/* The gallery is explicitly mixed-ratio, so each photo keeps its natural
   aspect — no aspect-ratio box and no object-fit crop. */
.eg-item img {
  display: block;
  width: 100%;
  height: auto;
}
