/* ============================================================================
   Joy Group — THE MENU DRAWER, SCRIM, FLOATING CALL BUTTON and SKIP LINK.
   One file, loaded by every page.

   Same lock as chrome-footer.css, and for the same reason: these render on the dc
   homepage and on every subpage, and keeping the design in two places let them
   drift. A measured comparison on 2026-08-19 found the What We Do sub-links at
   display:block with 13.4px of padding on the homepage and display:flex with 18px
   on the subpages, and the drawer's close button taking its colour from an inline
   style on one and from CSS on the other.

   NOT here, deliberately: the header shell and the menu button. Those are NOT the
   same element. The homepage's header is scroll-aware — transparent over the hero,
   ink after — driven by {{ headerBg }} / {{ headerFg }} bindings, and the menu
   button's rule lines follow that same state. Subpages have no hero, so theirs is
   always ink and static. Unifying them would break the homepage's hero treatment.

   As with the footer: do not restate these rules in the homepage <style> or in
   site.css, and do not put inline styles on drawer markup — an inline style beats
   this sheet and silently un-locks that element.
   ========================================================================== */


#dc-menu, #footer, .dc-inverse { --focus-ring: var(--rule-inverse-strong); }

/* Skip link */
.dc-skip { position: fixed; top: calc(8px + var(--sa-t)); left: calc(8px + var(--sa-l)); z-index: 200; transform: translateY(-160%); background: var(--ink-black); color: var(--crisp-white); border: 1px solid var(--rule-inverse-strong); padding: 10px 18px; border-radius: 999px; font-family: var(--font-ui); font-weight: var(--fw-medium); font-size: var(--text-nav-size); letter-spacing: var(--text-nav-ls); text-transform: uppercase; text-decoration: none; transition: transform var(--dur-base) var(--ease-standard); }
.dc-skip:focus { transform: translateY(0); }
.dc-skip:hover, .dc-skip:focus { color: var(--crisp-white); }

/* ---------- Menu drawer (Inland-pattern; choreography via html.menu-open) ---------- */
#dc-scrim { position: fixed; inset: 0; z-index: 35; background: rgba(20, 20, 20, 0.5); cursor: pointer; opacity: 0; pointer-events: none; transition: opacity 700ms var(--ease-standard); }
html.menu-open #dc-scrim { opacity: 1; pointer-events: auto; }
#dc-menu { position: fixed; top: 0; right: 0; bottom: 0; z-index: 40; width: 47vw; display: flex; flex-direction: column; background: var(--bg-inverse); color: var(--text-inverse); border-left: var(--hairline) solid var(--rule-inverse); clip-path: inset(0 0 0 100%); visibility: hidden; transition: clip-path 900ms cubic-bezier(0.74, 0, 0.24, 0.99), visibility 900ms; }
/* Visibility flips INSTANTLY on open and only eases out on close. Transitioning it over
   the full 900ms both ways meant the drawer was still visibility:hidden when openMenu's
   150ms focus call ran, so focus() silently failed and never entered the dialog. */
html.menu-open #dc-menu { clip-path: inset(0 0 0 0); visibility: visible;
  transition: clip-path 900ms cubic-bezier(0.74, 0, 0.24, 0.99), visibility 0s; }
#dc-menu .drawer-close { position: absolute; top: var(--sa-t); right: 76px; height: var(--header-h); appearance: none; background: none; border: none; cursor: pointer; padding: 12px; display: flex; align-items: center; color: rgba(255, 255, 255, 0.72); transition: color 260ms var(--ease-standard); z-index: 2; }
#dc-menu .drawer-close:hover { color: var(--crisp-white); }
#dc-menu .drawer-close span { font-size: 24px; line-height: 1; }
#dc-menu .drawer-body { flex: 1 1 auto; display: flex; flex-direction: column; padding: 112px 88px 72px 72px; }
/* ---- The desktop drawer scales with the window, it does not step ----
   Every size below is driven by viewport HEIGHT, because this is a full-height panel and
   the vertical fit is what constrains it: eight rows, an accordion that can add three
   more, and a foot. The clamps' floors are the old 760px-tall step and their ceilings the
   original design sizes, so a 1440x900 laptop and a 27" both get a menu in proportion to
   their own window instead of one fixed frame with two hard jumps in it. This replaces
   the max-height 840/760 blocks, which are gone. */
