/* ============================================================================
   WALLET 2026  -  shared stylesheet for the wallet.inc corporate rebuild
   ----------------------------------------------------------------------------
   Extracted from the landing-page design system (icp-landing-pages/free-wallet
   .html et al.) so the corporate site and the marketing fleet share one look.
   Served outside the gulp bundle so it cannot collide with the legacy CSS.

   The four-stage lifecycle is the spine:
     Visitor    . Attract  . amber  #dfa30b
     Subscriber . Engage   . orange #e99353
     Customer   . Motivate . teal   #6da7b9
     Member     . Reward   . green  #80b73e

   Chrome (this page) stays in Wallet's own identity. A merchant brand (skin)
   only ever appears inside the phone mockup. No em dashes anywhere.
   ========================================================================== */
:root{
  --attract:#dfa30b;  --attract-soft:#fbf0d3;
  --excite:#e99353;   --excite-soft:#fbe5d7;
  --motivate:#6da7b9; --motivate-soft:#dcebef;
  --reward:#80b73e;   --reward-soft:#e3f0d2;

  --ink:#16181d;      --ink-2:#3a3f49;
  --muted:#6b7280;    --faint:#9aa1ad;
  --bg:#ffffff;       --surface:#faf8f4;  --surface-2:#f3f0ea;
  --line:#ececec;     --line-2:#e0ddd6;

  --maxw:1140px;
  --radius:18px;      --radius-lg:26px;
  --shadow-sm:0 1px 2px rgba(22,24,29,.05), 0 4px 14px rgba(22,24,29,.04);
  --shadow:0 8px 30px rgba(22,24,29,.08), 0 2px 8px rgba(22,24,29,.05);
  --shadow-lg:0 30px 70px rgba(22,24,29,.16), 0 8px 24px rgba(22,24,29,.08);

  --ease:cubic-bezier(.22,.61,.36,1);
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  font-family:'Poppins',system-ui,sans-serif;
  color:var(--ink);
  background:var(--bg);
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
/* height:auto is a SAFETY NET, not decoration. Every img on the site carries
   width/height attributes (correctly, they reserve layout space and prevent
   shift). But max-width:100% alone caps the WIDTH while the height attribute
   keeps its literal value, so any image narrower than its intrinsic size
   renders squashed. Without this, every image depends on some later rule
   remembering height:auto, and the one that forgets is distorted in a way that
   looks like a bad export rather than a CSS bug. Belt and braces, once. */
img,svg{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 24px}
.eyebrow{
  font-size:.74rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);display:inline-flex;align-items:center;gap:.55em;
}
.eyebrow::before{content:"";width:22px;height:2px;border-radius:2px;background:var(--attract)}
h1,h2,h3{line-height:1.1;letter-spacing:-.02em;font-weight:700}
h2{font-size:clamp(1.7rem,3.4vw,2.6rem);margin-bottom:.5em}
.lead{font-size:clamp(1.02rem,1.6vw,1.18rem);color:var(--ink-2);font-weight:400}
section{padding:clamp(64px,9vw,118px) 0}

/* ---- buttons ---- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  padding:.85em 1.5em;border-radius:999px;font-weight:600;font-size:.98rem;
  border:1.5px solid transparent;transition:transform .18s var(--ease),box-shadow .18s var(--ease),background .18s;
  white-space:nowrap;
}
.btn-primary{background:var(--ink);color:#fff;box-shadow:var(--shadow)}
.btn-primary:hover{transform:translateY(-2px);box-shadow:var(--shadow-lg)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line-2)}
.btn-ghost:hover{border-color:var(--ink);transform:translateY(-2px)}
.btn-lg{padding:1.02em 1.9em;font-size:1.04rem}
.btn svg{width:18px;height:18px}

/* lifecycle rail - recurring 4-color spine motif */
.spine{display:flex;height:5px;border-radius:5px;overflow:hidden;width:100%}
.spine i{flex:1}
.spine .s1{background:var(--attract)} .spine .s2{background:var(--excite)}
.spine .s3{background:var(--motivate)} .spine .s4{background:var(--reward)}

/* =========================== NAV =========================== */
header.nav{
  position:sticky;top:0;z-index:60;background:rgba(255,255,255,.82);
  backdrop-filter:saturate(180%) blur(14px);border-bottom:1px solid var(--line);
}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:68px}
.brand{display:flex;align-items:center;gap:.6em}
.brand .logo{height:28px;width:auto}
.foot-brand .logo{height:24px}
.nav-links{display:flex;align-items:center;gap:8px}
.nav-links > a,
.nav-item > button{
  font-size:.93rem;color:var(--ink-2);font-weight:500;background:transparent;border:0;
  padding:.5em .7em;border-radius:10px;display:inline-flex;align-items:center;gap:.35em;
}
.nav-links > a:hover,
.nav-item > button:hover{color:var(--ink);background:var(--surface-2)}
.nav-item{position:relative}
.nav-item > button .car{width:9px;height:9px;transition:transform .2s var(--ease)}
.nav-item.open > button .car{transform:rotate(180deg)}
.nav-menu{
  position:absolute;top:calc(100% + 8px);left:0;min-width:240px;background:#fff;
  border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);
  padding:8px;opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .16s var(--ease),transform .16s var(--ease),visibility .16s;
}
.nav-item.open .nav-menu{opacity:1;visibility:visible;transform:none}
.nav-menu a{display:block;font-size:.9rem;color:var(--ink-2);padding:.55em .7em;border-radius:9px}
.nav-menu a:hover{background:var(--surface);color:var(--ink)}
.nav-menu.cols{min-width:430px;display:grid;grid-template-columns:1fr 1fr;gap:2px}
.nav-cta{display:flex;align-items:center;gap:14px}
.nav-cta .login{font-size:.93rem;color:var(--ink-2);font-weight:500}
.nav-cta .login:hover{color:var(--ink)}
.nav-toggle{display:none;background:transparent;border:0;width:42px;height:42px;border-radius:10px}
.nav-toggle:hover{background:var(--surface-2)}
.nav-toggle svg{width:24px;height:24px;margin:0 auto;color:var(--ink)}
@media(max-width:980px){
  .nav-links{display:none}
  .nav-cta .login{display:none}
  .nav-toggle{display:block}
}

/* =========================== HERO =========================== */
.hero{padding-top:clamp(48px,7vw,86px);position:relative;overflow:hidden}
.hero::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:
    radial-gradient(60% 50% at 78% 8%,var(--attract-soft) 0%,transparent 60%),
    radial-gradient(50% 50% at 12% 30%,var(--motivate-soft) 0%,transparent 55%);
  opacity:.7;
}
.hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:54px;align-items:center}
.hero h1{font-size:clamp(2.3rem,5.2vw,3.65rem);font-weight:800;margin:.34em 0 .42em}
/* The highlight used to be `white-space:nowrap` plus an absolutely-positioned
   ::after. The nowrap was there for the ::after, not for the design: one
   absolute rectangle spanning left to right only reads correctly while the
   phrase sits on a single line. The cost was that the longest highlighted
   phrases walked off the side of a real handset (/link-shortener at 24
   characters, /entertainment-and-attractions at 22, /service-providers at 19).
   That failure is silent: nothing scrolls, nothing reports overflow, the words
   are simply not on screen. Headless Chrome hides it too, because it clamps the
   window to 500px while real phones are 390, 375 and 360.

   Painting the highlight as a background on the inline box instead lets the
   phrase wrap, and box-decoration-break:clone gives each wrapped fragment its
   own strip rather than one rectangle stretched across both lines. The
   padding/negative-margin pair reproduces the old -.04em bleed per fragment,
   and dropping the z-index:-1 hack means the highlight can no longer fall
   behind an ancestor's background in a new stacking context.
   Reported by owner-cs, KAN-901. */
