/* v3 components — bento grid, footer, homepage staff deck, featured post card. Part of the v3 design layer; linked by build-pages.ts sharedStyle(). */
    /* ── Bento — 2-up hairline grid for label+blurb clusters ───────────────
       One framed container; the 1px grid gap shows the container background
       through as internal hairlines (works for any cell count, collapses to
       1-col on mobile). Same chrome as the footer bento. Safe inside .v3-prose
       because the v3 layer loads after the reset + prose. */
    .v3-bento { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--color-border); border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; margin: 8px 0 40px; box-shadow: -6px 5px 0 rgba(150,168,190,0.22); }
    @media (max-width: 600px) { .v3-bento { grid-template-columns: 1fr; } }
    .v3-bento__cell { background: var(--color-bg-card); padding: 22px 24px; }
    .v3-bento__icon { display: block; color: var(--color-brand); margin: 0 0 13px; }
    .v3-bento__icon .iconify { width: 26px; height: 26px; }
    /* Reuse the display-heading recipe (Newsreader + light weight + tight
       tracking/leading), same as the hero / band titles — thinner & florid.
       Double-class (.v3-bento .v3-bento__name, 0,2,0) so the light weight beats
       the inherited .v3-prose strong rule (font-weight bold, 0,1,1). */
    .v3-bento .v3-bento__name { display: block; font-family: var(--font-display); font-weight: var(--weight-light); color: var(--color-ink); font-size: 1.5rem; line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); margin: 0 0 8px; }
    .v3-bento .v3-bento__text, .v3-bento__cell p { margin: 0; } /* type: BODY-SM role */
    .v3-bento__cell p + p { margin-top: 14px; } /* stacked paragraphs in a cell (e.g. contact Insurance) */

    /* ── v3 footer (new, scoped) ───────────────────────────────────────── */
    /* Footer shares the BODY-SM size (1rem/1.55) but keeps its own navy/muted
       colours — so it's not in the BODY-SM role group. The uppercase cell/column
       labels (h2/h3) and the wordmark set their own (smaller/larger) sizes. */
    .v3-footer { background: #e8f5f9; color: #264068; margin-top: 64px; padding: 28px 24px 36px; font-family: var(--font-sans); font-weight: 400; }
    /* Footer rows/columns set their own size, leading and weight (the column
       labels are <h2>/<h3> with their own sizes, so '.v3-footer p' never
       touches them). */
    .v3-footer p, .v3-footer__row, .v3-footer-col, .v3-footer__pages, .v3-footer__links {
      font-size: 1rem; line-height: 1.55; font-weight: 500;
    }
    /* Mega footer (every page): everything sits inside ONE big rounded white card
       floating on the mist. A Visit zone (brand + a thin-line bento of address /
       hours / contact / follow + a full-width map + CTA) anchors the left; an
       auto-fitting sitemap of plain link columns (Care / Treatments / Practice /
       Learn) gives site-wide internal links for nav + SEO. © sits in a borderless
       bar at the bottom. auto-fit means the columns reflow without media queries. */
    .v3-footer__card {
      /* The card BORDER must line up with the content column, not the raw frame:
         nav items and band text sit inside a --space-6 gutter (edge at frame+24),
         so the card max-width is the frame minus those two gutters. Otherwise the
         card sticks out 24px past every other element's left/right edge. */
      max-width: calc(var(--w-content) - 2 * var(--space-6)); margin: 0 auto;
      background: var(--color-bg-card, #fff); border: 1px solid var(--color-border);
      border-radius: var(--radius-lg); box-shadow: 0 1px 3px rgba(38,64,104,0.06);
      padding: 44px 44px 24px;
    }
    @media (max-width: 600px) { .v3-footer__card { padding: 32px 24px 20px; } }
    .v3-footer__bento {
      display: grid; gap: 40px; align-items: start;
      grid-template-columns: minmax(340px, 420px) 1fr;
    }
    @media (max-width: 820px) { .v3-footer__bento { grid-template-columns: 1fr; } }
    .v3-footer__sitemap {
      display: grid; gap: 96px 40px;
      grid-template-columns: 1fr 1fr;
    }
    @media (max-width: 420px) { .v3-footer__sitemap { grid-template-columns: 1fr; } }
    .v3-footer__visit { display: flex; flex-direction: column; }
    .v3-footer__brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; margin-bottom: 30px; }
    .v3-footer__brand:hover, .v3-footer__brand:active, .v3-footer__brand:focus { text-decoration: none; background: transparent; }
    .v3-footer__logo { height: 36px; width: auto; display: block; }
    .v3-footer__wordmark { font-family: var(--font-display); font-weight: 400; font-size: 1.45rem; color: #264068; }
    /* Thin-line bento: a 1px grid gap + outer border over a border-colored
       background reads as hairline separators (each white cell paints over it). */
    .v3-footer__bento2 {
      display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
      background: var(--color-border); border: 1px solid var(--color-border);
      border-radius: var(--radius); overflow: hidden;
    }
    @media (max-width: 420px) { .v3-footer__bento2 { grid-template-columns: 1fr; } }
    .v3-footer__cell { background: var(--color-bg-card, #fff); padding: 15px 17px; }
    /* Address (and the inlined Hours) span the full bento width — the street
       "144 South Columbia Drive" needs ~214px but a half-cell only gives ~175px,
       so a half-width address always wraps mid-line. Full width fits it cleanly. */
    .v3-footer__cell--wide { grid-column: 1 / -1; }
    .v3-footer__cell--map { grid-column: 1 / -1; padding: 0; }
    /* Hours, full width: lay the two ranges side by side so the row fills. */
    .v3-footer__hours--inline { display: flex; flex-wrap: wrap; gap: 4px 18px; }
    .v3-footer__cell .v3-footer__row { margin-bottom: 7px; }
    .v3-footer__celltitle {
      font-family: var(--font-sans); font-size: 0.64rem; font-weight: 700;
      letter-spacing: 0.1em; text-transform: uppercase; color: #5a6b82; margin: 0 0 9px; text-align: left;
    }
    .v3-footer__cta { margin-top: 16px; }
    /* Shared thin-line bento for the financing link pair — used by BOTH the
       footer and the mobile nav takeover (the nav rule lives in v3-nav.css and
       reuses this class). 1px grid gap + outer border over a border-colored
       ground reads as a hairline divider between the two cells; each .v3-cta
       fills its cell (override .v3-cta's fit-content) and centers. Consumers own
       `display: grid` + column count, so each can hide/show + stack as it needs. */
    .v3-fin-bento {
      grid-template-columns: 1fr 1fr; gap: 1px;
      background: var(--color-border); border: 1px solid var(--color-border);
      border-radius: var(--radius); overflow: hidden;
    }
    .v3-fin-bento .v3-cta {
      width: auto; justify-content: center; background: var(--color-bg-card, #fff); padding: 14px 16px;
    }
    /* A100 (WCAG 2.4.7). These bentos clip to their corners with `overflow: hidden`,
       and each cell's link fills its cell exactly — so a focus ring drawn OUTSIDE the
       link (a positive `outline-offset`) gets clipped away and keyboard users see
       nothing. Draw it INSIDE instead. The tint is there because an inset ring hugs
       the cell edge and can otherwise read as just a border. */
    .v3-fin-bento a:focus-visible,
    .v3-footer__bento2 a:focus-visible,
    .v3-bento a:focus-visible {
      outline: 2px solid #264068;
      outline-offset: -3px;
      background: rgba(38, 64, 104, 0.07);
    }
    .v3-footer__visit-financing { display: grid; margin: 20px 0 0; }
    @media (max-width: 420px) { .v3-footer__visit-financing { grid-template-columns: 1fr; } }
    /* Regular footer nav — flat horizontal strip of the main site pages, divided
       from the rich columns above by a hairline. */
    .v3-footer__pages {
      display: flex; flex-wrap: wrap; gap: 10px 22px;
      margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--color-border);
    }
    .v3-footer__pages a { font-weight: 600; color: #264068; }
    .v3-footer__bar { margin-top: 16px; }
    .v3-footer__coltitle {
      font-family: var(--font-sans); font-size: 0.72rem; font-weight: 700;
      letter-spacing: 0.1em; text-transform: uppercase; color: #5a6b82;
      margin: 0 0 4px; text-align: left; /* explicit left — these labels are headings */
    }
    .v3-footer-col { display: flex; flex-direction: column; gap: 10px; }
    .v3-footer__hours { color: #2f3b4f; line-height: 1.6; margin: 0; }
    .v3-footer-map { overflow: hidden; }
    .v3-footer-map iframe { width: 100%; min-height: 168px; display: block; border: 0; }
    /* The v3-reset.css base gives every <p> padding-bottom: 2rem (32px) — which
       puffs dead space below the address, the Explore link list, the "Hours"
       link, and the copyright. Zero it inside the footer so the cards close up
       tight (the address tucks right onto the map). */
    .v3-footer p { padding-bottom: 0; }
    .v3-footer__addr { line-height: 1.6; margin: 0; }
    .v3-footer__links { display: flex; flex-direction: column; gap: 9px; margin: 0; }
    .v3-footer a { color: #264068; }
    .v3-footer a.btn { color: #fff; } /* footer link color must not override .btn's white text on navy */
    /* Footer text links (sitemap cols, address, contact/follow rows, page nav)
       underline on hover. The footer's own button/CTA/brand anchors opt out —
       a small, bounded list of exactly the components that live IN the footer,
       not a global registry. */
    .v3-footer a:not(.btn):not(.v3-cta):not(.v3-footer__brand):hover { text-decoration: underline; text-underline-offset: 2px; }
    .v3-footer__row { display: flex; align-items: center; gap: 10px; margin-bottom: 11px; }
    .v3-footer__row:last-child { margin-bottom: 0; }
    .v3-footer__row .iconify { width: 20px; height: 20px; color: #264068; flex-shrink: 0; }
    .v3-footer__copy { margin: 0; color: #5a6b82; }

    .v3-skip-link {
      position: absolute; left: -9999px; top: 0; background: #264068; color: #fff;
      padding: 10px 16px; z-index: 200000; border-radius: 0 0 6px 0;
    }
    .v3-skip-link:focus { left: 0; }
    /* #main-content is tabindex="-1" so the skip link can MOVE FOCUS to it
       (not just scroll). Suppress the big container outline — the focus move +
       scroll is the indication; the next Tab gets normal focus rings. */
    #main-content:focus { outline: none; }

    /* Mobile: clip stray decorative overflow (the rotated photo-peek candid on
       /about pokes ~3px past the right edge at narrow widths) so the page never
       scrolls sideways. clip (not hidden) creates no scroll box, so the sticky
       nav is unaffected; inner carousels keep their own overflow-x:auto. */
    html { overflow-x: clip; }

    /* ════════════════════════════════════════════════════════════════
       BRAND PALETTE — light blue + white + terracotta (locked 2026-06-13)
       Tokens in /static/css/tokens.css. This block re-skins v3 surfaces
       onto the semantic tokens; navy (--color-ink) stays for headings as
       brand equity. Loaded last → wins the cascade. Re-theme by editing
       tokens.css — nothing here changes. */
    body { background: var(--color-bg-page); color: var(--color-ink-body); }

    /* Primary buttons → clinical blue, cool offset shadow */
    .btn { background: var(--color-brand); border-color: var(--color-brand); color: #fff;
           box-shadow: -4px 4px 0 0 rgba(30,58,95,0.18); }
    .btn:hover { background: var(--color-brand-deep); border-color: var(--color-brand-deep); color: #fff; }
    .btn--outline { background: var(--color-bg-card); color: var(--color-brand); border-color: var(--color-brand); }
    .btn--outline:hover { background: var(--color-bg-card); color: var(--color-brand-deep); }
    /* A105. This rebrand override loads after v3-base.css and used to hardcode
       `outline-color: var(--color-brand)` — which is the SAME colour as .v3-book-band's
       background, so the focus ring on "Book a visit" was brand-blue on brand-blue: a
       contrast ratio of 1.00:1, i.e. perfectly invisible. Go through --focus-ring so dark
       surfaces can flip it to white. Never hardcode a colour here again. */
    .btn:focus-visible { outline-color: var(--focus-ring, var(--color-brand)); }

    /* Nav (scrolled state only) → light frosted white, no border */
    .v3nav.is-scrolled { background: rgba(255,255,255,0.7); }
    @media (max-width: 820px) { .v3nav__links { background: var(--color-bg-card); border-bottom-color: var(--color-border); } }

    /* Eyebrows / kicker labels → terracotta accent (the warm pop) */
    .v3-eyebrow, .v3-service-hero .v3-eyebrow, .v3-pillar__label { color: var(--color-accent); }

    /* Treatment + related cards → white on cool borders */
    .v3-tcard { background: var(--color-bg-card); border-color: var(--color-border); }
    a.v3-tcard:hover { border-color: var(--color-brand-soft); }

    /* ── .v3-lift — the ONE hover "rise" for interactive CARDS. Buttons never
       lift (see v3-base.css); cards do. This owns the rise + the reduced-motion
       guard; each card keeps its own shadow growth in its component rule. The
       card classes opt in below. New liftable card → add the `v3-lift` class,
       or list it here. */
    .v3-lift, a.v3-tcard, .v3-featured__card { transition: transform 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease; }
    .v3-lift:hover, a.v3-tcard:hover, .v3-featured__card:hover { transform: translateY(-2px); }
    @media (prefers-reduced-motion: reduce) {
      .v3-lift:hover, a.v3-tcard:hover, .v3-featured__card:hover { transform: none; }
    }
    .v3-tcard__tag { background: var(--color-sky); color: var(--color-brand-deep); }
    .v3-faq__item { border-bottom-color: var(--color-border); }

    /* Numbered steps → blue */
    .v3-steps li::before { background: var(--color-brand); }
    .v3-steps li::after { background: var(--color-border); }

    /* Service hero / callout → cool washes */
    .v3-service-hero { background: linear-gradient(150deg, var(--color-bg-alt) 0%, var(--color-sky) 100%); }
    .v3-callout { background: var(--color-bg-alt); border-left-color: var(--color-brand); }

    /* Book band → blue brand */
    .v3-book-band { background: var(--color-brand); }
    .v3-book-band p { color: var(--color-ink-invert); }
    .v3-book-band .btn { background: var(--color-bg-card); color: var(--color-brand); border-color: var(--color-bg-card); }
    .v3-book-band .btn:hover { background: #fff; color: var(--color-brand-deep); }

    /* Footer → light mist behind the white card (keeps the dark thesis band as
       the page's one dark moment) */
    .v3-footer { background: var(--color-bg-alt); color: var(--color-ink); }

    /* ════════════════════════════════════════════════════════════════
       FULL-BLEED BANDS — Parsley-style "register shifts" (IA teardown).
       A .v3-band is a full-width section child of <main>; the inner wrapper
       re-centers content. Variants set the surface (+ ink on the dark one)
       from tokens, so they re-skin with the theme. */
    /* Full-bleed: these painted bands carry no horizontal margin, so they reach
       the viewport edge (the reset already zeros section/div margins; this just
       re-asserts it). Inner content stays constrained by .v3-band__inner
       (max-width + padding). */
    .v3-band, .v3-featured { margin-left: 0; margin-right: 0; }
    .v3-band { padding: clamp(var(--space-12), 7vw, var(--space-20)) 0; }
    /* About page (bodyClass: page-about) — one standardized, generous vertical
       rhythm across every stacked section. Bands get a bigger block padding, and
       the team block (not a .v3-band) gets a matching bottom gap so the
       "Come see for yourself" book band isn't crowded against the roster. */
    .page-about .v3-band { padding-block: clamp(72px, 8vw, 112px); }
    .page-about .v3-team-section { padding-bottom: clamp(96px, 9vw, 140px); }
    /* About: center the WIDE showcase-section headers — #visit (info grid),
       #team (roster intro), and #reviews (testimonial cards) — so they don't
       read as offset-left against their centered content below. The narrow
       prose bands (Prevention, Tech, …) stay left-aligned on purpose. */
    .page-about #visit .v3-band__inner,
    .page-about #reviews .v3-band__inner { text-align: center; }
    .page-about #visit .v3-band__lede,
    .page-about #reviews .v3-band__lede { margin-left: auto; margin-right: auto; }
    .page-about #visit .v3-info-grid,
    .page-about #reviews .v3-review-masonry { text-align: left; }
    .page-about #team { text-align: center; }
    .page-about #team .v3-band__lede { margin-left: auto; margin-right: auto; }
    .v3-band__inner { max-width: var(--w-content); margin: 0 auto; padding: 0 var(--space-6); }
    .v3-band__inner--narrow { max-width: var(--w-read); }
    .v3-band--alt    { background: var(--color-bg-alt); }
    .v3-band--quote  { background: var(--color-bg-quote); }
    .v3-band--sand   { background: var(--color-bg-sand); }
    /* --focus-ring: white, because this band is dark and the default ring is navy — on
       navy it's invisible (A105). Every focusable inside the band inherits it. */
    .v3-band--invert { background: var(--color-bg-invert); color: var(--color-ink-invert); --color-accent: var(--ds-terracotta-500); --focus-ring: #fff; }
    .v3-band__title {
      font-family: var(--font-display); font-weight: var(--weight-light); color: var(--color-ink);
      font-size: var(--text-h2); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); margin: 0;
    }
    .v3-band__lede {
      font-family: var(--font-display); font-weight: var(--weight-light); font-size: var(--text-2xl);
      line-height: var(--leading-normal); color: var(--color-ink-muted); margin: var(--space-4) 0 0; max-width: 40em;
    }
    .v3-band--invert .v3-band__title { color: var(--color-ink-invert); }
    .v3-band--invert .v3-band__lede { color: rgba(234,242,251,0.82); margin-left: auto; margin-right: auto; }
    /* Guard (A08): prose inside a dark band must invert its ink, or BODY-role
       text (dark ink) would render dark-on-dark. */
    .v3-band--invert .v3-prose, .v3-band--invert .v3-prose p,
    .v3-band--invert .v3-prose li, .v3-band--invert .v3-prose strong { color: var(--color-ink-invert); }
    .v3-band--invert .v3-prose a { color: #fff; }
    /* On the dark band, buttons go white-fill / ghost-outline for contrast */
    .v3-band--invert .btn { background: #fff; color: var(--color-ink); border-color: #fff; box-shadow: -4px 4px 0 0 rgba(0,0,0,0.18); }
    .v3-band--invert .btn:hover { background: var(--color-bg-alt); color: var(--color-ink); }
    .v3-band--invert .btn--outline { background: transparent; color: #fff; border-color: rgba(255,255,255,0.55); }
    .v3-band--invert .btn--outline:hover { background: rgba(255,255,255,0.12); color: #fff; }

    /* Round prev/next arrow button — used by the homepage staff deck. */
    .v3-scroller__btn {
      width: 46px; height: 46px; border-radius: 50%; box-shadow: none;
      border: 1.5px solid var(--color-border-strong); background: var(--color-bg-card);
      color: var(--color-brand); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
      transition: background .15s ease, color .15s ease, border-color .15s ease;
    }
    .v3-scroller__btn:hover { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }
    .v3-scroller__btn:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 2px; }
    .v3-scroller__btn .iconify { width: 22px; height: 22px; flex: 0 0 auto; }

    /* ── "Care for your teeth" service deck (.v3-deck) — a fanned card deck. The
       per-card transform is set by tf(i) in Alpine (index.html), so the cards
       react to selection: the others slide away while the clicked one rises,
       straightens, and reveals its blurb. The deck breaks out wider on big
       screens; under 600px it falls back to a vertical tap-to-expand stack (tf()
       returns no transform there). --i is the card index (0–7, centred on 3.5). */
    .v3-deck { position: relative; width: 100%; max-width: 920px; height: 256px; margin: 0 auto; }
    /* On wide screens let the deck break out past the band's reading column so
       the fan spreads wider and the cards stop blocking each other (same
       breakout trick as .v3-pillar-grid). The spread step in tf() then scales
       with the wider deck. */
    @media (min-width: 1080px) {
      .v3-deck { --deck-w: min(1280px, 100vw - 96px); width: var(--deck-w); max-width: none; margin-inline: calc(50% - var(--deck-w) / 2); }
    }
    .v3-deck__card {
      position: absolute; left: 50%; top: 14px; width: 158px; min-height: 146px; margin-left: -79px;
      background: #fff; border: 1px solid #d9e6ec; border-radius: var(--radius);
      box-shadow: -4px 6px 16px rgba(38,64,104,0.12);
      padding: 15px 16px; cursor: pointer; text-align: left; display: flex; flex-direction: column; gap: 0;
      transform-origin: 50% 50%;
      /* transform is set per-card by Alpine tf(i) (:style) so the cards react to
         selection — others slide away from the clicked card and it rises +
         straightens. The width-fit spread + arc are computed there too. */
      transition: transform .34s cubic-bezier(.2,.7,.3,1), box-shadow .2s ease, border-color .2s ease;
      z-index: 1;
    }
    .v3-deck__card:hover { z-index: 25; box-shadow: -7px 12px 26px rgba(38,64,104,0.22); }
    .v3-deck__card.is-sel { z-index: 40; box-shadow: -8px 14px 32px rgba(38,64,104,0.26); border-color: #264068; }
    /* The card is a plain container; the toggle (tag + title) is the real
       <button> and the "Learn more" <a> is a sibling — no nested interactive
       controls. Raise the card's z while anything inside it is focused so the
       focus ring isn't hidden under a neighbour. */
    .v3-deck__card:focus-within { z-index: 30; }
    /* flex-grow:1 stretches the button to fill the card's height (its tag+title
       stay top-aligned) so the WHOLE collapsed card is clickable — without
       nesting another interactive control. */
    .v3-deck__toggle { display: flex; flex-direction: column; align-items: flex-start; gap: 7px; flex-grow: 1; width: 100%; background: none; border: 0; padding: 0; margin: 0; text-align: left; cursor: pointer; font: inherit; color: inherit; }
    .v3-deck__toggle:focus-visible { outline: 2px solid #264068; outline-offset: 4px; border-radius: var(--radius); }
    /* visibility:hidden when closed pulls the blurb's "Learn more" link OUT of
       the tab order (so tabbing the closed deck only stops on the cards). On
       open, overflow flips to visible AFTER the expand finishes so the Learn-more
       focus ring isn't clipped by the reveal box. The 0s transition delays make
       both switches happen at the right moment without breaking the animation. */
    .v3-deck__reveal {
      display: block; opacity: 0; max-height: 0; min-height: 0; overflow: hidden; visibility: hidden;
      transition: opacity .28s ease .08s, max-height .34s ease, visibility 0s linear .36s;
    }
    .v3-deck__card.is-sel .v3-deck__reveal {
      opacity: 1; max-height: 300px; margin-top: 12px; overflow: visible; visibility: visible;
      transition: opacity .28s ease .08s, max-height .34s ease, visibility 0s, overflow 0s linear .34s;
    }
    .v3-deck__blurb { display: block; margin: 0 0 12px; font-family: var(--font-sans); font-size: 0.88rem; line-height: 1.5; color: var(--color-ink-body); }
    /* The card-title role is 1.4rem — oversized for a compact fan card and it
       overflows on long words ("Remineralization"). Scale it down to fit; keep
       break-word as a last-resort guard. */
    .v3-deck__card .v3-tcard__name { font-size: 0.96rem; line-height: 1.2; overflow-wrap: break-word; hyphens: auto; }
    /* Mobile — a fan can't fit a narrow screen, so drop to a plain vertical
       stack of title-only cards that tap to expand. tf() returns no transform
       below 600px (see index.html), so the cards flow normally here. */
    @media (max-width: 600px) {
      .v3-deck { height: auto; max-width: 440px; }
      .v3-deck__card { position: relative; left: auto; top: auto; margin: 0 0 12px; width: 100%; min-height: 0; }
      .v3-deck__card:last-child { margin-bottom: 0; }
    }
    /* Respect reduced-motion: keep the fanned layout but drop the sliding/fade
       animation (the transforms still apply, just instantly). */
    @media (prefers-reduced-motion: reduce) {
      .v3-deck__card, .v3-deck__reveal { transition: none; }
    }
    /* ── Homepage staff deck — 'flip through' the team's fun quotes, shuffled
       fresh per visit. One card at a time; prev/next arrows reuse the round
       .v3-scroller__btn; the card cross-fades on each step (reduced-motion
       safe). Just the fun quote here — full roster + photos + bios on /about#team.
       Data + shuffle live in the staffDeck() Alpine component in index.html;
       names/roles/quotes mirror the team roster in pages/about.html (its the source of truth). */
    /* ── Homepage staff deck — a 'flip through' stack of tilted POLAROIDS.
       Stripped to just the switcher: prev/next arrows flank one polaroid
       (person photo + name—role caption), the fun quote sits below. Tilt
       alternates per step so it feels like riffling a stack. If a person has a
       'fun' photo (currently only Carolyn), a small flip button swaps it.
       Data + shuffle: staffDeck() in index.html; mirrors the team roster in pages/about.html. */
    .v3-staffdeck__stage { display: flex; align-items: center; justify-content: center; gap: 14px; }
    .v3-staffdeck__nav { flex: 0 0 auto; }
    .v3-polaroid {
      position: relative; cursor: pointer;
      flex: 0 0 auto; width: 300px; max-width: min(70vw, 320px);
      background: #fff; padding: 14px 14px 0; border-radius: 2px;
      box-shadow: 0 12px 28px rgba(38,64,104,0.18);
      transition: transform 0.22s ease, opacity 0.16s ease;
    }
    .v3-polaroid__link { display: block; text-decoration: none; color: inherit; }
    .v3-polaroid:hover { box-shadow: 0 16px 34px rgba(38,64,104,0.24); }
    .v3-polaroid.tilt-0 { transform: rotate(2deg); }   /* first card (i=0) leans clockwise */
    .v3-polaroid.tilt-1 { transform: rotate(-1.7deg); }
    .v3-polaroid.is-fading { opacity: 0; }
    .v3-polaroid__photo { display: block; position: relative; aspect-ratio: 1 / 1; overflow: hidden; background: #e6edf4; }
    .v3-polaroid__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .v3-polaroid__flip {
      position: absolute; right: 22px; bottom: 60px; z-index: 2; cursor: pointer;
      font-family: var(--font-sans); font-size: 0.68rem; font-weight: 700;
      letter-spacing: 0.02em; color: #264068; background: rgba(255,255,255,0.92);
      border: 0; border-radius: 999px; padding: 4px 10px; box-shadow: 0 2px 6px rgba(38,64,104,0.22);
    }
    .v3-polaroid__flip:hover { background: #fff; }
    .v3-polaroid__flip:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 2px; }
    .v3-polaroid__cap { display: block; padding: 14px 6px 18px; text-align: center; font-family: var(--font-sans); }
    .v3-polaroid__name { font-weight: 700; color: #264068; font-size: 1.04rem; }
    .v3-polaroid__sep { color: var(--color-border-strong); margin: 0 7px; }
    .v3-polaroid__role { color: var(--color-ink-muted); font-size: 0.84rem; } /* muted token = #5B6B7A → 5.48:1 on white (AA; #6b7a90 was 4.36) */
    .v3-staffdeck__quote {
      margin: 26px auto 0; max-width: 30em; text-align: center; padding-bottom: 0;
      font-family: var(--font-display); font-style: italic; color: #264068;
      font-size: clamp(1.2rem, 2.6vw, 1.7rem); line-height: 1.3; font-weight: 400;
      transition: opacity 0.16s ease;
    }
    .v3-staffdeck__quote.is-fading { opacity: 0; }
    .v3-staffdeck__quote::before { content: '\201C'; color: var(--color-brand-soft); }
    .v3-staffdeck__quote::after { content: '\201D'; color: var(--color-brand-soft); }
    @media (max-width: 480px) {
      .v3-staffdeck__stage { gap: 7px; }
      .v3-staffdeck__nav { width: 40px; height: 40px; }
      .v3-polaroid { max-width: 64vw; }
    }
    /* ── Office tour — polaroid-framed click-to-play video. Mirrors v2 .office-tour
       with v3 tokens. Streams from R2; Alpine swaps poster → <video> on play, and
       the frame straightens (.is-playing) instead of staying tilted. ── */
    .v3-office-tour {
      max-width: 680px; margin: 0 auto;
      background: #fff; padding: 14px 14px 0; border-radius: 2px;
      box-shadow: 0 12px 28px rgba(38,64,104,0.18);
      transform: rotate(-1.4deg);
      transition: transform 0.22s ease, box-shadow 0.22s ease;
    }
    .v3-office-tour:hover,
    .v3-office-tour:focus-within,
    .v3-office-tour.is-playing {
      transform: rotate(0deg); box-shadow: 0 16px 34px rgba(38,64,104,0.24);
    }
    .v3-office-tour__media {
      position: relative; aspect-ratio: 16 / 9; overflow: hidden;
      background: #e6edf4; border-radius: 2px;
    }
    .v3-office-tour__media img,
    .v3-office-tour__media video {
      position: absolute; inset: 0; z-index: 0;
      width: 100%; height: 100%; object-fit: cover; border: 0; display: block;
    }
    .v3-office-tour__btn {
      position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
      background: transparent; border: 0; padding: 0; cursor: pointer;
      transition: background 0.2s ease;
    }
    .v3-office-tour__btn::after { /* hover tint, above poster, below play circle */
      content: ""; position: absolute; inset: 0; z-index: 1;
      background: transparent; transition: background 0.2s ease;
    }
    .v3-office-tour__btn:hover::after,
    .v3-office-tour__btn:focus-visible::after { background: rgba(38,64,104,0.12); }
    /* A103 (WCAG 2.4.7). The button is `inset: 0` inside .v3-office-tour__media, which clips
       to `overflow: hidden` — so ANY ring with a positive outline-offset, including the
       browser's own default, is clipped away and a keyboard user sees nothing before the
       video is played. Same failure as A100: draw it INSIDE. Two-tone because what's behind
       it is a photograph — a single colour is only guaranteed to contrast against part of
       it. The white outline hugs the edge (0–3px in); the navy inset shadow shows through
       just beneath it (3–6px in). */
    .v3-office-tour__btn:focus-visible {
      outline: 3px solid #fff;
      outline-offset: -3px;
      box-shadow: inset 0 0 0 6px rgba(38,64,104,0.9);
    }
    .v3-office-tour__play {
      position: relative; z-index: 2; width: 76px; height: 76px; border-radius: 50%;
      background: rgba(255,255,255,0.94); box-shadow: 0 6px 18px rgba(38,64,104,0.3);
      display: flex; align-items: center; justify-content: center;
      transition: transform 0.2s ease, background 0.2s ease;
    }
    .v3-office-tour__btn:hover .v3-office-tour__play,
    .v3-office-tour__btn:focus-visible .v3-office-tour__play { transform: scale(1.08); background: #fff; }
    .v3-office-tour__play::after { /* play triangle */
      content: ""; margin-left: 5px; border-style: solid;
      border-width: 13px 0 13px 22px; border-color: transparent transparent transparent #264068;
    }
    .v3-office-tour__cap { padding: 14px 8px 18px; text-align: center; font-family: var(--font-sans); }
    .v3-office-tour__cap-title { display: block; color: #264068; font-family: var(--font-display); font-size: 1.15rem; }
    .v3-office-tour__cap-sub { display: block; margin-top: 2px; color: var(--color-ink-muted); font-size: 0.84rem; }
    @media (prefers-reduced-motion: reduce) { .v3-office-tour { transform: none; } }
    /* ── Featured post — one highlighted blog post, polaroid-flavored:
       white frame, soft offset shadow, a whisker of tilt that straightens on
       hover. The "cover" is a soft branded tile (posts have no hero yet); swap
       in a real image later. */
    .v3-featured { padding: clamp(var(--space-8), 5vw, var(--space-12)) 0; }
    /* Featured blog card — the "More than teeth" box look (.v3-tcard: tag · serif
       title · excerpt · "Read the post") at hero scale. Inherits the base
       .v3-tcard hard left offset shadow (rest -6px 5px, hover -8px 8px) so it
       matches the treatment-card scroller exactly — no separate shadow here.
       The original polaroid-spine card lives commented-out in index.html. */
    .v3-tcard--featured {
      max-width: var(--w-read); margin: 0 auto; gap: 14px; padding: 34px 38px;
    }
    /* pretty, not balance: long featured titles should fill the line, not split
       into two stubby half-width lines (balance leaves ~45% right-side whitespace). */
    .v3-tcard--featured .v3-tcard__name { font-size: clamp(1.5rem, 3vw, 2.1rem); line-height: 1.15; text-wrap: pretty; }
    .v3-tcard--featured .v3-tcard__desc { font-size: 1.05rem; line-height: 1.55; }
    .v3-tcard--featured .v3-featured__meta { margin: -4px 0 2px; }
    @media (max-width: 620px) { .v3-tcard--featured { padding: 26px 24px; } }
    .v3-featured__card {
      display: grid; grid-template-columns: 10px 1fr;
      max-width: var(--w-read); margin: 0 auto; background: #fff;
      border-radius: var(--radius-sm); overflow: hidden; color: inherit; text-decoration: none; border: 0;
      box-shadow: 0 14px 32px rgba(38,64,104,0.16);
      transition: transform 0.22s ease, box-shadow 0.22s ease;
    }
    .v3-featured__card:hover { box-shadow: 0 20px 40px rgba(38,64,104,0.22); border: 0; } /* rise comes from .v3-lift */
    .v3-featured__card:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 3px; }
    /* 10px blue spine — the only decoration; no filler text */
    .v3-featured__accent { background: linear-gradient(180deg, var(--color-brand), var(--color-brand-soft)); }
    /* Plain variant — same polaroid card, no left spine (used for the blog list). */
    .v3-featured__card--plain { grid-template-columns: 1fr; }
    .v3-featured__body { display: flex; flex-direction: column; gap: 9px; padding: 26px 32px; }
    .v3-featured__title { font-family: var(--font-display); font-weight: 400; font-size: clamp(1.35rem, 2.6vw, 1.85rem); line-height: 1.18; color: #264068; margin: 0; }
    /* Byline meta row — one even flex gap (0.6em) drives [date · avatar · name]
       plus an optional leading draft badge. The SAME 0.6em sits on the meta row
       AND the inner .v3-byline, so date→avatar and avatar→name are identical;
       drop the avatar and it collapses to an even date→name, no placeholder. */
    .v3-featured__meta { font-family: var(--font-sans); font-size: 0.8rem; display: flex; align-items: center; flex-wrap: wrap; gap: 0.6em; row-gap: 4px; }
    .v3-featured__date { color: #264068; font-weight: 700; } /* bold so it reads distinct from the muted author, not a faint color shift */
    .v3-featured__author { color: var(--color-ink-muted); } /* muted token passes AA; spacing is the flex gap, not a margin */
    /* Byline = avatar + name as one flex unit. An <a> to /about#<slug> on post
       pages; a plain <span> on cards (the whole card is already the link). */
    .v3-byline { display: inline-flex; align-items: center; gap: 0.6em; vertical-align: middle; }
    .v3-byline__avatar { width: 22px; height: 22px; border-radius: 50%; object-fit: contain; box-sizing: border-box; padding: 2px; flex: 0 0 auto; display: block; background: #e6edf4; } /* tooth logo, full mark visible inside the circle */
    a.v3-byline:hover .v3-featured__author { text-decoration: underline; text-underline-offset: 2px; }
    .v3-featured__excerpt { font-family: var(--font-display); font-size: 1.05rem; line-height: 1.5; color: #3a4a63; margin: 0; }
    .v3-featured__cta { font-family: var(--font-sans); font-weight: 700; font-size: 0.9rem; letter-spacing: 0.03em; color: #264068; padding-top: 4px; }
    /* "Read the post" arrow — same draw-in mask as .v3-tcard__cta (mdi:arrow-right) */
    .v3-featured__cta::after {
      content: ''; display: inline-block; vertical-align: -0.06em;
      width: 0; height: 0.78em; margin-left: 0; opacity: 0;
      background-color: currentColor;
      -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z'/%3E%3C/svg%3E") no-repeat left center / 1.05em 0.78em;
      mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z'/%3E%3C/svg%3E") no-repeat left center / 1.05em 0.78em;
      transition: width 0.3s cubic-bezier(0.45,0,0.25,1), margin-left 0.3s cubic-bezier(0.45,0,0.25,1), opacity 0.22s ease;
    }
    .v3-featured__card:hover .v3-featured__cta::after { width: 1.05em; margin-left: 0.4em; opacity: 1; }
    @media (max-width: 620px) { .v3-featured__body { padding: 22px 22px; } }
    @media (prefers-reduced-motion: reduce) { .v3-polaroid, .v3-staffdeck__quote, .v3-featured__card, .v3-featured__cta::after { transition: none; } }