#dc-menu .menu-nav { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2); }
/* Orientation is carried by light alone — no dash, no rule. The current page sits
   at full white while the rest rest low enough that the lit item reads instantly. */
#dc-menu .menu-nav a { display: flex; align-items: center; justify-content: flex-end; text-align: right; text-decoration: none; border: none; color: rgba(255, 255, 255, 0.56); opacity: 0; transform: translateX(24px); transition: none; }
#dc-menu .menu-nav a:hover { color: var(--crisp-white); }
#dc-menu .menu-nav a[aria-current="page"] { color: var(--crisp-white); }
#dc-menu .menu-nav a span.lbl { font-family: var(--font-display); font-weight: var(--fw-display-light); font-size: 42px; line-height: 1.1; letter-spacing: var(--text-display-4-ls); }
html.menu-open #dc-menu .menu-nav a { opacity: 1; transform: translateX(0); transition: opacity 460ms var(--ease-standard) calc(150ms + var(--i, 0) * 50ms), transform 460ms var(--ease-standard) calc(150ms + var(--i, 0) * 50ms), color 260ms var(--ease-standard); }
/* What We Do accordion: the group wraps the parent link and its company list,
   so the flex gap sits between GROUPS and hover never crosses a dead zone.
   Expanding pushes every item after it down. Hover/keyboard-focus opens on
   pointer devices; .is-open is the touch path (chrome.js first-tap toggle). */
#dc-menu .menu-group { display: flex; flex-direction: column; align-items: flex-end; }
#dc-menu .menu-sub { display: flex; flex-direction: column; align-items: flex-end; gap: 0; max-height: 0; overflow: hidden; opacity: 0; transition: max-height 460ms var(--ease-standard), opacity 360ms var(--ease-standard); }
/* .is-open is the ONLY opener on touch. :hover and :focus-within both latch there — after
   a tap the group keeps focus, so the list stayed expanded however many times you tapped
   and the second tap appeared to do nothing. Mirrors the homepage. */
#dc-menu .menu-group.is-open .menu-sub { max-height: 150px; opacity: 1; }
@media (hover: hover) {
  #dc-menu .menu-group:hover .menu-sub,
  #dc-menu .menu-group:focus-within .menu-sub { max-height: 150px; opacity: 1; }
}
/* The companies stay in Haas — the second voice is the point. What made them read
   chunky was WEIGHT, not size: measured on canvas, Regular 400 carries a stem 13%
   of its cap height against the parents' 10.2%, so the children were texturally
   heavier than the 42px display line above them. Light 300 measures 10.1% — a
   match. 26px against the parents' 42, a 38px pitch (roomy enough not to cramp
   beside 62px parents, tight enough to group), and the first row's 18px is the
   tier break. Tone tracks the parents; size and weight carry the hierarchy. */
#dc-menu .menu-sub a { padding: 0; }
#dc-menu .menu-sub a:first-child { padding-top: 18px; }
#dc-menu .menu-nav .menu-sub a { font-family: var(--font-ui); font-weight: var(--fw-light); font-size: 26px; line-height: 1.46; letter-spacing: -0.005em; color: rgba(255, 255, 255, 0.56); }
#dc-menu .menu-nav .menu-sub a:hover { color: var(--crisp-white); }
/* The pinned foot, the centred nav band and the enlarged language toggle are PHONE-ONLY —
   see the 768 block. The desktop drawer keeps the foot in flow at the bottom of the body. */