.hero h1 .hl{
  position:relative;
  padding:0 .04em;margin:0 -.04em;
  border-radius:3px;
  background:linear-gradient(90deg,var(--attract-soft),var(--excite-soft)) no-repeat;
  background-size:100% .34em;
  background-position:0 calc(100% - .06em);
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
}
.hero .lead{max-width:31em;margin-bottom:1.9em}
.hero-actions{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.hero-note{margin-top:1.4em;font-size:.86rem;color:var(--muted);display:flex;flex-wrap:wrap;align-items:center;gap:.5em}
.hero-note svg{width:16px;height:16px;color:var(--reward);flex:none}
/* `.hero-stage{order:-1}` used to live here, so on one column the phone mockup
   came first. It arrived with the original /v2 scaffold (a0a4493) rather than
   from a Design ruling, and it costs the whole mobile first screen: the stage is
   a full phone plus the "Demo brands" chip plus its caption, which pushes the
   eyebrow, H1, lead and the in-hero CTA about a screen and a half down. A phone
   visitor's first screen carried a picture and no proposition. Source order is
   already copy then stage, so dropping the override is the entire fix, and it
   fixes all seventeen pages that use .hero-stage at once. Desktop is unchanged;
   it is two columns and never consulted `order`. Reported by owner-cs, KAN-901. */
@media(max-width:900px){.hero-grid{grid-template-columns:1fr;gap:40px}}

/* ====================== PHONE MOCKUP ======================= */
/* Modern-iPhone proportions: body ~2.08:1, screen 19.5:9, island + home indicator */
/* LEGACY phone, scoped. These rules predate owner-design's Phone-Hero Pack and
   carry the drift its acceptance checklist calls out (1/2.08 not 9/19.5, 46px
   not 48px, #0c0c10 not #0b0c0f, a side-button pseudo-element, perspective on
   the stage). They are now scoped to `.phone-stage .phone`, which ONLY the /v2
   homepage's cycling reskin demo uses, so they cannot leak into `.ph-hero`.
   When the homepage migrates onto the pack, delete this block outright rather
   than fixing the numbers: the pack is the source of truth for the phone. */
.phone-stage{display:flex;justify-content:center;perspective:1400px}
.phone-stage .phone{
  width:300px;aspect-ratio:1/2.08;background:#0c0c10;border-radius:46px;
  padding:13px;position:relative;box-shadow:var(--shadow-lg);
  border:1.5px solid #2a2a30;
}
.phone-stage .phone::after{ /* side button hint */
  content:"";position:absolute;right:-2px;top:148px;width:2.5px;height:58px;border-radius:2px;background:#3a3a42;
}
.screen{
  position:relative;width:100%;height:100%;border-radius:34px;overflow:hidden;
  background:#101018;
}
.phone-stage .island{
  position:absolute;top:11px;left:50%;transform:translateX(-50%);
  width:88px;height:26px;background:#000;border-radius:16px;z-index:8;
}
.phone-stage .home-ind{
  position:absolute;bottom:8px;left:50%;transform:translateX(-50%);
  width:118px;height:5px;border-radius:5px;background:rgba(255,255,255,.55);z-index:8;
}

/* ===========================================================
   MERCHANT SKIN  (white-label) - scoped ONLY inside the phone.
   This is the MERCHANT's brand, NOT Wallet's. On the corporate page the
   skin cycles through three FICTIONAL demo brands across industries to show
   "one platform, fully your brand, any business." Clearly framed as a demo
   via the "Your brand here" pill.
   =========================================================== */
.skin{
  /* Fallbacks only. A .skin-* class supplies the real authored values; these
     keep the component renderable if a page forgets one. Design's dictionary
     (--s-hd/--s-on/--s-accent/--s-accent2/--s-page/--s-ink/--s-mut/--s-soft/
     --s-card/--s-tile/--s-ov) is authoritative and must not be redefined here.
     Two names below are LOCAL to this mockup component and are deliberately
     NOT in Design's schema: --s-hd-2 (gradient partner for the brand block)
     and --s-on-mut (muted text ON the dark brand block; Design's --s-mut is
     muted text on the light page, a different job). --s-surface is the
     translucent row fill; it is NOT Design's --s-card, which is #fff. */
  --s-accent:#dfa30b; --s-accent2:#a4521f;
  --s-hd:#1a1530;
  --s-on:#f6f3ff;
  --s-hd-2:color-mix(in srgb,var(--s-hd) 80%,#ffffff);
  --s-on-mut:color-mix(in srgb,var(--s-on) 62%,transparent);
  --s-surface:rgba(255,255,255,.06);
  position:absolute;inset:0;color:var(--s-on);
  background:
    radial-gradient(120% 70% at 80% -5%,color-mix(in srgb,var(--s-accent) 32%,transparent),transparent 55%),
    linear-gradient(170deg,var(--s-hd-2),var(--s-hd) 62%);
  font-size:13px;display:flex;flex-direction:column;
  padding:46px 18px 24px;transition:background .5s var(--ease);
}
.skin .s-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px}
.skin .s-avatar{
  width:60px;height:60px;border-radius:18px;
  background:linear-gradient(135deg,var(--s-accent),var(--s-accent2));
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.3rem;color:#22141f;
  box-shadow:0 6px 20px color-mix(in srgb,var(--s-accent) 45%,transparent);
  transition:background .5s var(--ease);
}
/* Active Memberships drawer affordance (top-right), PRODUCT TRUTH: the shipped
   wallet is guest-owned and multi-merchant, and this icon switches the whole
   wallet to another merchant. Required in accurate mockups per the 2026 design
   lock, section 4. Static in mockups; the drawer itself is not recreated. */
.skin .s-drawer{
  position:absolute;top:14px;right:14px;width:30px;height:30px;border-radius:10px;
  display:flex;align-items:center;justify-content:center;
  background:var(--s-surface);border:1px solid rgba(255,255,255,.12);color:var(--s-on);
}
.skin .s-drawer svg{width:15px;height:15px}
.skin .s-drawer .badge{
  position:absolute;top:-3px;right:-3px;width:9px;height:9px;border-radius:50%;
  background:var(--s-accent2);border:2px solid var(--s-hd);transition:background .5s var(--ease);
}
.skin .s-name{font-weight:700;font-size:1.02rem;letter-spacing:-.01em}
.skin .s-tagline{color:var(--s-on-mut);font-size:.76rem;margin-top:-3px}
.skin .s-links{display:flex;flex-direction:column;gap:9px;margin-top:16px}
.skin .s-link{
  display:flex;align-items:center;gap:10px;border-radius:12px;padding:11px 13px;
  background:var(--s-surface);border:1px solid rgba(255,255,255,.07);font-weight:500;font-size:.82rem;
}
.skin .s-link .dot{width:8px;height:8px;border-radius:50%;background:var(--s-accent);flex:none;transition:background .5s var(--ease)}
.skin .s-link.is-feature{
  background:linear-gradient(100deg,color-mix(in srgb,var(--s-accent2) 20%,transparent),color-mix(in srgb,var(--s-accent) 12%,transparent));
  border-color:color-mix(in srgb,var(--s-accent2) 42%,transparent);
}
.skin .s-qr{
  margin-top:14px;display:flex;align-items:center;gap:11px;border-radius:12px;padding:11px 13px;
  background:var(--s-surface);border:1px solid rgba(255,255,255,.07);
}
.skin .s-qr .qr{width:38px;height:38px;border-radius:8px;background:#fff;padding:4px;flex:none}
.skin .s-qr .qr svg{width:100%;height:100%;color:#101018}
.skin .s-qr .qt{font-size:.74rem;line-height:1.3}
.skin .s-qr .qt b{font-size:.8rem}
.skin .s-foot{margin-top:auto;text-align:center;font-size:.62rem;color:var(--s-on-mut);opacity:.85;padding-top:12px}

/* ===========================================================
   DEMO SKINS - owner-design's Wallet-screen variant kit (KAN-658).

   Per that kit's partial contract: "Skins are class-scoped variable sets
   (.skin-*), nothing else." So brand values live here and pages carry only a
   class, never an inline style. Header/Accent/Page hex values are Design's
   verbatim, all nine authored tokens per brand, nothing derived by us
   rather than invented, so Design stays the single source of the brand hexes.

   The lifecycle dot colors are canonical noun tokens and are never skinned.

   STILL PLACEHOLDERS. Meridian and Northside are the ledger's standing demo
   set; Harlow & Thread, Starlight Amphitheater, Hillcrest Market, Juniper &
   Sage Spa and Harborview Hotel were introduced by the kit. John rules on the
   fleet-wide demo-brand set before any of this deploys.
   =========================================================== */
/* Design's authored blocks, verbatim from the approved seven-brand set. Schema
   is the one ratified in the Wallet Composition Contract (Confluence 29163536
   section 4): --s-* is the Design-authoring alias that compiles to --wallet-*
   on the product side, so mockups and portal read one dictionary. Do not
   re-derive these values; if a hex looks wrong, it is Design's to change. */
.skin-northside {--s-hd:#3b2a20;--s-on:#f6ead9;--s-accent:#c98a4b;--s-accent2:#8f5a26;--s-page:#faf6f0;--s-ink:#33281f;--s-mut:#8d8378;--s-soft:#f1e6d8;--s-card:#fff;--s-tile:#f6ead9;--s-ov:rgba(43,29,20,.8)}
.skin-meridian  {--s-hd:#15202e;--s-on:#f2ead8;--s-accent:#c9a227;--s-accent2:#8a6f16;--s-page:#f4f4f6;--s-ink:#1d2530;--s-mut:#7b8494;--s-soft:#e9e4d2;--s-card:#fff;--s-tile:#f2ead8;--s-ov:rgba(21,32,46,.82)}
.skin-harlow    {--s-hd:#5c3a47;--s-on:#f9ecef;--s-accent:#d8a3b0;--s-accent2:#93596b;--s-page:#faf5f6;--s-ink:#3d2e34;--s-mut:#95848a;--s-soft:#f3e2e7;--s-card:#fff;--s-tile:#f9ecef;--s-ov:rgba(92,58,71,.78);--s-pos:20% center}
.skin-starlight {--s-hd:#1d1836;--s-on:#efe9fb;--s-accent:#e8b64c;--s-accent2:#a67818;--s-page:#f5f4f8;--s-ink:#242038;--s-mut:#847e99;--s-soft:#ebe7f5;--s-card:#fff;--s-tile:#efe9fb;--s-ov:rgba(29,24,54,.8)}
.skin-hillcrest {--s-hd:#24422c;--s-on:#eff5e9;--s-accent:#d9a441;--s-accent2:#94691b;--s-page:#f6f8f3;--s-ink:#25332a;--s-mut:#7f8b7c;--s-soft:#e7efdf;--s-card:#fff;--s-tile:#eff5e9;--s-ov:rgba(36,66,44,.8)}
.skin-juniper   {--s-hd:#4a5b44;--s-on:#f2f6ee;--s-accent:#a8bf9a;--s-accent2:#5e7355;--s-page:#f7faf5;--s-ink:#32402e;--s-mut:#84907e;--s-soft:#e8efe2;--s-card:#fff;--s-tile:#f2f6ee;--s-ov:rgba(74,91,68,.78);--s-pos:center 30%}
.skin-harborview{--s-hd:#223744;--s-on:#eef3f5;--s-accent:#b98d4f;--s-accent2:#84642f;--s-page:#f4f6f7;--s-ink:#243239;--s-mut:#7d8a91;--s-soft:#e5ebee;--s-card:#fff;--s-tile:#eef3f5;--s-ov:rgba(34,55,68,.82)}

/* ===========================================================
   WALLET SCREEN VARIANTS - recreated UI, per design lock s5
   ("Recreated UI (HTML/CSS/SVG) for every interactive and hero moment").

   One component set; each industry page picks the screen that argues its
   own point, so the seven heroes differ by MOMENT rather than by brand
   string alone. Every variant is product-true against the CS Product
   Surfaces pass (Confluence 26804233) and its Guest Wallet page (27590657).

   Rendered by views/partials/wallet-body-*.hbs, dropped inside .skin
   beneath the brand header. Motion plays once and is killed wholesale by
   the prefers-reduced-motion block at the end of this file (lock s6).
   =========================================================== */

/* Shared redeemable card. PRODUCT TRUTH: every redeemable follows one
   pattern, a designed card with "Tap to show code" and a QR on the reverse. */
.skin .s-card{
  margin-top:14px;border-radius:14px;padding:13px;
  background:linear-gradient(135deg,color-mix(in srgb,var(--s-accent) 26%,transparent),color-mix(in srgb,var(--s-accent2) 16%,transparent));
  border:1px solid color-mix(in srgb,var(--s-accent) 40%,transparent);
}
.skin .s-card .c-label{font-size:.62rem;letter-spacing:.09em;text-transform:uppercase;color:var(--s-on-mut)}
.skin .s-card .c-value{font-size:1.72rem;font-weight:800;letter-spacing:-.02em;line-height:1.1;margin-top:2px}
.skin .s-card .c-sub{font-size:.72rem;color:var(--s-on-mut);margin-top:3px}
.skin .s-tap{
  margin-top:10px;text-align:center;font-size:.68rem;font-weight:600;color:var(--s-on-mut);
  border-top:1px dashed rgba(255,255,255,.16);padding-top:9px;
}

/* Dynamic Voucher decay. PRODUCT TRUTH: value visibly decays over time
   ("This offer loses $0.10 every 3 Hour(s)"), with a live refresh ring and
   a running redemption count. The sharpest differentiator in the product. */
.skin .s-decay{display:flex;align-items:center;gap:11px;margin-top:11px}
.skin .s-ring{
  width:34px;height:34px;border-radius:50%;flex:none;position:relative;
  background:conic-gradient(var(--s-accent) 0turn,var(--s-accent) .72turn,rgba(255,255,255,.14) .72turn);
  animation:s-ring-once 1.5s var(--ease) .3s 1 both;
}
.skin .s-ring::after{
  content:"";position:absolute;inset:5px;border-radius:50%;
  background:linear-gradient(170deg,var(--s-hd-2),var(--s-hd));
}
@keyframes s-ring-once{from{background:conic-gradient(var(--s-accent) 0turn,rgba(255,255,255,.14) 0turn)}}
.skin .s-decay .d-text{font-size:.68rem;line-height:1.35;color:var(--s-on-mut)}
.skin .s-decay .d-text b{color:var(--s-on);font-size:.72rem}

/* QR reverse of a card (the tap-to-flip state). */
.skin .s-qrback{
  margin-top:14px;border-radius:14px;padding:15px;text-align:center;
  background:rgba(255,255,255,.94);color:#101018;
}
.skin .s-qrback .qbig{width:96px;height:96px;margin:0 auto;display:block}
.skin .s-qrback .qcap{font-size:.66rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;margin-top:9px;color:#3a3f49}

/* Simple listed items (tickets, passes, saved offers). */
.skin .s-list{display:flex;flex-direction:column;gap:8px;margin-top:13px}
.skin .s-row{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  border-radius:11px;padding:10px 12px;background:var(--s-surface);border:1px solid rgba(255,255,255,.07);
}
.skin .s-row .r-main{font-size:.76rem;font-weight:600}
.skin .s-row .r-sub{font-size:.65rem;color:var(--s-on-mut);margin-top:1px}
.skin .s-row .r-tag{
  font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;flex:none;
  color:var(--s-hd);background:var(--s-accent);border-radius:999px;padding:.25em .6em;
}

/* Membership tier card. PRODUCT TRUTH: a tier is a merchant-defined named
   discount percentage with its own artwork, not a fixed Bronze/Silver ladder. */
.skin .s-tier{
  margin-top:14px;border-radius:14px;padding:14px;
  background:linear-gradient(135deg,color-mix(in srgb,var(--s-accent2) 30%,transparent),color-mix(in srgb,var(--s-accent) 14%,transparent));
  border:1px solid color-mix(in srgb,var(--s-accent2) 45%,transparent);
}
.skin .s-tier .t-name{font-size:1.12rem;font-weight:800;letter-spacing:-.01em}
.skin .s-tier .t-perk{font-size:.72rem;color:var(--s-on-mut);margin-top:2px}
.skin .s-tier .t-dots{display:flex;gap:5px;margin-top:11px}
.skin .s-tier .t-dots i{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.28)}
.skin .s-tier .t-dots i.on{background:var(--s-accent)}

/* The product's own HOSPITALITY page set. PRODUCT TRUTH: Gaming, Dining,
   Lounges, Rooms & Rates and Amenities sit behind an explicit HOSPITALITY
   divider in Wallet Configuration > Navigation Menu. Merchants outside
   hospitality do not see them, so this variant is for hotel/gaming only. */
.skin .s-set{display:flex;flex-direction:column;gap:7px;margin-top:13px}
.skin .s-set .set-label{font-size:.58rem;letter-spacing:.12em;text-transform:uppercase;color:var(--s-on-mut);margin-bottom:1px}
.skin .s-set .set-item{
  display:flex;align-items:center;gap:9px;border-radius:10px;padding:9px 11px;
  background:var(--s-surface);border:1px solid rgba(255,255,255,.07);font-size:.76rem;font-weight:500;
}
.skin .s-set .set-item .dot{width:7px;height:7px;border-radius:50%;background:var(--s-accent);flex:none}

/* "Your brand here" pill near the phone (chrome, not skin) */
.skin-tag{
  display:inline-flex;align-items:center;gap:.5em;margin-top:18px;font-size:.74rem;font-weight:600;
  color:var(--ink-2);background:#fff;border:1px solid var(--line-2);border-radius:999px;padding:.45em .9em;box-shadow:var(--shadow-sm);
}
.skin-tag .d{width:8px;height:8px;border-radius:50%;background:var(--attract)}

/* skin toggle */
.phone-toggle{
  display:inline-flex;background:var(--surface-2);border-radius:999px;padding:4px;margin-top:16px;gap:2px;
  border:1px solid var(--line-2);
}
.phone-toggle button{
  border:0;background:transparent;padding:.5em 1.05em;border-radius:999px;font-size:.82rem;font-weight:600;color:var(--muted);
  transition:all .2s var(--ease);
}
.phone-toggle button.active{background:#fff;color:var(--ink);box-shadow:var(--shadow-sm)}
/* Reassurance line under a hero CTA (KAN-823). Deliberately quiet: it should
   reassure at the point of commitment without competing with the CTA itself. */
.hero-privacy{margin-top:.55rem;font-size:.78rem;color:var(--faint)}
.hero-privacy a{color:var(--muted);text-decoration:underline;text-underline-offset:2px}
.hero-privacy a:hover{color:var(--ink-2)}

/* Center the phone in its hero column.
   .ph-hero comes from owner-design's pack and sets no display, so its .phone
   child (a fixed 300px block) sat hard against the LEFT edge of .hero-stage
   while .toggle-wrap below it centered itself. That mismatch read as a large
   unexplained gap on the right of the hero. Reported by John 2026-08-21.

   Applied to .ph-hero ITSELF, not to a parent. Two reasons. Setting it on
   .hero-stage would catch that stage's other children, including full-width
   ones (.tool-shot on the QR page), and a column flex with align-items:center
   would shrink those to their content width. And scoping it to one parent only
   fixes the containers we happen to use today: .ph-hero also appears inside
   .otp-visual and .wl-stage on the homepage, and will appear in whatever
   container the next page introduces. Centring the pack's own wrapper makes it
   correct everywhere by construction rather than per page. Fixed here rather than in phone-hero.css because that file is
   pack-owned and regenerated by build-pack.ps1, so an edit there would be lost
   at the next re-sync. */
.ph-hero{display:flex;justify-content:center}

.toggle-wrap{display:flex;flex-direction:column;align-items:center}
.toggle-cap{font-size:.78rem;color:var(--muted);margin-top:.7em;text-align:center;max-width:19em}

/* =================== AS FEATURED ON (logo strip) =========== */
.featured{padding:clamp(40px,5vw,60px) 0;background:var(--surface);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.featured .cap{text-align:center;font-size:.74rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
/* Real press logos as of 2026-07-29 (cleared, design lock s9). Tighter gap than
   the five text placeholders needed, since there are twelve of them. Desaturated
   at rest so a wall of network logos reads as quiet proof instead of competing
   with the lifecycle palette; full color on hover. */
.logo-strip{
  list-style:none;margin:26px 0 0;padding:0;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:14px clamp(20px,3.5vw,40px);
}
.logo-strip li{display:flex;align-items:center}
.logo-strip img{
  height:clamp(38px,4.4vw,54px);width:auto;display:block;
  filter:grayscale(1);opacity:.55;
  transition:filter .25s var(--ease),opacity .25s var(--ease);
}
.logo-strip li:hover img{filter:grayscale(0);opacity:1}
/* Legacy text placeholders; kept until no view references .ph-logo. */
.logo-strip .ph-logo{
  font-weight:800;font-size:1.1rem;letter-spacing:.02em;color:var(--faint);
  filter:grayscale(1);opacity:.65;
}
.featured .strip-note{display:flex;justify-content:center;margin-top:22px}

/* shared placeholder flag (reused across sections) */
.ph-flag{display:inline-block;font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#b45309;background:#fff7ed;border:1px dashed #f59e0b;border-radius:6px;padding:.2em .5em}

/* ======================= FOUR PILLARS ===================== */
.pillars-head{max-width:38em}
.pillars-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-top:42px}
.pillar{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:26px 22px;box-shadow:var(--shadow-sm);border-top:3px solid var(--line-2)}
.pillar .ic{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;margin-bottom:15px}
.pillar .ic svg{width:23px;height:23px}
.pillar h3{font-size:1.08rem;margin-bottom:.35em}
.pillar p{font-size:.9rem;color:var(--muted)}
.pillar.p1{border-top-color:var(--attract)}  .pillar.p1 .ic{background:var(--attract-soft);color:#8a6406}
.pillar.p2{border-top-color:var(--excite)}   .pillar.p2 .ic{background:var(--excite-soft);color:#a4521f}
.pillar.p3{border-top-color:var(--motivate)} .pillar.p3 .ic{background:var(--motivate-soft);color:#2f6473}
.pillar.p4{border-top-color:var(--reward)}   .pillar.p4 .ic{background:var(--reward-soft);color:#4a7016}
@media(max-width:860px){.pillars-grid{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.pillars-grid{grid-template-columns:1fr}}

/* =================== LIFECYCLE WALKTHROUGH ================ */
.life{background:var(--ink);color:#fff;position:relative;overflow:hidden}
.life .eyebrow{color:rgba(255,255,255,.6)} .life .eyebrow::before{background:var(--excite)}
.life h2{color:#fff} .life .lead{color:rgba(255,255,255,.72)}
.life-head{max-width:36em}
.stages{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:42px}
.stage{
  position:relative;text-align:left;border-radius:var(--radius);padding:22px 20px 24px;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);
  transition:transform .25s var(--ease),background .25s,border-color .25s;
}
.stage:hover{transform:translateY(-4px);background:rgba(255,255,255,.07)}
.stage .num{font-size:.74rem;font-weight:600;color:rgba(255,255,255,.45);letter-spacing:.1em}
.stage .verb{font-size:.78rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-top:14px}
.stage h3{font-size:1.28rem;margin:.15em 0 .4em;color:#fff}
.stage p{font-size:.87rem;color:rgba(255,255,255,.66);line-height:1.5}
.stage .bar{height:4px;border-radius:4px;width:46px;margin-bottom:18px}
.stage.v1 .bar{background:var(--attract)} .stage.v1 .verb{color:var(--attract)}
.stage.v2 .bar{background:var(--excite)}  .stage.v2 .verb{color:var(--excite)}
.stage.v3 .bar{background:var(--motivate)}.stage.v3 .verb{color:var(--motivate)}
.stage.v4 .bar{background:var(--reward)}  .stage.v4 .verb{color:var(--reward)}
@media(max-width:860px){.stages{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.stages{grid-template-columns:1fr}}

/* ===================== OTP / NO-APP ======================= */
.otp-grid{display:grid;grid-template-columns:.95fr 1.05fr;gap:54px;align-items:center}
.otp-steps{display:grid;gap:18px;margin-top:30px}
.otp-step{display:flex;gap:16px;align-items:flex-start}
.otp-step .n{
  width:34px;height:34px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:.92rem;background:var(--surface-2);color:var(--ink);
}
.otp-step:nth-child(1) .n{background:var(--attract-soft);color:#8a6406}
.otp-step:nth-child(2) .n{background:var(--excite-soft);color:#a4521f}
.otp-step:nth-child(3) .n{background:var(--reward-soft);color:#4a7016}
.otp-step h4{font-size:1rem;margin-bottom:.1em}
.otp-step p{font-size:.9rem;color:var(--muted)}
.otp-visual{display:flex;justify-content:center}

/* WHITE LABEL (section grammar position 7). Composition d from the Phone-Hero
   Pack; the toggle drives PhoneHero.setBrand, so this CSS styles only the
   chrome around the phone, never the phone itself. */
.whitelabel{padding:clamp(64px,8vw,92px) 0;background:var(--surface)}
.wl-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:54px;align-items:center}
.wl-stage{display:flex;flex-direction:column;align-items:center;gap:16px}
.wl-toggle{display:flex;flex-wrap:wrap;gap:8px;margin-top:26px}
.wl-toggle button{
  font:inherit;font-size:.82rem;font-weight:600;cursor:pointer;
  color:var(--ink-2);background:#fff;border:1px solid var(--line-2);
  border-radius:999px;padding:.5em 1.05em;
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease);
}
.wl-toggle button:hover{border-color:var(--ink-2)}
.wl-toggle button.active{background:var(--ink);border-color:var(--ink);color:#fff}
@media(max-width:900px){
  .wl-grid{grid-template-columns:1fr;gap:36px}
}
.sms{
  width:300px;background:#fff;border-radius:var(--radius-lg);box-shadow:var(--shadow);
  border:1px solid var(--line);padding:20px;
}
.sms .bubble{background:var(--surface);border-radius:16px;border-top-left-radius:4px;padding:13px 15px;font-size:.9rem;max-width:88%}
.sms .code{font-size:1.5rem;font-weight:700;letter-spacing:.18em;margin-top:6px}
.sms .meta{font-size:.72rem;color:var(--faint);margin-top:14px;text-align:center}
@media(max-width:900px){.otp-grid{grid-template-columns:1fr;gap:36px}}

/* ===================== VALUE LADDER ======================= */
/* hub-and-spoke: the tools that serve each stage (Visitors -> Members) */
.ladder{background:var(--surface)}
.ladder-head{max-width:38em}
.ladder-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-top:44px;align-items:stretch}
.rung{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:24px 22px;box-shadow:var(--shadow-sm);border-top:3px solid var(--line-2)}
.rung .who-tag{font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;display:flex;align-items:center;gap:.45em;margin-bottom:6px}
.rung .who-tag .d{width:9px;height:9px;border-radius:50%}
.rung h3{font-size:1.16rem;margin-bottom:.15em}
.rung .verb{font-size:.82rem;font-weight:600;margin-bottom:14px}
.rung ul{list-style:none;display:grid;gap:9px;margin-top:auto}
.rung li{font-size:.84rem;color:var(--ink-2);display:flex;gap:9px;align-items:flex-start}
.rung li svg{width:15px;height:15px;flex:none;margin-top:.25em}
.rung.r1{border-top-color:var(--attract)}  .rung.r1 .who-tag,.rung.r1 .verb{color:#8a6406} .rung.r1 .who-tag .d{background:var(--attract)} .rung.r1 li svg{color:var(--attract)}
.rung.r2{border-top-color:var(--excite)}   .rung.r2 .who-tag,.rung.r2 .verb{color:#a4521f} .rung.r2 .who-tag .d{background:var(--excite)}  .rung.r2 li svg{color:var(--excite)}
.rung.r3{border-top-color:var(--motivate)} .rung.r3 .who-tag,.rung.r3 .verb{color:#2f6473} .rung.r3 .who-tag .d{background:var(--motivate)}.rung.r3 li svg{color:var(--motivate)}
.rung.r4{border-top-color:var(--reward)}   .rung.r4 .who-tag,.rung.r4 .verb{color:#4a7016} .rung.r4 .who-tag .d{background:var(--reward)}  .rung.r4 li svg{color:var(--reward)}
@media(max-width:860px){.ladder-grid{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.ladder-grid{grid-template-columns:1fr}}

/* ============ WHY NOT A GENERIC LOYALTY PROGRAM =========== */
.venn-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:54px;align-items:center}
.venn{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:14px;max-width:430px;margin:0 auto}
.venn .quad{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:20px 18px;box-shadow:var(--shadow-sm);text-align:center}
.venn .quad .ic{width:38px;height:38px;border-radius:11px;display:flex;align-items:center;justify-content:center;margin:0 auto 10px}
.venn .quad .ic svg{width:20px;height:20px}
.venn .quad h4{font-size:.96rem;margin-bottom:.2em}
.venn .quad p{font-size:.78rem;color:var(--muted)}
.venn .q1 .ic{background:var(--attract-soft);color:#8a6406}
.venn .q2 .ic{background:var(--excite-soft);color:#a4521f}
.venn .q3 .ic{background:var(--motivate-soft);color:#2f6473}
.venn .q4 .ic{background:var(--reward-soft);color:#4a7016}
.venn .hub{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:3;
  width:96px;height:96px;border-radius:50%;background:var(--ink);color:#fff;
  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
  box-shadow:var(--shadow-lg);border:4px solid #fff;
}
.venn .hub .logo{height:18px;width:auto}
.venn .hub small{font-size:.58rem;color:rgba(255,255,255,.7);margin-top:3px;letter-spacing:.04em}
@media(max-width:900px){.venn-grid{grid-template-columns:1fr;gap:40px}}

/* ======================= INTEGRATION ====================== */
.integrate{background:var(--ink);color:#fff;position:relative;overflow:hidden}
.integrate .eyebrow{color:rgba(255,255,255,.6)} .integrate .eyebrow::before{background:var(--motivate)}
.integrate h2{color:#fff} .integrate .lead{color:rgba(255,255,255,.72)}
.integrate-grid{display:grid;grid-template-columns:1fr 1fr;gap:54px;align-items:center}
.int-chips{display:flex;flex-wrap:wrap;gap:12px;margin-top:8px}
.int-chip{font-size:.84rem;font-weight:500;color:#fff;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);border-radius:999px;padding:.55em 1.05em}
.int-card{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.12);border-radius:var(--radius-lg);padding:30px 28px}
.int-card .badge{font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--motivate);margin-bottom:12px}
.int-card h3{color:#fff;font-size:1.3rem;margin-bottom:.4em}
.int-card p{color:rgba(255,255,255,.72);font-size:.92rem}
.int-card .btn{margin-top:18px;background:#fff;color:var(--ink)}
@media(max-width:900px){.integrate-grid{grid-template-columns:1fr;gap:34px}}

/* ====================== PROOF BAND ======================== */
/* PRIZE MOMENT (gamification), section grammar 11a. Renders on /v2 as of
   2026-07-31 (V2_IS_PREVIEW in server.js); still gated on any published route
   until both compliance flags open. Section chrome only; the phone inside is
   owner-design's and brings its own. */
.prize{background:var(--surface);text-align:center}
.prize .pillars-head{margin:0 auto}
.prize-stage{display:flex;justify-content:center;margin-top:40px;perspective:none}
.prize-fine{margin-top:26px;font-size:.78rem;color:var(--faint);line-height:1.5}

/* The .prize-preview-banner and .prize-fine-pending rules were removed
   2026-07-31 with the warning chrome they styled. The gate did not move; it is
   in server.js. Do not reintroduce a visible placeholder for Legal's rules text:
   an empty space is the honest state, a convincing placeholder is not. */
/* TEMPORARY, remove when pack v5 lands. Requested from [owner-design] on
   KAN-658. This supersedes the styling fix that was here: there is no point
   styling a line that should not exist.

   PRODUCT TRUTH, confirmed by John 2026-07-30: the shipped guest wallet does
   NOT show Wallet's industry taxonomy anywhere on a merchant's own pages. The
   ONLY guest-facing use is the multi-merchant menu (the Active Memberships
   panel), where merchants are GROUPED by industry so a guest can switch between
   them. The pack's homepage-drawer partial already models that correctly with
   its dr-cat group headers, and it is deliberately untouched here.

   So the category line under the merchant name inside a wallet is an INVENTED
   SURFACE, the same class of error Design caught on the creators draft with
   follower counts in the guest header. It is also a chrome-vs-skin violation:
   it is Wallet's vocabulary in the merchant's storefront, and the merchant
   cannot even set it (Domain Branding exposes logo, headline, subtext, byline
   and colors, with no industry field).

   Five partials render it: meridian, starlight, harborview (page heroes),
   otp-unlock and prize-wheel. Scoped to .m-id on purpose, which leaves
   remivale's <i>@remivale</i> alone: that lives in .d-brand and is the
   creator's own handle, not our taxonomy. */
.ph-hero .m-id i{display:none}

/* ============ FREE-TOOL PAGES (Tier 1, 2026-08-01) ============
   Three components the industry pages do not use: the free/paid note, the FAQ,
   and the "more free tools" cross-link strip. Section chrome only; everything
   above them reuses the existing .hero / .integrate / .life / .otp / .pillars
   sections unchanged, which is why this block is short.

   FAQ and the cross-link strip are NOT positions in the locked 12-section
   grammar (28934145). They are load-bearing for a page whose job is to rank, so
   they are added after the value ladder and before the CTA, preserving the
   existing order above them. Flagged to [owner-design] for a ruling rather than
   assumed; if the grammar gains them formally, only the comment changes. */

/* The free/paid reassurance under the "what's free" grid. Deliberately quiet:
   it is a boundary statement, not a pitch. Trial SPECIFICS (length, card,
   auto-downgrade) must not appear here until owner-api confirms them (KAN-695). */
.free-note{
  margin:30px auto 0;max-width:44em;text-align:center;
  font-size:.86rem;color:var(--muted);line-height:1.6;
}

/* FAQ. Native <details> so it works with no JS and stays keyboard accessible;
   the marker is replaced with a drawn chevron rather than hidden entirely. */
.faq{background:var(--surface)}
.faq-list{max-width:760px;margin:40px auto 0}
.faq-item{
  border-bottom:1px solid var(--line-2);
}
.faq-item summary{
  list-style:none;cursor:pointer;padding:20px 40px 20px 0;position:relative;
  font-weight:600;font-size:1.02rem;color:var(--ink);
}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary::after{
  content:"";position:absolute;right:8px;top:50%;width:9px;height:9px;
  border-right:2px solid var(--faint);border-bottom:2px solid var(--faint);
  transform:translateY(-70%) rotate(45deg);transition:transform .25s var(--ease);
}
.faq-item[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq-item summary:hover{color:var(--ink-2)}
.faq-item p{padding:0 40px 22px 0;margin:0;color:var(--muted);line-height:1.65}

/* Cross-link strip. Whole card is the link, so the label is decoration rather
   than a second tab stop. */
.tools-more{background:var(--bg)}
.tools-grid{
  display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:40px;
}
.tool-card{
  display:block;text-decoration:none;color:inherit;
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);padding:30px 28px;
  transition:transform .3s var(--ease),box-shadow .3s var(--ease),border-color .3s var(--ease);
}
.tool-card:hover{
  transform:translateY(-3px);box-shadow:var(--shadow);border-color:var(--line-2);
}
.tool-card .ic{
  width:40px;height:40px;border-radius:11px;background:var(--surface-2);
  display:flex;align-items:center;justify-content:center;margin-bottom:16px;
}
.tool-card .ic svg{width:19px;height:19px}
.tool-card h3{margin:0 0 8px;font-size:1.1rem}
.tool-card p{margin:0;color:var(--muted);line-height:1.6;font-size:.94rem}
.tool-go{
  display:inline-block;margin-top:16px;font-size:.86rem;font-weight:600;
  color:var(--motivate);
}
.tool-card:hover .tool-go{text-decoration:underline}

/* Minimal legal footer for layouts/standalone-2026.hbs. Landing pages carry no
   site navigation, but a page that collects an email or a phone number still
   needs privacy, terms and cookie links. Quiet on purpose: this is compliance
   furniture, not a second navigation surface. */
.foot-min{
  border-top:1px solid var(--line);background:var(--surface);
  padding:38px 0 42px;text-align:center;
}
.foot-min .brand{display:inline-block;opacity:.55}
.foot-min .logo{height:24px;width:auto}
.foot-min-legal{
  display:flex;flex-wrap:wrap;gap:8px 22px;justify-content:center;margin:18px 0 14px;
}
.foot-min-legal a{
  color:var(--muted);font-size:.84rem;text-decoration:none;
}
.foot-min-legal a:hover{color:var(--ink-2);text-decoration:underline}
.foot-min-copy{
  margin:0 auto;max-width:52em;color:var(--faint);font-size:.78rem;line-height:1.6;
}

/* The free-tools index shows all three at once; the per-page strips show two. */
.tools-grid-3{grid-template-columns:repeat(3,1fr)}

@media(max-width:900px){
  .tools-grid-3{grid-template-columns:1fr 1fr}
}
@media(max-width:760px){
  .tools-grid,.tools-grid-3{grid-template-columns:1fr}
}

.proof{text-align:center}
.proof .quotes{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:42px}

.qcard{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:26px 24px;box-shadow:var(--shadow-sm);text-align:left}
.qcard p{font-size:.96rem;color:var(--ink-2);line-height:1.55}
.qcard .who-q{display:flex;align-items:center;gap:11px;margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.qcard .av{width:38px;height:38px;border-radius:50%;background:var(--surface-2);display:flex;align-items:center;justify-content:center;font-weight:700;color:var(--ink-2);font-size:.9rem}
.qcard .who-q b{font-size:.88rem} .qcard .who-q span{font-size:.78rem;color:var(--muted);display:block}
.qcard .ph-flag{margin-bottom:10px}
@media(max-width:860px){.proof .quotes{grid-template-columns:1fr}}

/* ====================== FINAL CTA ========================= */
.cta{position:relative;overflow:hidden;background:var(--ink);color:#fff;text-align:center}
.cta .spine{max-width:340px;margin:0 auto 28px}
.cta h2{color:#fff;font-size:clamp(1.9rem,4vw,2.8rem)}
.cta p{color:rgba(255,255,255,.74);max-width:31em;margin:.6em auto 1.9em}
.cta .btn-primary{background:#fff;color:var(--ink)}
.cta .btn-ghost{color:#fff;border-color:rgba(255,255,255,.3)}
.cta .btn-ghost:hover{border-color:#fff}

/* ====================== FOOTER ============================ */
footer{background:var(--surface);border-top:1px solid var(--line);padding:54px 0 40px}
.foot-grid{display:flex;justify-content:space-between;gap:30px;flex-wrap:wrap;align-items:flex-start}
.foot-brand{max-width:23em}
.foot-brand p{font-size:.86rem;color:var(--muted);margin-top:12px}
.foot-contact{font-size:.84rem;color:var(--ink-2);margin-top:16px;line-height:1.7}
.foot-contact a{color:var(--ink-2)} .foot-contact a:hover{color:var(--ink)}
.foot-cols{display:flex;gap:48px;flex-wrap:wrap}
.foot-col h5{font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);margin-bottom:12px;font-weight:600}
.foot-col a{display:block;font-size:.9rem;color:var(--ink-2);margin-bottom:9px}
.foot-col a:hover{color:var(--ink)}
.foot-social{display:flex;gap:12px;margin-top:6px}
.foot-social a{width:36px;height:36px;border-radius:10px;border:1px solid var(--line-2);display:flex;align-items:center;justify-content:center;color:var(--ink-2);background:#fff}
.foot-social a:hover{color:var(--ink);border-color:var(--ink)}
.foot-social svg{width:18px;height:18px}
.foot-badges{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-top:26px}
.foot-badges img{height:40px;width:auto;opacity:.85}
.foot-bottom{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-top:34px;padding-top:22px;border-top:1px solid var(--line);font-size:.8rem;color:var(--faint)}
.foot-bottom .legal{display:flex;gap:16px;flex-wrap:wrap}
.foot-bottom .legal a{color:var(--faint)} .foot-bottom .legal a:hover{color:var(--ink-2)}

/* ============ PLATFORM FEATURE GALLERY (partials/features-2026) ===========
   The nine admin-portal feature pages. Alternating full-width rows rather than
   a card grid: these descriptions run several sentences with embedded <br/>,
   which is exactly what the legacy three-up grid could not hold (it cropped the
   screenshot to 200px and let the copy overflow out of sight).

   The screenshots are real product UI at assorted aspect ratios, so the frame
   never crops. It sizes to the image and carries a border, because a browser
   screenshot on a white page needs an edge to read as a screenshot rather than
   as part of the layout.
   ========================================================================== */
.featgal{background:var(--surface);padding-top:clamp(56px,7vw,92px)}
.fg-group + .fg-group{margin-top:clamp(56px,7vw,96px)}
.fg-head{max-width:760px;margin:0 0 clamp(28px,4vw,46px)}
.fg-head h2{font-size:clamp(1.5rem,2.6vw,2.1rem);line-height:1.2;letter-spacing:-.02em;margin-top:.5rem}

.fg-row{
  display:grid;grid-template-columns:1.05fr .95fr;
  gap:clamp(28px,4vw,56px);align-items:center;
}
.fg-row + .fg-row{margin-top:clamp(40px,5vw,72px)}
/* Alternate which side the screenshot sits on, so a long page does not become a
   single column of identical rows. Reversing the COLUMN rather than reordering
   the DOM keeps reading order correct for a screen reader and for tabbing. */
.fg-row:nth-child(even) .fg-shotwrap{order:2}

.fg-shot{
  display:block;width:100%;padding:0;border:1px solid var(--line-2);
  background:var(--bg);border-radius:var(--radius);overflow:hidden;
  box-shadow:var(--shadow-sm);position:relative;
  transition:box-shadow .35s var(--ease),transform .35s var(--ease);
}
.fg-shot:hover{box-shadow:var(--shadow);transform:translateY(-3px)}
.fg-shot:focus-visible{outline:3px solid var(--motivate);outline-offset:3px}
.fg-shot img{width:100%;height:auto}

/* The zoom affordance only appears on hover or keyboard focus: on a page that is
   mostly screenshots, twelve permanent badges is noise. */
.fg-zoom{
  position:absolute;right:12px;bottom:12px;width:34px;height:34px;
  display:grid;place-items:center;border-radius:50%;
  background:rgba(22,24,29,.82);color:#fff;
  opacity:0;transition:opacity .3s var(--ease);
}
.fg-zoom svg{width:17px;height:17px}
.fg-shot:hover .fg-zoom,.fg-shot:focus-visible .fg-zoom{opacity:1}

.fg-copy .fg-chip{
  display:inline-block;font-size:.72rem;font-weight:600;letter-spacing:.04em;
  padding:.32em .8em;border-radius:999px;
  background:var(--motivate-soft);color:#2c5766;
}
.fg-copy .fg-sub{
  display:block;margin-top:.85rem;font-size:.74rem;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
}
.fg-copy h3{font-size:clamp(1.15rem,1.9vw,1.5rem);line-height:1.28;letter-spacing:-.015em;margin-top:.4rem}
.fg-desc{margin-top:.9rem;color:var(--ink-2);font-size:.975rem}
.fg-desc br{content:"";display:block;margin-bottom:.6rem}

@media(max-width:900px){
  .fg-row{grid-template-columns:1fr;gap:22px}
  /* Cancel the alternation on one column: with the image always first, an odd
     row would otherwise push its screenshot BELOW its own copy. */
  .fg-row:nth-child(even) .fg-shotwrap{order:0}
}

/* ---- Lightbox (native <dialog>, no library) ----
   The dialog is a full-viewport stage and the CONTENT is centered inside it.
   Do not switch this to centring the dialog itself with margin:auto: the
   global reset at the top of this file sets *{margin:0}, which cancels the
   user-agent margin:auto that a modal <dialog> centers with, and the image
   lands in the top-left corner. Centring the child does not depend on a UA
   default that a reset can quietly undo. */
.fg-lightbox{
  border:0;padding:0;background:transparent;color:#fff;
  width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;
  overflow:visible;
}
/* Only when open: a bare display:grid would defeat the UA's
   dialog:not([open]){display:none} and leave it on screen permanently. */
.fg-lightbox[open]{display:grid;place-items:center}
.fg-lightbox::backdrop{background:rgba(12,13,16,.88)}

.fg-box{position:relative;max-width:min(1200px,92vw)}
.fg-lightbox img{
  width:100%;height:auto;max-height:82dvh;object-fit:contain;
  border-radius:var(--radius);background:#fff;box-shadow:var(--shadow-lg);
}
.fg-lightcap{margin-top:.85rem;text-align:center;font-size:.92rem;color:#e8e9ec}
.fg-close{
  position:absolute;top:-14px;right:-14px;width:38px;height:38px;
  display:grid;place-items:center;border:0;border-radius:50%;
  background:#fff;color:var(--ink);box-shadow:var(--shadow);
}
.fg-close svg{width:19px;height:19px}
.fg-close:focus-visible{outline:3px solid var(--motivate);outline-offset:2px}
@media(max-width:600px){.fg-close{top:6px;right:6px}}

/* Feature-page hero: no phone stage, so the copy is a single measured column
   rather than the industry pages' two-column hero-grid. */
.feat-hero-copy{max-width:760px}

/* Composed hero art (owner-design's QR kit). Deliberately UNFRAMED: unlike the
   feature-gallery screenshots, this art carries its own background and its own
   drop shadow on the code, so a border and a card shadow would double up and
   read as a screenshot of a screenshot. Just size it and center it. */
/* "Your code, your brand" strip (QR page). Eight per-merchant codes proving the
   branding claim the section above makes. Each tile is square art on its own
   pale field, so tiles get no border or shadow: the art already reads as an
   object and a frame around a frame reads as a screenshot. */
.brandstrip{background:var(--surface)}
.bs-grid{
  list-style:none;display:grid;gap:clamp(14px,2vw,24px);
  grid-template-columns:repeat(4,1fr);margin-top:clamp(28px,4vw,44px);
}
.bs-grid img{width:100%;height:auto;border-radius:var(--radius)}
.bs-note{margin-top:1.4em;font-size:.78rem;color:var(--faint);text-align:center}
@media(max-width:860px){.bs-grid{grid-template-columns:repeat(2,1fr)}}

/* COLLAPSE THE BOUNDARY BETWEEN TWO TRANSPARENT SECTIONS.
   Reported by John as "a huge gap of white space in the middle of the page".

   Every section carries clamp(64px,9vw,118px) top and bottom. Where sections
   alternate background (dark .life, .integrate; tinted .faq, .brandstrip) that
   padding reads as breathing room around a visible edge. But .otp and .pillars
   are both transparent and sit next to each other on the three free-tool pages,
   so their padding stacks into ~236px of unbroken white at 1440 with no edge to
   justify it. It reads as a rendering fault rather than as spacing.

   Halved at the seam rather than removed: the two sections are still distinct
   arguments and need separating, they just do not need separating twice. */
.otp + .pillars{padding-top:clamp(8px,1vw,18px)}

/* UTM tip aside (link shortener). Deliberately set apart from the main flow:
   a card on the surface tint, narrower measure, so an operator's eye skips it
   and a marketer's stops. It is optional reading by design. */
.utmtip{padding-top:0}
.tip-card{
  max-width:760px;margin:0 auto;padding:clamp(24px,3vw,36px);
  background:var(--surface);border:1px solid var(--line-2);border-radius:var(--radius-lg);
}
.tip-card h3{font-size:clamp(1.1rem,1.8vw,1.4rem);margin:.5rem 0 .8rem}
.tip-card p + p{margin-top:.8em}
.tip-card p{color:var(--ink-2);font-size:.96rem}
.tip-card code{
  background:var(--surface-2);border:1px solid var(--line-2);border-radius:6px;
  padding:.12em .4em;font-size:.88em;word-break:break-all;
}

/* Free-versus-paid link comparison (link shortener). Two rows, same shape, so
   the only thing that changes between them is the domain. That is the whole
   point being made, and a table would bury it in chrome. */
.owndomain{background:var(--surface)}
.domain-compare{max-width:620px;margin:clamp(28px,4vw,40px) auto 0;display:grid;gap:12px}
.dc-row{
  display:flex;align-items:center;gap:14px;
  padding:.9em 1.1em;background:var(--bg);
  border:1px solid var(--line-2);border-radius:var(--radius);
}
.dc-row code{font-size:1.02rem;font-weight:600;color:var(--ink)}
.dc-tag{
  font-size:.68rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  padding:.3em .7em;border-radius:999px;flex:none;
}
.dc-free .dc-tag{background:var(--attract-soft);color:#8a6406}
.dc-paid .dc-tag{background:var(--reward-soft);color:#4a7016}

/* "Where it can point" section (QR page). Answers the flexibility objection
   with the product's own Target field rather than with a sentence. The art is
   wide and type-heavy, so it gets a readable measure rather than full bleed. */
.destination{background:var(--surface)}
.dest-art{position:relative;max-width:880px;margin:clamp(28px,4vw,44px) auto 0}
.dest-art img{width:100%;height:auto;display:block}

/* Replay control, used by BOTH animated figures (hero and destination field).
   Quiet by default and only revealed by JS once the animation has actually run,
   so a no-JS reader never sees a button that would do nothing. */
.qr-hero{position:relative}
.qr-replay{
  position:absolute;right:14px;bottom:14px;
  display:inline-flex;align-items:center;gap:.45em;
  padding:.45em .9em;border:1px solid var(--line-2);border-radius:999px;
  background:rgba(255,255,255,.9);backdrop-filter:blur(6px);
  font-size:.78rem;font-weight:600;color:var(--ink-2);
  opacity:0;transition:opacity .25s var(--ease),transform .25s var(--ease);
}
.qr-hero:hover .qr-replay,.dest-art:hover .qr-replay,.qr-replay:focus-visible{opacity:1}
.qr-replay:hover{color:var(--ink);transform:translateY(-1px)}
.qr-replay svg{width:14px;height:14px}
.qr-replay:focus-visible{outline:3px solid var(--motivate);outline-offset:2px}
/* Touch has no hover, so never hide it there. */
@media(hover:none){.qr-replay{opacity:1}}

/* No border-radius any more. It was a workaround for the v1 art, which shipped
   on a flat #faf8f4 field that read as a pasted rectangle against the hero
   gradient. owner-design's v2 export is genuinely transparent, so the hero
   gradient now runs behind the art as intended and a radius would only clip
   the soft drop shadows the transparency exists to preserve. */
.qr-hero{margin:0}
.qr-hero img{width:100%;height:auto;display:block}

/* The QR hero art is a wide two-object composition (1108x865), so this page
   gives the stage the larger share of the grid rather than the copy. A first
   attempt bled the stage out to the viewport edge; that made the art enormous
   and cropped the phone off the right, so it is a plain wider column instead.

   Not the default 1.05fr/.95fr: at that split the art lands near 500px, which
   puts the phone around 145px and makes its screen unreadable, which defeats
   the reason for showing the phone at all. */
.qr-hero-grid{grid-template-columns:.92fr 1.08fr;gap:40px;align-items:center}
@media(max-width:900px){
  .qr-hero-grid{grid-template-columns:1fr}
}

/* Stacked hero: copy at a readable measure, then a full-width stage beneath.
   Used instead of .hero-grid when the stage is a wide screenshot rather than a
   phone, because a portal screenshot squeezed into a half-width column is
   illegible at the exact moment the page is asking you to look at it. */
.hero-stack{display:block}
.hero-stack .hero-copy{max-width:720px}
.hero-stack .hero-stage{margin-top:clamp(34px,4.5vw,56px)}
.hero-stack .toggle-wrap{margin-top:18px;max-width:760px}

/* ====================== MOTION (restrained, play-once) ==== */
.reveal{opacity:0;transform:translateY(18px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.reveal.in{opacity:1;transform:none}
.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}
.reveal.d3{transition-delay:.24s}.reveal.d4{transition-delay:.32s}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important;scroll-behavior:auto!important}
  .reveal{opacity:1;transform:none}
}

/* ================================================================
   COMPANY + CERTIFICATION PAGES (2026), added 2026-08-25 (KAN-87).

   The last eleven legacy pages (awards, press room, compliance, downloads,
   meet-us and the six certification pages) were the only surfaces still
   rendering Bootstrap rows inside the old layout. They are content pages
   rather than industry pages, so they use a small shared kit here instead of
   the 12-position industry grammar: a plain card grid, a comparison table, a
   logo directory, and an embed frame. Nothing below is page-specific; every
   one of these classes is used by at least two of the eleven.
   ================================================================ */

/* --- Compact page hero. No phone stage: none of these pages has a product
       shot worth half the fold, and a borrowed one would be decoration. --- */
.pagehero{padding:clamp(52px,7vw,88px) 0 clamp(30px,4vw,44px);position:relative;overflow:hidden}
.pagehero::before{
  content:"";position:absolute;inset:0 0 auto;height:100%;
  background:radial-gradient(900px 380px at 12% -12%,var(--attract-soft),transparent 62%);
  opacity:.5;pointer-events:none
}
.pagehero .wrap{position:relative}
.pagehero-copy{max-width:44em}
.pagehero h1{font-size:clamp(2.1rem,4.4vw,3.1rem);font-weight:800;margin:.34em 0 .38em;letter-spacing:-.02em}
.pagehero .lead{max-width:36em}
.pagehero .hero-actions{margin-top:1.7em}

/* Breadcrumb. The legacy pages all carried one and it is genuinely useful on
   a nested URL like /certification/agencies, so it survives the migration. */
.crumbs{display:flex;flex-wrap:wrap;gap:.5em;align-items:center;font-size:.82rem;color:var(--faint);margin-bottom:.2em}
.crumbs a{color:var(--muted)}
.crumbs a:hover{color:var(--ink)}
.crumbs li{list-style:none;display:flex;align-items:center;gap:.5em}
.crumbs li + li::before{content:"";width:4px;height:4px;border-radius:50%;background:var(--line-2);flex:none}
.crumbs .here{color:var(--ink-2);font-weight:500}

/* --- Generic content-card grid. Column count is set per section with a
       modifier so one rule serves compliance (4-up), sponsorships (3-up) and
       downloads (2-up), and all of them collapse the same way. --- */
.cmp-grid{display:grid;gap:18px;margin-top:clamp(28px,4vw,44px)}
.cmp-2{grid-template-columns:repeat(2,1fr)}
.cmp-3{grid-template-columns:repeat(3,1fr)}
.cmp-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:1000px){.cmp-4{grid-template-columns:repeat(2,1fr)}}
@media(max-width:860px){.cmp-3{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.cmp-2,.cmp-3,.cmp-4{grid-template-columns:1fr}}

.cmp-card{
  display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);
  border-radius:var(--radius);padding:24px 22px;box-shadow:var(--shadow-sm)
}
.cmp-card .cmp-mark{height:52px;width:auto;max-width:100%;object-fit:contain;object-position:left center;margin-bottom:16px}
.cmp-card h3{font-size:1.05rem;margin:0 0 .4em;letter-spacing:-.01em}
.cmp-card p{font-size:.9rem;color:var(--muted);line-height:1.6}
.cmp-card p + p{margin-top:.7em}
.cmp-card .cmp-foot{margin-top:auto;padding-top:16px}
.cmp-card a.cmp-go{font-size:.86rem;font-weight:600;color:var(--ink)}
.cmp-card a.cmp-go:hover{text-decoration:underline}

/* Card variant that leads with a wordmark rather than a heading: press
   outlets and partner logos. Centered, because a logo has no reading order. */
.cmp-card.is-logo{align-items:center;text-align:center}
.cmp-card.is-logo .cmp-mark{object-position:center;margin-bottom:18px}

/* --- Section head, reused by every one of these pages. --- */
.sec-head{max-width:40em}
.sec-head + .cmp-grid{margin-top:clamp(24px,3.4vw,38px)}

/* --- Certification tier stack. Four tiers, each a full-width block rather
       than a card, because each carries a paragraph of overview plus a
       requirements paragraph and four of those side by side are unreadable. --- */
.tierstack{display:grid;gap:16px;margin-top:clamp(28px,4vw,44px)}
.tier-block{
  background:#fff;border:1px solid var(--line);border-left:4px solid var(--line-2);
  border-radius:var(--radius);padding:26px 26px;box-shadow:var(--shadow-sm)
}
.tier-block .tier-top{display:flex;flex-wrap:wrap;gap:12px;align-items:baseline;justify-content:space-between}
.tier-block h3{font-size:1.2rem;margin:0;letter-spacing:-.01em}
.tier-block .tier-avail{font-size:.74rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.tier-block .tier-lab{font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:.5em}
.tier-block p{font-size:.92rem;color:var(--ink-2);line-height:1.65;margin-top:.8em}
.tier-block p b{color:var(--ink)}
.tier-t1{border-left-color:var(--reward)}   .tier-t1 .tier-lab{color:#4a7016}
.tier-t2{border-left-color:var(--attract)}  .tier-t2 .tier-lab{color:#8a6406}
.tier-t3{border-left-color:var(--motivate)} .tier-t3 .tier-lab{color:#2f6473}
.tier-t4{border-left-color:var(--excite)}   .tier-t4 .tier-lab{color:#a4521f}

/* --- Comparison table. A real table element, not a grid of divs: the legacy
       build used Bootstrap columns, which meant a screen reader read every
       cell as an unlabeled fragment and a narrow screen stacked the ticks
       away from the rows they belonged to. Scoped headers fix both. It
       scrolls inside its own wrapper so the page body never scrolls
       sideways. --- */
.ctable-wrap{overflow-x:auto;margin-top:clamp(28px,4vw,44px);border:1px solid var(--line);border-radius:var(--radius);background:#fff;box-shadow:var(--shadow-sm)}
.ctable{width:100%;min-width:720px;border-collapse:collapse;font-size:.9rem}
.ctable th,.ctable td{padding:13px 16px;text-align:center;border-bottom:1px solid var(--line)}
.ctable thead th{background:var(--surface)}
.ctable td:first-child{text-align:left}
.ctable tbody th[scope="row"]{text-align:left;color:var(--ink-2);font-weight:400}
.ctable .ct-group th{
  background:var(--ink);color:#fff;text-align:left;font-size:.76rem;
  letter-spacing:.1em;text-transform:uppercase;padding:12px 16px
}
.ctable .ct-tier{min-width:132px}
.ctable .ct-tier .ct-name{display:block;font-size:1.02rem;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.ctable .ct-tier .ct-avail{display:block;font-size:.68rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-top:3px}
.ctable .ct-bar{display:block;height:4px;border-radius:4px;margin:0 auto 10px;width:34px}
.ct-t1 .ct-bar{background:var(--reward)} .ct-t2 .ct-bar{background:var(--attract)}
.ct-t3 .ct-bar{background:var(--motivate)} .ct-t4 .ct-bar{background:var(--excite)}
.ctable tbody tr:hover td,.ctable tbody tr:hover th[scope="row"]{background:var(--surface)}
.ctable .ct-yes{color:#4a7016;font-weight:700}
.ctable .ct-no{color:var(--line-2)}
.ctable .ct-note{font-size:.8rem;color:var(--muted)}
/* --- Scroll hint. MOVED ABOVE THE TABLE 2026-08-27 (KAN-865).

       It used to sit after the table. owner-cs' review reported "no swipe hint"
       and they were right in every way that counts: the hint existed, but it
       was below a 720px-wide, screen-tall table, so a phone reader met the
       clipped table first and the explanation only after scrolling past all of
       it. An affordance that arrives after the confusion is not an affordance.

       Now above, and styled as an instruction rather than a footnote. --- */
.ctable-scrollnote{
  display:flex;align-items:center;gap:7px;font-size:.8rem;font-weight:600;
  color:var(--ink-2);margin:clamp(24px,3.4vw,36px) 0 -8px
}
.ctable-scrollnote svg{width:16px;height:16px;flex:0 0 auto;color:var(--muted)}
@media(min-width:820px){.ctable-scrollnote{display:none}}

/* --- STICKY HEADER + STICKY FEATURE COLUMN, added 2026-08-27 (KAN-865).

       owner-cs named the real defect precisely, and it was not the sideways
       scroll itself: "the header row scrolls out of view vertically while the
       tiers scroll horizontally. A reader sees a feature description and two
       green ticks with no column headers above them. They cannot tell whether
       those ticks mean Platinum and Gold, or Silver and Bronze."

       That is a comparison table that cannot be used to compare, which is its
       only job, and the reader hitting it is someone choosing between a 1-seat
       Platinum and a 10-seat Bronze.

       Both axes lose their label, so both are pinned:
       - thead sticks to the top of the VIEWPORT (the vertical scroller is the
         page, not the wrapper), so tier names stay above their ticks.
       - the row label column sticks to the LEFT of the wrapper, so scrolling
         right does not strand a tick with no feature name either. owner-cs
         only hit the first, but the second is the same failure on the other
         axis and it would have been found the moment anyone scrolled.

       border-collapse:collapse drops collapsed borders on sticky cells in most
       engines, so the separators here are inset box-shadows rather than
       borders. Backgrounds are explicit and opaque for the same reason: a
       transparent sticky cell shows the scrolling content sliding underneath
       it, which looks worse than the bug being fixed. --- */
/* The wrapper must scroll on BOTH axes for the sticky header to have anything
   to stick to. This is the part I got wrong first and only caught by measuring
   it: `overflow-x:auto` already makes .ctable-wrap the nearest scrolling
   ancestor for BOTH axes (overflow-y computes to auto alongside it), so a
   sticky thead resolves against the WRAPPER, not the page. With the wrapper
   unbounded in height it never scrolls vertically, so the header could never
   stick and the fix was inert. Probed at a real 390px: theadTop=2628, i.e. the
   header sat far off-screen exactly as before.
   Capping the height gives the wrapper a vertical scroll, which is what the
   sticky header needs. Mobile only: at desktop the whole table fits and a
   nested scroll box would be strictly worse. */
@media(max-width:819px){
  .ctable-wrap{max-height:76vh;overflow-y:auto}
}
.ctable thead th{position:sticky;top:0;z-index:3;box-shadow:inset 0 -1px 0 var(--line)}
.ctable td:first-child,.ctable tbody th[scope="row"]{
  position:sticky;left:0;z-index:2;background:#fff;
  box-shadow:inset -1px 0 0 var(--line),inset 0 -1px 0 var(--line)
}
.ctable thead th:first-child{z-index:4;background:var(--surface)}
.ctable .ct-group th{z-index:2}
/* Hover must repaint the sticky cell too, or the pinned column stays white
   while the rest of its row highlights and the row reads as two rows. */
.ctable tbody tr:hover td:first-child,
.ctable tbody tr:hover th[scope="row"]{background:var(--surface)}
@media(min-width:820px){
  /* Nothing is clipped at desktop width, so drop the pinning entirely rather
     than pay for sticky painting on a table that already fits. */
  .ctable thead th,.ctable td:first-child,.ctable tbody th[scope="row"]{
    position:static;box-shadow:none
  }
  .ctable td:first-child,.ctable tbody th[scope="row"]{background:transparent}
}

/* --- Logo directory. Used by the three "our certified X" pages, where a tier
       is either a row of marks or an empty state, and the empty state is the
       common case today. --- */
.dir-tier{border-top:1px solid var(--line);padding-top:26px;margin-top:30px}
.dir-tier:first-child{border-top:0;padding-top:0;margin-top:clamp(28px,4vw,44px)}
.dir-tier h3{font-size:1.1rem;display:flex;align-items:center;gap:.6em;letter-spacing:-.01em}
.dir-tier h3 .d{width:10px;height:10px;border-radius:50%;flex:none}
.dir-t1 h3 .d{background:var(--reward)}   .dir-t2 h3 .d{background:var(--attract)}
.dir-t3 h3 .d{background:var(--motivate)} .dir-t4 h3 .d{background:var(--excite)}
.dir-tier > p{font-size:.92rem;color:var(--ink-2);line-height:1.65;margin-top:.7em;max-width:62em}
.dir-logos{display:flex;flex-wrap:wrap;gap:16px;margin-top:20px}
.dir-logos > a,.dir-logos > span{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:20px 24px;min-width:180px;box-shadow:var(--shadow-sm)
}
.dir-logos > a:hover{border-color:var(--line-2);transform:translateY(-2px);box-shadow:var(--shadow)}
.dir-logos img{height:46px;width:auto;max-width:170px;object-fit:contain}
.dir-logos .dir-name{font-size:.84rem;font-weight:600;color:var(--ink-2)}
.dir-empty{
  margin-top:18px;background:var(--surface);border:1px dashed var(--line-2);
  border-radius:var(--radius);padding:22px 24px;font-size:.9rem;color:var(--muted);line-height:1.65
}
.dir-empty a{color:var(--ink);font-weight:600;text-decoration:underline;text-underline-offset:2px}

/* --- Downloads. Art on the left, copy and store buttons on the right; the
       store badges are links or plain images depending on availability, and
       an unavailable one must not look clickable. --- */
.dl-card{display:grid;grid-template-columns:150px 1fr;gap:22px;align-items:start}
.dl-card .dl-art{width:100%;height:auto;border-radius:12px}
.dl-kind{font-size:.66rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.dl-card h3{margin:.3em 0 .4em}
.dl-stores{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
.dl-stores a,.dl-stores span{display:inline-flex}
.dl-stores img{height:38px;width:auto}
.dl-stores span img{opacity:.4;filter:grayscale(1)}
.dl-when{font-size:.8rem;font-weight:600;color:var(--ink-2);margin-top:16px}
.dl-when + .dl-stores{margin-top:9px}
@media(max-width:560px){.dl-card{grid-template-columns:1fr}.dl-card .dl-art{max-width:150px}}

/* --- Embedded scheduler. The booking iframe is third-party and sets its own
       height, so it gets a bounded frame rather than being dropped raw into
       the page as the legacy build did (where it ran edge to edge and had no
       accessible name). --- */
.embed-sec{background:var(--surface)}
.embed-frame{
  margin-top:clamp(24px,3.4vw,38px);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;background:#fff;box-shadow:var(--shadow-sm)
}
.embed-frame iframe{display:block;width:100%;height:850px;border:0}
@media(max-width:700px){.embed-frame iframe{height:1000px}}
/* --- Booking link-out, replacing the scheduler iframe (KAN-865, 2026-08-27).
       The vendor sends X-Frame-Options: SAMEORIGIN, so the embed rendered a
       grey broken-document box at every width and every consultative path on
       the site ended in nothing. See partials/booking-cta-2026.hbs for the
       verification and the conditions for putting the iframe back.

       .embed-frame above is deliberately KEPT rather than deleted: it is the
       styling the iframe needs the day the vendor allows framing, and deleting
       it would mean rebuilding it from scratch to undo a change we hope to
       undo. It is currently unused. --- */
.book-out{
  margin-top:clamp(24px,3.4vw,38px);border:1px solid var(--line);border-radius:var(--radius);
  background:#fff;box-shadow:var(--shadow-sm);padding:clamp(28px,4vw,44px);text-align:center
}
.book-out-note{font-size:1.02rem;color:var(--ink-2);line-height:1.6;max-width:46ch;margin:0 auto 1.4em}
.book-out .btn{display:inline-flex;align-items:center;gap:10px}
.book-out-ico{width:17px;height:17px;flex:0 0 auto}
.book-out-sub{font-size:.8rem;color:var(--faint);margin-top:1.1em}
.embed-fallback{font-size:.84rem;color:var(--muted);margin-top:.9em}
.embed-fallback a{color:var(--ink);font-weight:600;text-decoration:underline;text-underline-offset:2px}

/* --- Stat pair, used once on the agency page for the two retention charts.
       Kept generic because the developer page will want the same shape if it
       ever gains proof art. --- */
.statpair{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:clamp(28px,4vw,40px)}
.stat-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow-sm);text-align:center}
.stat-card img{width:100%;max-width:320px;height:auto;margin:0 auto 16px}
.stat-card p{font-size:.94rem;color:var(--ink-2);line-height:1.6}
.stat-card p b{color:var(--ink)}
.stat-src{font-size:.76rem;color:var(--faint);margin-top:.8em}
@media(max-width:700px){.statpair{grid-template-columns:1fr}}

/* --- Awards. One flagship award gets a wide block with its artefacts; the
       rest sit in the generic card grid. --- */
.award{display:grid;grid-template-columns:1.1fr .9fr;gap:34px;align-items:center;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);padding:clamp(24px,3vw,36px);box-shadow:var(--shadow-sm)}
.award + .award{margin-top:22px}
.award-art{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.award-art img{width:100%;height:auto;border-radius:10px;border:1px solid var(--line)}
.award h3{font-size:1.24rem;letter-spacing:-.01em;margin-bottom:.4em}
.award p{color:var(--ink-2);font-size:.94rem;line-height:1.65}
.award p + p{margin-top:.7em}
.award .award-when{font-size:.8rem;color:var(--faint);margin-top:1em}
@media(max-width:820px){.award{grid-template-columns:1fr;gap:24px}}

/* --- Closing contact line, shared by press room and the directories. --- */
.contact-line{
  margin-top:clamp(30px,4vw,44px);background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);padding:26px 28px;text-align:center;font-size:.96rem;color:var(--ink-2)
}
.contact-line a{color:var(--ink);font-weight:600;text-decoration:underline;text-underline-offset:2px}

/* Screen-reader-only. Needed by the certification table caption, which names
   the table for assistive tech without printing a redundant line above a table
   that already has a visible heading. */
.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
}

/* ================================================================
   IN-PAGE REGISTRATION DIALOG, added 2026-08-26.

   Replaces the wall.et/register domain hop. Native <dialog> for the same
   reason the feature-gallery lightbox uses one: the browser gives focus
   trapping, Escape-to-close and inertness on the rest of the page for free,
   and the hand-rolled versions of those are where accessibility bugs live.
   ================================================================ */
/* CENTRING, fixed 2026-08-27. The dialog was rendering in the top-left corner.

   Cause: the universal reset at the top of this file, `*{margin:0}`, also hits
   <dialog>. A modal dialog is centred by the browser's own stylesheet using
   `margin: auto` against `inset: 0`, and zeroing the margin removes exactly the
   thing doing the centring, so it collapses to the top-left. Nothing in the
   dialog's own rules was wrong, which is why it was not obvious: the bug was a
   reset written long before this component existed.

   Both properties are restored explicitly rather than relying on the UA
   defaults, because the whole problem was a UA default being overridden from a
   distance. inset + margin:auto centres on both axes in every engine that
   supports <dialog>.

   max-height and overflow are here for the same class of failure: the form is
   six fields plus a captcha notice, and on a short landscape phone it is taller
   than the viewport. Without a cap the top of the dialog would be pushed off
   screen with no way to reach it. */
.reg-dialog{
  border:0;padding:0;background:transparent;max-width:min(560px,94vw);width:100%;
  max-height:92vh;overflow:auto;margin:auto;
  color:var(--ink)
}
.reg-dialog::backdrop{background:rgba(12,13,16,.62);backdrop-filter:blur(3px)}
.reg-dialog[open]{display:block;position:fixed;inset:0}

.reg-box{
  background:#fff;border-radius:var(--radius-lg);padding:clamp(24px,3.4vw,36px);
  box-shadow:var(--shadow-lg);position:relative
}
.reg-box .spine{max-width:none;margin-bottom:22px}
.reg-box h2{font-size:clamp(1.4rem,2.6vw,1.85rem);letter-spacing:-.02em;margin:0}

.reg-sub{color:var(--muted);font-size:.94rem;margin-top:.5em;line-height:1.6}
.reg-sub a{color:var(--ink);font-weight:600;text-decoration:underline;text-underline-offset:2px}

.reg-close-form{position:absolute;top:0;right:0;z-index:2}
.reg-close{
  position:absolute;top:14px;right:14px;width:36px;height:36px;border-radius:10px;
  border:1px solid var(--line);background:#fff;color:var(--ink-2);cursor:pointer;
  display:flex;align-items:center;justify-content:center
}
.reg-close:hover{border-color:var(--line-2);color:var(--ink)}
.reg-close svg{width:17px;height:17px}
.reg-close:focus-visible{outline:3px solid var(--motivate);outline-offset:2px}

#regForm{margin-top:22px}
.reg-grid2{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:480px){.reg-grid2{grid-template-columns:1fr}}

.reg-field{margin-bottom:14px}
.reg-field label{display:block;font-size:.84rem;font-weight:600;margin-bottom:6px;color:var(--ink-2)}
.reg-field input{
  width:100%;font:inherit;font-size:.96rem;padding:.72em .9em;
  border:1px solid var(--line-2);border-radius:11px;background:#fff;color:var(--ink)
}
.reg-field input::placeholder{color:var(--faint)}
.reg-field input:focus{outline:0;border-color:var(--motivate);box-shadow:0 0 0 3px var(--motivate-soft)}
.reg-field input:user-invalid{border-color:#c5372c}

/* Password mismatch. Hidden until the two fields actually disagree, so it is
   never showing while someone is still typing the first one. */
.reg-mismatch{display:none;color:#b3261e;font-size:.82rem;margin:-6px 0 12px}
.reg-mismatch.show{display:block}

.reg-err{
  display:none;background:#fdecea;border:1px solid #f5c2bd;color:#8c1d18;
  border-radius:11px;padding:12px 14px;font-size:.9rem;line-height:1.5;margin-top:18px
}
.reg-err.show{display:block}

.reg-foot{font-size:.78rem;color:var(--faint);text-align:center;margin-top:12px;line-height:1.5}
.reg-foot a{color:var(--muted);text-decoration:underline;text-underline-offset:2px}
.reg-foot a:hover{color:var(--ink-2)}

/* Success state: verify your email, NOT "you're in". */
.reg-done{display:none;text-align:center}
.reg-done.show{display:block}
.reg-done .reg-tick{
  width:54px;height:54px;border-radius:50%;background:var(--reward-soft);
  display:flex;align-items:center;justify-content:center;margin:6px auto 18px
}
.reg-done .reg-tick svg{width:26px;height:26px;color:#4a7016}
.reg-done .reg-sub{max-width:36em;margin-left:auto;margin-right:auto}