/* baseline, not flex-end: the motif's translateY(13.2%) lands its OY baseline exactly on
   its layout box's bottom edge, and an <img> flex item's baseline IS that edge — so this
   puts the A of AL on the Y of JOY. Under flex-end the two BOXES lined up and the text sat
   11px high. Applies at every width; the phone block no longer repeats it. */
#dc-menu .drawer-foot { margin-top: auto; display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-6); opacity: 0; transform: translateX(24px); transition: none; }
html.menu-open #dc-menu .drawer-foot { opacity: 1; transform: translateX(0); transition: opacity 460ms var(--ease-standard) calc(150ms + var(--i, 8) * 50ms), transform 460ms var(--ease-standard) calc(150ms + var(--i, 8) * 50ms); }
#dc-menu .drawer-foot .motif { width: 300px; opacity: 0.10; pointer-events: none; display: block; transform: translateY(13.2%); }
/* The drawer must scroll when its content outgrows the screen. On a 667px phone with the
   What We Do accordion expanded the foot — motif and language toggle — was pushed past the
   bottom edge and could not be reached. overscroll-behavior: contain does the second job:
   without it a scroll reaching the drawer's end chains through to the page underneath. */
/* No -webkit-overflow-scrolling: touch. It promotes this box to its own compositing
   layer, which iOS Safari puts ABOVE absolutely-positioned siblings with no z-index —
   the close button — so taps on the x did nothing. It is a no-op on iOS 13+ anyway. */
#dc-menu .drawer-body { overflow-y: auto; overscroll-behavior: contain; }
/* NOTE: no `overflow: hidden` page lock. On iOS it makes position:fixed children — the
   drawer's close button among them — stop responding to touch. overscroll-behavior above
   already keeps a drawer scroll from chaining into the page. */

/* ---- Android/Chrome: don't let an open drawer hand gestures to the page ----
   overscroll-behavior only helps where a scroll actually STARTS in a scroll container.
   A swipe that begins on the scrim, or on the drawer's foot, has no scroller of its own,
   so Chrome hands it to the document: the page slides behind the open drawer, and at
   scroll position 0 the same downward swipe arms pull-to-refresh — which reloads the
   page out from under the user mid-menu. iOS has no pull-to-refresh, so this reads as a
   drift there and as data loss here.
   touch-action: none on those two surfaces removes panning without touching taps (it
   governs gestures, not clicks) and without touching .menu-nav, which is not their
   descendant and keeps scrolling normally. overscroll-behavior-y on the root disarms
   pull-to-refresh for the whole time the drawer is up, covering the strips of body
   padding that neither rule reaches. Both revert the moment the drawer closes. */
html.menu-open { overscroll-behavior-y: none; }
#dc-scrim, #dc-menu .drawer-foot { touch-action: none; }
#dc-menu:focus, #dc-menu:focus-visible { outline: none; }

#dc-menu .drawer-close { min-width: 44px; justify-content: center; }
/* Fill the pill's height: at its intrinsic 21px, tapping the pill's own padding missed
   the field entirely. */

/* ---- Drawer language toggle ----
   Was a bordered pill. In a drawer whose whole character is type on ink the pill was the
   one piece of chrome, and on a phone the foot wanted more width than the column had, so
   it was cut off the right edge. Two words and a slash: a third of the width, nothing to
   overflow. The slash is a glyph, not a rule. The solid footer keeps its pill. */
#dc-menu .drawer-lang { display: flex; align-items: baseline; gap: var(--space-1); flex: 0 0 auto; }
#dc-menu .lang-word { appearance: none; background: none; border: none; padding: 8px 2px; cursor: pointer; font-family: var(--font-ui); font-weight: var(--fw-medium); /* 1.5x the label token at full size, scaling with the window like the nav labels and
   the motif — an 11px toggle beside a 300px motif read as an afterthought. */
  font-size: clamp(12px, 1.83vh, calc(var(--text-label-size) * 1.5)); letter-spacing: var(--text-label-ls); text-transform: uppercase; color: rgba(255, 255, 255, 0.46); transition: color var(--dur-base) var(--ease-standard); }
#dc-menu .lang-word:hover { color: rgba(255, 255, 255, 0.78); }
#dc-menu .lang-word[aria-pressed="true"] { color: var(--crisp-white); }
#dc-menu .lang-sep { color: rgba(255, 255, 255, 0.24); font-family: var(--font-ui); font-size: clamp(12px, 1.83vh, calc(var(--text-label-size) * 1.5)); line-height: 1; user-select: none; }

/* ---------- Footer: see chrome-footer.css, imported at the top ---------- */

/* ---------- Floating call button (verbatim from the homepage) ---------- */
.dc-wa-fab { position: fixed; right: calc(28px + var(--sa-r)); bottom: calc(56px + var(--sa-b)); z-index: 70; width: 72px; height: 72px; display: block; color: var(--crisp-white); text-decoration: none; border: none; opacity: 1; pointer-events: auto; visibility: visible; transition: opacity var(--dur-base) var(--ease-standard), visibility 0s linear 0s; }
/* visibility, not opacity alone. pointer-events stops the mouse and nothing else:
   at opacity 0 the link stayed in the tab order and in the accessibility tree, so
   tabbing across the hero or the footer landed on an invisible "Call" and Enter
   opened WhatsApp. The flip is delayed by the length of the fade on the way out and
   immediate on the way back, so the button still fades rather than blinking. */
html.menu-open .dc-wa-fab, html.fab-hidden .dc-wa-fab { opacity: 0; pointer-events: none; visibility: hidden; transition: opacity var(--dur-base) var(--ease-standard), visibility 0s linear var(--dur-base); }
@keyframes joy-fab-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } }
.dc-wa-fab .fab-joy { animation: joy-fab-pulse 2s ease-in-out infinite; }
.fab-bubble { display: block; width: 72px; height: 72px; transition: opacity 1500ms var(--ease-standard); }
.fab-pill { position: absolute; top: 50%; right: -28px; display: flex; align-items: center; height: 53px;
  background: var(--ink-black); border: 1px solid var(--white-a40); border-right: none;
  border-radius: 999px 0 0 999px; white-space: nowrap;
  transform: translate(100%, -50%); opacity: 0;
  transition: transform 1500ms var(--ease-standard), opacity 1500ms var(--ease-standard); }
.fab-pill-label { display: block; padding: 0 29px 0 38px; white-space: nowrap;
  font-family: var(--font-ui); font-weight: var(--fw-medium); font-size: calc(var(--text-btn-size) * 2);
  letter-spacing: normal; text-transform: uppercase; color: var(--crisp-white); }
@media (hover: hover) {
  .dc-wa-fab:hover .fab-bubble, .dc-wa-fab:focus-visible .fab-bubble { opacity: 0; }
  .dc-wa-fab:hover .fab-pill, .dc-wa-fab:focus-visible .fab-pill { transform: translate(0, -50%); opacity: 1; }
}
/* ---- TOUCH, AT ANY WIDTH ----
   The two-step tap arms on the media FEATURE (hover: none) - chrome.js, and the
   same block at the foot of the homepage - so the rules that answer .is-armed have
   to be gated the same way. They used to sit in the 768px block below, and the two
   sets do not coincide: every iPad (810-1366) and every iPhone held in landscape
   (844-932) reports hover:none well above 768. There the first tap was swallowed by
   preventDefault and nothing anywhere responded to the class - no pill, no fade, no
   feedback of any kind - and only a second tap reached WhatsApp. Only the reveal
   belongs here; the phone's smaller sizes stay on width, where they belong. */
@media (hover: none) {
  .fab-pill { transition-duration: 260ms; }
  .dc-wa-fab.is-armed .fab-bubble { opacity: 0; transition-duration: 260ms; }
  .dc-wa-fab.is-armed .fab-pill { transform: translate(0, -50%); opacity: 1; }
}

/* ---- The desktop drawer scales with the window, it does not step ----
   Driven by viewport HEIGHT: this is a full-height panel and the vertical fit is what
   constrains it — eight rows, an accordion that can add three, and a foot. The clamps'
   floors are the old 760px-tall step and their ceilings the original design sizes, so a
   1440x900 laptop and a 27" each get a menu in proportion to their own window rather than
   one fixed frame with two hard jumps. Replaces the max-height 840/760 blocks, which are
   gone. Gated to >=769px: unscoped, these selectors outrank the phone block's own. */
@media (min-width: 769px) {
  #dc-menu .drawer-body { padding: clamp(72px, 12vh, 112px) clamp(48px, 6vw, 88px) clamp(48px, 8vh, 72px) clamp(40px, 5vw, 72px); }
  #dc-menu .menu-nav { gap: clamp(4px, 1.1vh, 16px); }
  #dc-menu .menu-nav a span.lbl { font-size: clamp(26px, 4.6vh, 42px); }
  #dc-menu .menu-nav .menu-sub a { font-size: clamp(18px, 2.9vh, 26px); }
  #dc-menu .menu-sub a:first-child { padding-top: clamp(10px, 2vh, 18px); }
  #dc-menu .menu-group.is-open .menu-sub { max-height: clamp(96px, 18vh, 170px); }
  #dc-menu .drawer-foot .motif { /* floor 150, not 190: at a 600px-tall window 28vh wants 168px, so a 190 floor stopped
     the motif scaling exactly where the window most needed it to keep going. */
  width: clamp(150px, 28vh, 300px);
  /* ...but the width above is driven by viewport HEIGHT while the drawer is sized by
     viewport WIDTH (47vw), and on a tablet in portrait those two disagree badly: at
     820x1180 the tall window asks for a 294px motif and the narrow drawer offers a
     294px foot, so the mark filled the row and shoved the AL/EN toggle clean outside
     the drawer's right edge. Measured, not theorised: langWithinDrawer was false at
     both 820x1180 and 834x1194. Capping against the foot's own width re-couples the
     two axes. 58% is chosen to be a no-op everywhere it was already fine — 1440
     wants 49%, the landscape tablets 54-58% — so only portrait actually moves. */
  max-width: 58%; }
  #dc-menu .drawer-close { right: clamp(32px, 5.3vw, 76px); }
}
@media (max-width: 768px) {
  #dc-menu { width: 100vw; border-left: none; }
  /* ---- PHONE DRAWER GEOMETRY (phone-only by design) ----
     THE FOOT NEVER MOVES: absolutely pinned to the drawer's bottom edge (containing block
     is #dc-menu, which is fixed, so the body's scrolling cannot carry it), on the drawer's
     own ink so nav rows slide beneath it; the body reserves its height as bottom padding.
     The nav owns the band above and centres there, so an expanding sub-list grows inside
     the band, never into the foot. align-items: baseline puts the AL/EN text baseline on
     the motif's own baseline — its translateY(13.2%) lands the OY baseline exactly on its
     layout box's bottom edge, and an <img> flex item's baseline IS that edge. */
  /* ---- THE MENU SCALES WITH THE SCREEN'S HEIGHT (mirrors the homepage) ----
     Every value is a clamp on vh whose ceiling is what this drawer used at 812px tall.
     The basis is 850px, not 812: at 812 the menu is ALREADY 20px short of fitting with a
     sub-list open, so a scale pegged to 812 would sit at its ceiling and shrink nothing.
     Pegging full size to 850 gives an 812px phone a gentle 4% trim and room to spare.
     Divisor 8.5 throughout. */
  /* THE SCROLLPORT IS THE NAV, NOT THE BODY.
     .drawer-foot is a CHILD of .drawer-body, so as long as .drawer-body is the thing
     that scrolls, the foot can only ever be one of two bad things: in flow (and then it
     scrolls away, which breaks "the motif and the language selector are never pushed
     down"), or absolutely pinned across the bottom (and then it is an opaque curtain
     painted over the scroll area, which is what hid Contact on short phones — the body
     reserved the foot's height as padding, but reserving space is not the same as not
     overlapping: the moment the nav overflowed, the surplus landed inside that padding,
     which is exactly where the foot is drawn).
     Moving the scrollport one level in dissolves the conflict. The body stops scrolling
     and just lays out two children; the nav takes the free space and scrolls inside
     itself; the foot sits in normal flow underneath it and therefore cannot be reached
     by any nav item, at any height, in any state. min-height: 0 is what actually makes
     the nav scroll — a flex item defaults to min-height: auto and refuses to shrink
     below its content, so without it the nav would grow and shove the foot off-screen. */
  /* svh, not vh, throughout the drawer. #dc-menu is sized top:0/bottom:0 — the
     SMALL viewport, what is on screen while Safari's URL bar is showing — but
     every metric inside it was measured in vh, which on iOS is the LARGE
     viewport, 60-90px taller. So the drawer laid itself out for a box bigger
     than the one it occupies, which is precisely why it overflowed on small
     iPhones and not on big ones. svh is also stable: unlike dvh it does not
     re-run as the URL bar collapses, so nothing reflows mid-scroll. */
  #dc-menu .drawer-body { overflow: hidden; min-height: 0;
    padding: clamp(40px, 8.47svh, 72px) 40px 0;
    padding-top: calc(clamp(40px, 8.47svh, 72px) + var(--sa-t)); }
  #dc-menu .drawer-foot { position: static; flex: 0 0 auto; margin-top: auto;
    padding: clamp(10px, 1.88svh, 16px) 0 calc(clamp(24px, 5.65svh, 48px) + var(--sa-b));
    gap: clamp(16px, 5.65svh, 48px); }
  /* `safe center`, not plain `center`. A centred flex box that OVERFLOWS pushes its
     content out of BOTH ends, and the surplus above the start edge is unreachable —
     you cannot scroll backwards past a scroll container's origin. `safe` keeps the
     centring whenever there is room and silently falls back to `start` the moment there
     is not, so overflow only ever goes downward, where it scrolls. The plain `center`
     before it is the fallback for engines that do not know the keyword.
     padding-right/margin-right cancel out: the right edge lands exactly where it did,
     but the 24px the entry animation translates from now lives inside the padding
     instead of overflowing a scroll container that would answer with a sideways scroll. */
  #dc-menu .menu-nav { flex: 1 1 auto; min-height: 0; overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: 24px; margin-right: -24px;
    gap: clamp(9px, 1.88svh, 16px);
    justify-content: center;
    justify-content: safe center; }
  #dc-menu .menu-nav a { min-height: clamp(40px, 5.18svh, 44px); }
  #dc-menu .menu-nav a span.lbl { font-size: clamp(23px, 3.77svh, 32px); }
  #dc-menu .menu-nav .menu-sub a { font-size: clamp(15px, 2.35svh, 20px); line-height: 1.5; }
  /* phones keep a little padding so the rows stay tappable at this size */
  #dc-menu .menu-sub a { padding: 4px 0; }
  /* keeps its corner, simply gets smaller — at 200px it pushed the language toggle
     clean off the right edge */
  #dc-menu .drawer-foot .motif { width: clamp(92px, 17.41svh, 148px); }
  /* An open sub-list adds ~120px, which is what actually breaks a short phone. Rather than
     pay for that in the resting state, the tighter spec applies ONLY while one is open:
     36px rows (still well clear of the 24px WCAG 2.5.8 minimum) and closer gaps. At 812
     both sit above their floors, so nothing changes there. */
  #dc-menu:has(.menu-group.is-open) .menu-nav a { min-height: clamp(36px, 5.18svh, 44px); }
  #dc-menu:has(.menu-group.is-open) .menu-nav { gap: clamp(7px, 1.5svh, 16px); }
  /* The last 12px, at 640 only. Rows and gaps are already as tight as they should go, so
     the remainder comes out of the head margin, which at that height is a very generous
     54px. The ramp is steeper than the 8.47svh it overrides so that it hits the same 72px
     ceiling by ~780 — every phone at 844 and above therefore keeps its spacing to the
     pixel, and only genuinely short screens give anything back. Below 640 it holds at the
     40px floor and the nav's own scrolling takes over. */
  #dc-menu:has(.menu-group.is-open) .drawer-body {
    padding-top: clamp(40px, calc(22.54svh - 104.3px), 72px); }
  #dc-menu .drawer-lang { gap: 4px; }
  #dc-menu .lang-word { min-height: 44px; min-width: 44px; padding: 4px 8px; display: inline-flex; align-items: center; justify-content: center; }
    /* 40px here against the homepage's 44 — the touch-target bump had been applied to the
     homepage only. It also threw the pill's alignment out, since the pill lines up with
     the last icon and the row's width depends on the icon size. */
  /* Sized off the social icons, not off the touch minimum. The 44px buttons made the
       pill 58px tall — 14px taller than the icons it sits above — and it read as bulky.
       The ring now hugs the buttons (no padding, no gap, clipped by overflow) so the
       control is 44px overall, exactly an icon's height, with each half still a 42px
       target: comfortably past the 24px WCAG 2.5.8 floor, and the same inner height
       the icons themselves have inside their own 1px ring.

       Right edge lines up with the WhatsApp icon rather than the page margin. The
       social row is CENTRED, so its last icon stops short of the margin — the offset
       below is that shortfall, derived rather than guessed. It depends on the icon
       COUNT, so if a social link is ever added or removed, update the 5 here. */
  #dc-menu .drawer-close { right: 28px; }

  /* ---- FLOATING CALL BUTTON ON PHONES ----
     Measured off Meraas's own floating buttons, which are 44x44 tucked at right
     21 / bottom 13 — small and cornered, not hovering mid-column. Ours shipped
     the 72px desktop bubble unchanged, so it sat on top of the body copy on
     every scroll position. 48px keeps the tap target comfortable while clearing
     the text; the hover pill never applied on touch anyway. */
  .dc-wa-fab { right: calc(16px + var(--sa-r)); bottom: calc(16px + var(--sa-b));
    width: 48px; height: 48px; }
  .fab-bubble { width: 48px; height: 48px; }
  /* The pill EXISTS on phones now — it is the first half of a two-step tap. There is
     no hover on a phone, so the desktop reveal (gated behind hover:hover) never fired
     and a tap went straight to WhatsApp with no confirmation. Now the first tap arms
     the button and shows the label; the second follows the link.
     Scaled to the 48px bubble rather than the desktop 72, and the reveal is 260ms
     instead of 1500 — a hover can afford to unfurl slowly, a tap needs to answer. */
  /* right: -16px matches the FAB's own 16px inset, so the pill's right edge lands
     exactly on the screen edge. At -20 it overhung by 4px and clipped. */
  .fab-pill { display: flex; height: 40px; right: -16px;
    transition-duration: 260ms; }
  .fab-pill-label { padding: 0 18px 0 24px; font-size: var(--text-body-size); }
  /* the .is-armed reveal itself now lives in the (hover: none) block above */
}

/* ---------- Reduced motion (mirrors the homepage block) ---------- */
@media (prefers-reduced-motion: reduce) {
  #dc-menu { transition-duration: 1ms !important; }
  #dc-menu .menu-nav a, #dc-menu .drawer-foot {
    transition: none !important; transform: none !important; opacity: 1 !important;
  }
}