/* Kurdify / KurdConnect marketing site, shared design system.
   Tokens mirror the app so pages feel native.
   Powered by Kavalsia Inc. */

/*
  Copyright (c) Kavalsia Inc. All Rights Reserved.
  Lead Architect & Engineer: Siavash Sadighi
*/

/* Language bootstrap, paired with the inline <head> script build.py injects (inject_lang_boot).
   The pages are authored in Sorani, so the served markup paints ckb/rtl. site.js swapped the text
   on DOMContentLoaded from a script at the END of body, which by definition runs after that first
   paint, so anyone who had ever chosen English watched the Sorani page appear and flip on every
   visit. The head script fixes lang/dir/theme synchronously, which kills the layout jump, and sets
   this class only when the stored language is NOT the authored one, so the text swap happens
   unseen. Sorani visitors, the default and the majority, are never hidden for a moment.
   visibility rather than display: the layout is already correct, only the words are wrong, so
   nothing needs to reflow when it is revealed. The script also drops the class after 1200ms come
   what may, because a page that stays hidden is a worse failure than a flash. */
html.kx-lang-boot body{visibility:hidden}
/* And if CSS loads but JS is dead, never hide anything: no class is ever added without the script. */
@media print{html.kx-lang-boot body{visibility:visible}}

:root{
  --bg:#0b1418;--panel:#0f1d22;--panel2:#12252b;--line:#1e3a42;--line2:#295059;
  --text:#eaf4f2;--muted:#8fb0ad;--gold:#e0b64a;--gold2:#f0cd6e;--green:#2fbf87;--red:#e0574f;
  /* TWO GOLDS, because gold does two jobs and they need opposite treatment per theme.
     --goldink is the text that sits ON a gold fill. --goldtext is gold used AS text on the
     page ground. Dark theme: the fill is bright, so its ink is near-black, and gold as text is
     already legible. Light theme flips both (see the block below). Hardcoding either one is how
     .btn shipped var(--goldink,#231a05) on a #8a6508 fill at 3.23:1 across every marketing page. */
  --goldink:var(--goldink,#231a05);
  --goldtext:var(--gold);
  /* --greentext is the same idea as --goldtext, for the one place green is text sitting on its
     OWN green-tinted fill rather than on the page ground: .pill.green (queue #585, span.pill
     "Claimed"/"Published"). --green stays a status/confirmation token used elsewhere (icons,
     dots, borders, gradients) and is left alone on purpose; moving it would move every one of
     those surfaces too. Measured with tools/contrast-proof.mjs on the marketing home before
     this fix: dark 4.1:1 and 3.74:1, light 4.47:1 and 3.94:1, all under the 4.5 floor. */
  --greentext:#42d099;
  --dred:#7c241d;--dred2:#b23a2e;
  --sun:#d9b13a;--r:16px;
}
html[data-theme="light"]{
  --bg:#f4f7f6;--panel:#ffffff;--panel2:#eef3f2;--line:#dce6e4;--line2:#c2d4d0;
  /* --muted and --green each sat a hair under AA in their own most common pairing: --muted on
     the page ground read 4.41:1, and --green on its own 16% tint (.pill.green) read 4.25:1.
     Both are nudged down rather than special-cased per component, because the failure is the
     token and not the one place it was noticed.
     THAT NUDGE WAS NOT ENOUGH FOR --green, and queue #585 stopped repeating it. Re-measured
     2026-08-26: .pill.green still read 4.47:1 and 3.94:1 in light, 4.1:1 and 3.74:1 in dark,
     both under the 4.5 floor in both themes. Nudging --green further would have moved every
     OTHER surface that reads it as status/confirmation (icons, dots, borders, gradients), which
     is exactly the per-component special-casing this note argues against for a genuinely shared
     token. The difference here is that --green's most-common pairing (its own translucent fill)
     is not actually shared with those other surfaces, so #585 gave that one pairing its own
     token, --greentext, instead: same shape as the --gold/--goldtext split below. */
  --text:#12262c;--muted:#4d6560;--gold:#8a6508;--gold2:#7a5804;--green:#0a6740;--red:#cc3b31;--sun:#c99a2e;
  /* --greentext, light half (queue #585): darker still than --green, because the .pill.green
     fill composites lighter here than in dark (the light ground has less to absorb the 16%
     tint), so the text needs MORE room, not the same nudge. Light has no headroom where dark
     has plenty (the fill rule, .nexus/design-contract.md #10): tuned to the tougher of the two
     marketing-home readings (the Published pill's lighter composite background) with a small
     margin, then checked against the other. */
  --greentext:#095c39;
  /* --gold/--gold2 NOT touched for queue #492, on purpose: queue #385 (see the appended <style>
     block near the end of site/index.html) already tried this and reverted the idea, because
     .cta-band and its siblings pin themselves to a literal dark ground in BOTH themes, so
     raising --gold's light value to fix small gold-on-gradient text elsewhere would darken (or
     otherwise move) every var(--gold) reading that also sits on that always-dark ground, which
     is the opposite of what it needs there. #492's --gold-driven readings (.kv-badge "We are
     Kavalsia", b.rung-w "Credit") are fixed at the component level in site/index.html instead,
     redirected to var(--goldtext) below, which was already built for exactly "gold used as
     text" and never reaches the always-dark bands. */
  /* Light theme's --gold is a DARK gold, so the ink on it goes cream, not near-black, and gold
     used as text has to come down further still: the bright accent on a cream ground measured
     1.63:1 on the soon-badges, the worst reading on the whole site. */
  --goldink:#fff8e6;
  --goldtext:#6b4e06;
  --dred:#8a2b22;--dred2:#a5342a;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
@media(min-width:820px){html{font-size:94%}}
body{font-family:'Figtree','Vazirmatn',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
:root[dir=rtl] body{font-family:'Vazirmatn','Figtree',-apple-system,sans-serif}
a{color:var(--gold2);text-decoration:none}
img{max-width:100%;display:block}
h1,h2,h3,h4{text-wrap:balance;letter-spacing:-.02em;line-height:1.14}
h3,h4{letter-spacing:-.01em;line-height:1.25}
/* English: force all headlines onto the Sans display stack (never a serif). */
:root[lang="en"] h1,:root[lang="en"] h2,:root[lang="en"] h3,:root[lang="en"] h4,:root[lang="en"] h5,:root[lang="en"] h6{font-family:'Figtree',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif !important}
p{text-wrap:pretty}
.wrap{max-width:1680px;margin:0 auto;padding:0 clamp(24px,5vw,72px)}
.wrap-wide{max-width:1680px}
@media(max-width:640px){.wrap{padding-inline:24px!important}}

/* ---- top banner ---- */
.topbanner{position:relative;background:color-mix(in srgb,var(--gold) 8%,var(--bg));color:var(--gold2);font-weight:700;font-size:.76rem;text-align:center;padding:.6rem 16px;display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:nowrap}
:root[dir=ltr] .topbanner{text-transform:uppercase;letter-spacing:.12em}
.topbanner::after{content:"";position:absolute;inset-inline:0;bottom:0;height:1px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--gold) 55%,transparent),transparent)}
.topbanner::before{content:"";position:absolute;inset:0;background:radial-gradient(50% 200% at 50% 0%,color-mix(in srgb,var(--gold) 10%,transparent),transparent 70%);pointer-events:none}
.topbanner svg{width:15px;height:15px;flex:none}
.topbanner a{color:var(--gold2);font-weight:800;text-decoration:underline;text-underline-offset:3px}
html[data-theme="light"] .topbanner{color:#7a5804;background:color-mix(in srgb,var(--gold) 14%,var(--bg))}
@media(max-width:520px){.topbanner{font-size:.68rem;gap:7px;padding:.5rem 10px}}

/* ---- nav ---- */
.nav{position:sticky;top:0;z-index:40;background:color-mix(in srgb,var(--bg) 82%,transparent);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}
.nav::after{content:"";position:absolute;inset-inline:0;bottom:-1px;height:1px;background:linear-gradient(90deg,transparent 8%,color-mix(in srgb,var(--gold) 30%,transparent) 50%,transparent 92%)}
/* Header (banner + nav) slides down smoothly once the preloader clears. Default is
   visible, so no-JS / reduced-motion always shows it; only the preloading state
   lifts it off-screen, and removing that state transitions it back in. */
/* small, subtle downward slide that lands ~2s in (after the preloader clears + a beat) */
.topbanner,.nav{transition:transform 1s cubic-bezier(.16,1,.3,1) .45s, opacity .8s ease .45s}
html.preloading .topbanner,html.preloading .nav{transform:translateY(-16px);opacity:0}
@media(prefers-reduced-motion:reduce){
  .topbanner,.nav{transition:none}
  html.preloading .topbanner,html.preloading .nav{transform:none;opacity:1}
}
.nav .wrap{display:flex;align-items:center;justify-content:space-between;height:70px;gap:14px}
.brand{display:flex;align-items:center;gap:10px;font-weight:800;font-size:1.15rem;letter-spacing:-.02em;color:var(--text)}
.brand .sun{width:24px;height:24px;color:var(--sun);flex:none}
.brand b{color:var(--gold)}
.nav-links{display:flex;gap:14px;align-items:center}
/* 44px min-height is the hit-target floor, not a look. These were 34px tall (and the More
   button 21px), which is a miss on a phone and on any imprecise pointer. The height is bought
   with padding rather than a taller bar, so the 70px nav is unchanged; gap drops 24 to 14 to
   pay for the new inline padding, leaving the optical spacing where it was. */
.nav-links > a{position:relative;display:inline-flex;align-items:center;min-height:44px;
  padding-inline:10px;color:var(--muted);font-size:.9rem;font-weight:600;white-space:nowrap;
  border-radius:10px;transition:color .15s ease,background-color .15s ease}
/* Anchored to a fixed offset, not to the padding box: the link is now 44px tall with the line
   box centred in it, so bottom:-2px would have dropped the rule 10px below the word. */
.nav-links > a::after{content:"";position:absolute;inset-inline:10px;bottom:9px;height:2px;border-radius:2px;background:var(--gold);transform:scaleX(0);transform-origin:center;transition:transform .22s cubic-bezier(.22,1,.36,1)}
.nav-links > a:hover{color:var(--text);background:color-mix(in srgb,var(--gold) 7%,transparent)}
.nav-links > a:hover::after{transform:scaleX(.6)}
.nav-links > a.nav-on{color:var(--gold)}
.nav-links > a.nav-on::after{transform:scaleX(1)}
@media(prefers-reduced-motion:reduce){.nav-links a::after{transition:none}}
/* The language pill and the theme toggle read as one control group now: a shared
   glass surface with a hairline between them, a gold-tinted glow on hover and a
   proper focus ring. They were two separate flat boxes with only a border swap. */
.nav-actions{display:inline-flex;align-items:center;gap:7px;padding:4px;border-radius:14px;
  background:color-mix(in srgb,var(--panel) 72%,transparent);
  box-shadow:none}
.icon-btn{transition:border-color .2s ease,background-color .2s ease,color .2s ease,transform .2s cubic-bezier(.22,1,.36,1),box-shadow .2s ease;background:var(--panel);color:var(--text);width:44px;height:44px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;flex:none;font-family:inherit}
.icon-btn:hover{background:color-mix(in srgb,var(--gold) 10%,var(--panel));color:var(--gold2);transform:translateY(-1px);box-shadow:0 8px 18px -12px color-mix(in srgb,var(--gold) 70%,transparent);}
.icon-btn:active{transform:translateY(0)}
/* Every interactive object in the bar, not just the two that had it. A keyboard user was
   getting the browser default ring on the nav links, the More button, both menus' rows and
   the burger, which on this dark teal is close to invisible. */
.icon-btn:focus-visible,.lang-btn:focus-visible,.nav-links > a:focus-visible,.more-btn:focus-visible,
.more-menu a:focus-visible,.lang-opt:focus-visible,.burger:focus-visible,.brand:focus-visible{
  outline:2px solid var(--gold);outline-offset:2px;border-radius:10px}
.icon-btn svg{width:18px;height:18px}
.lang-btn{transition:border-color .2s ease,background-color .2s ease,color .2s ease,transform .2s cubic-bezier(.22,1,.36,1),box-shadow .2s ease;background:var(--panel);color:var(--text);border-radius:10px;height:44px;padding:0 .8rem;font-family:inherit;font-size:.82rem;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.lang-btn:hover{background:color-mix(in srgb,var(--gold) 10%,var(--panel));color:var(--gold2);transform:translateY(-1px);box-shadow:0 8px 18px -12px color-mix(in srgb,var(--gold) 70%,transparent);}
.lang-btn:active{transform:translateY(0)}
@media(prefers-reduced-motion:reduce){
  .icon-btn,.lang-btn{transition:none}
  .icon-btn:hover,.lang-btn:hover{transform:none}
}
.lang-btn svg{width:15px;height:15px}
.lang-wrap{position:relative}
/* Reveal, not a flip. display:none to block gave the two menus no transition at all, so a
   seven-item panel appeared instantly under the cursor. visibility keeps them out of the tab
   order while closed, which display:none did for free and opacity alone would not. */
.lang-menu{position:absolute;top:calc(100% + 7px);inset-inline-end:0;min-width:150px;background:var(--panel);border-radius:13px;padding:6px;box-shadow:0 18px 44px rgba(0,0,0,.45);z-index:90;opacity:0;visibility:hidden;transform:translateY(-6px) scale(.98);transform-origin:top center;transition:opacity .18s ease,transform .22s cubic-bezier(.22,1,.36,1),visibility 0s linear .22s}
.lang-menu.open{opacity:1;visibility:visible;transform:none;transition:opacity .18s ease,transform .22s cubic-bezier(.22,1,.36,1),visibility 0s}
.lang-opt{display:flex;align-items:center;justify-content:space-between;min-height:44px;padding:.55rem .8rem;border-radius:9px;cursor:pointer;font-size:.88rem;font-weight:600;color:var(--text);width:100%;background:none;border:none;font-family:inherit;text-align:start}
.lang-opt:hover{background:var(--panel2)}
.lang-opt.on{color:var(--gold)}
.lang-opt .lo-ck{width:15px;height:15px;opacity:0;color:var(--gold)}
.lang-opt.on .lo-ck{opacity:1}
/* "More" nav dropdown (I2) - modeled on .lang-* mechanics */
.more-wrap{position:relative;display:inline-flex;align-items:center}
/* Was 41x21, the smallest target in the bar and the one that opens a seven-item menu.
   Matched to the nav links beside it so the row reads as one set of objects. */
.more-btn{background:none;border:none;color:var(--muted);font-family:inherit;font-size:.9rem;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:5px;min-height:44px;padding-inline:10px;border-radius:10px;white-space:nowrap;transition:color .15s ease,background-color .15s ease}
.more-btn:hover{color:var(--text);background:color-mix(in srgb,var(--gold) 7%,transparent)}
/* The chevron states what the menu is doing. Without this the button looks identical open
   and closed, so the only feedback was the menu itself appearing. */
.more-chev{transition:transform .22s cubic-bezier(.22,1,.36,1)}
.more-btn[aria-expanded="true"]{color:var(--text)}
.more-btn[aria-expanded="true"] .more-chev{transform:rotate(180deg)}
.more-chev{width:14px;height:14px}
.more-menu{position:absolute;top:calc(100% + 12px);inset-inline-end:0;min-width:200px;background:var(--panel);border-radius:13px;padding:6px;box-shadow:0 18px 44px rgba(0,0,0,.45);z-index:90;opacity:0;visibility:hidden;transform:translateY(-6px) scale(.98);transform-origin:top center;transition:opacity .18s ease,transform .22s cubic-bezier(.22,1,.36,1),visibility 0s linear .22s}
.more-menu.open{opacity:1;visibility:visible;transform:none;transition:opacity .18s ease,transform .22s cubic-bezier(.22,1,.36,1),visibility 0s}
.more-menu a{display:flex;align-items:center;min-height:44px;padding:.55rem .8rem;border-radius:9px;font-size:.88rem;font-weight:600;color:var(--text);white-space:nowrap}
.more-menu a:hover{background:var(--panel2);color:var(--text)}
.more-menu a.nav-on{color:var(--gold)}

/* ---- Dropdowns, glass (owner request 2026-08-14: "make the dropdown better") -------------
   Both menus hang off the header, and the header is glass, but these were built as flat
   `--panel` slabs with a hard 1px `--line2` outline, so opening one dropped an opaque card out
   of a translucent bar. Restated here rather than edited above so the two menus are guaranteed
   to move together; they are the same component in two places and had already drifted apart in
   min-width and offset.
   Ground is darker and more opaque than the bar's (.82 against .34): a bar only has to stay
   legible over the page, a menu has to stay legible over whatever the page put under it, which
   on the home hero is a photograph. The outward shadow IS wanted here and is not the bleed that
   was removed from the bar: a floating menu is supposed to cast one, and it is tight and offset
   downward rather than a soft halo in every direction.
   Rims are rgba white, never `--line2`: on app.kurdify.app that token is transparent (borderless
   pass) and the edge vanished, on the site pages it is opaque and drew a hard outline. Same trap
   the control cluster hit on 2026-08-14, same fix. */
/* THE GROUND IS OPAQUE AND THESE MENUS HAVE NO backdrop-filter OF THEIR OWN, and both halves
   are deliberate. This is the same defect #679 fixed on the app host's `.nav .csel-menu`, filed
   here as #681 and fixed on 2026-08-27 BEFORE it was ever visible, so there is no dramatic
   before/after shot to point at and that is the point.

   These pages load css/header.css as well as this file, and header.css gives `.nav .wrap` its
   own backdrop-filter (blur(26px) saturate(1.7), css/header.css:134). That makes .wrap a
   backdrop root, and these menus hang below its box (`top:calc(100% + 12px)` off a 70px bar).
   A translucent background on a descendant that escapes a backdrop-filtered ancestor does not
   composite at its declared alpha: on the app host at .94 AND at .97 the hero headline read
   straight through the panel, while getComputedStyle reported the correct colour the whole
   time. The style applies; the paint does not.

   It did not LOOK broken here on 2026-08-27, and that is a property of the backdrop, not of the
   CSS: the marketing home puts flat dark behind this menu rather than a photographic hero with
   a large bright headline. The moment that backdrop changes -- a new hero image, another page,
   a scrolled position -- the bleed appears. Latent, not absent.

   The blur is dropped rather than kept because inside that backdrop root it has nothing left to
   sample: it was paying compositor cost to filter an empty backdrop. The white sheen gradient
   stays and is what still reads as glass.

   DO NOT reintroduce an alpha below 1 here, and do not add an @supports fallback that sets one:
   the branch that used to sit below this rule set rgba(19,16,23,.97) and would have re-broken
   it on any browser without backdrop-filter, which is why it is deleted rather than edited.
   If a real translucent glass menu is wanted, the fix is to portal the menu out of `.wrap`,
   not to lower this alpha. */
.nav .lang-menu,.nav .more-menu{
  border:0;border-radius:15px;padding:7px;
  background:
    linear-gradient(178deg,rgba(255,255,255,.07),rgba(255,255,255,.015) 45%,rgba(255,255,255,0) 80%),
    #131017;
  box-shadow:0 20px 44px -16px rgba(0,0,0,.72); /* border pass, 2026-08-31: rim layers dropped, elevation kept */
}
/* 44px is the touch minimum and stays that on a coarse pointer (queue 242). A mouse does not
   need it, and six 44px rows made the More menu tall and sparse enough to read as a list of
   sections rather than a menu, so the fine-pointer row tightens to 40px. */
.nav .more-menu a,.nav .lang-opt{border-radius:11px;min-height:40px;padding:.5rem .75rem}
@media (pointer:coarse){
  .nav .more-menu a,.nav .lang-opt{min-height:44px}
}
/* Hover picks up the brand the way the header's own controls do, instead of a flat panel swap. */
.nav .more-menu a:hover,.nav .lang-opt:hover{
  background:color-mix(in srgb,var(--gold) 11%,rgba(255,255,255,.05));
  color:var(--text);
}
.nav .more-menu a.nav-on,.nav .lang-opt.on{color:var(--gold)}
.burger{display:none;background:var(--panel);color:var(--text);cursor:pointer;width:44px;height:44px;border-radius:10px;align-items:center;justify-content:center}
.mobile-menu{display:none;position:fixed;top:70px;inset-inline:0;background:var(--panel);padding:8px;z-index:55;flex-direction:column;max-height:82vh;overflow:auto;box-shadow:0 14px 34px rgba(0,0,0,.35)}
.mobile-menu.open{display:flex}
.mobile-menu a{padding:.85rem 1rem;color:var(--text);font-weight:700;border-radius:10px;text-decoration:none}
.mobile-menu a:hover,.mobile-menu a.nav-on{background:var(--panel2);color:var(--gold)}
.mm-langs{display:flex;gap:8px;flex-wrap:wrap;padding:.7rem 1rem}
.mm-lang{padding:.5rem .9rem;border-radius:8px;font-weight:700;font-size:.82rem;cursor:pointer;background:var(--panel2);color:var(--text);font-family:inherit}
.mm-lang.on{background:var(--gold);color:var(--goldink,#231a05);}
@media(max-width:900px){.nav-links{display:none}.burger{display:inline-flex}}

/* ---- buttons ---- */
/* min-height is the 44px touch target, not decoration: the padding alone resolved to 42px,
   two short of the minimum, on every button across the marketing site. */
.btn{display:inline-flex;align-items:center;gap:8px;background:var(--gold);color:var(--goldink,#231a05);font-weight:800;padding:.7rem 1.2rem;min-height:44px;border-radius:11px;font-size:.9rem;border:0;cursor:pointer;font-family:inherit;transition:.15s;text-decoration:none;line-height:1.2}
.btn:hover{background:var(--gold2);color:var(--goldink,#231a05)}
.btn svg{width:17px;height:17px;flex:none}
.btn.ghost{background:transparent;color:var(--text)}
.btn.ghost:hover{background:transparent;color:var(--text);}
.btn.green{background:var(--green);color:#04231a}
.btn.green:hover{background:#4dd39f;color:#04231a}
.btn.lg{padding:.95rem 1.7rem;font-size:1rem}
.btn.block{width:100%;justify-content:center}

/* ---- hero ---- */
.hero{padding:clamp(2.6rem,7vw,5.5rem) 0 2.5rem;position:relative;overflow:hidden}
.hero::after{content:"";position:absolute;top:-140px;inset-inline-end:-90px;width:480px;height:480px;background:radial-gradient(circle,rgba(217,177,58,.22),transparent 70%);pointer-events:none;z-index:0}
/* The green bloom that used to sit at the bottom-start of the hero wrap was removed on
   2026-08-12 (owner request: "remove this green glow"). It painted a 420px radial of the green
   accent across the band between the stat tiles and the category ticker, which is the one place
   on the page where the hero's gold and the KurdConnect green met and read as two brands at once.
   The gold .hero::after above stays: it is the brand accent, it sits behind the headline where a
   single light source belongs, and it was not what was reported. */
/* Hero wash: Erbil Citadel (Wahlen, CC0 / public domain, via Wikimedia).
   Sits under the copy and fades out before the text block ends, so contrast never drops.
   Decorative only, hence no <img> and aria-hidden. Raised from .12 (near-invisible on the
   dark panel) so the photo actually reads instead of the hero looking like flat black. */
.hero::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(6,10,12,.55),rgba(6,10,12,.2) 45%,var(--bg) 92%),url(img/hero-erbil.jpg) center 35%/cover no-repeat;opacity:.34;
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 48%,transparent 92%);
  mask-image:linear-gradient(to bottom,#000 0%,#000 48%,transparent 92%)}
html[data-theme="light"] .hero::before{opacity:.16}
@media(prefers-reduced-motion:reduce){.hero::before{opacity:.22}}
.hero .wrap{position:relative;z-index:1}
/* Border removed 2026-08-06, owner request, and it applies to every eyebrow on the site:
   WE ARE KAVALSIA, PLATFORM FEATURES, the built-on-our-own-data note. An outlined pill around
   two words of uppercase gold was drawing a box around the least important line on the section.
   The panel fill stays so it still reads as a chip rather than loose floating text, and the
   padding is untouched so nothing below it shifts. */
.eyebrow{display:inline-flex;align-items:center;gap:7px;background:var(--panel);border:0;color:var(--gold);font-size:.68rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;padding:.32rem .75rem;border-radius:100px}
.eyebrow svg{width:12px;height:12px}
.hero h1,.hero .hero-h1{font-size:clamp(2.1rem,6vw,3.6rem);line-height:1.08;margin:1.1rem 0 .9rem;font-weight:800;text-wrap:balance}
.hero h1 span,.hero .hero-h1 span{color:var(--gold)}
.hero-lead{color:var(--muted);font-size:clamp(1rem,2.4vw,1.18rem);max-width:640px}
.hero-cta{display:flex;gap:12px;margin-top:1.8rem;flex-wrap:wrap}
.center{text-align:center}
/* .hero-us is a second, standalone hero paragraph (the brand tagline). Like
   .hero-lead it is width-capped, so it needs an auto inline margin or the block
   hugs the inline-start edge and reads as misaligned under a centred hero.
   !important overrides a legacy inline `margin:.4rem 0 1.2rem` still carried by
   one page this pass could not edit; logical props keep RTL (ckb/ar) correct. */
.center .hero-lead{margin-inline:auto}
.center .hero-us{margin-inline:auto!important}
/* Give CTAs a shared min-width so a two-button row reads as balanced around center
   (otherwise a narrow primary + wide secondary looks off-center), without stretching
   a lone button. */
.center .hero-cta{justify-content:center}
.center .hero-cta .btn{min-width:190px;justify-content:center;text-align:center}

/* ---- IN / OUTSIDE chooser ---- */
/* Three tracks, not two: the middle one is the bridge that joins the two homes. */
.chooser{display:grid;grid-template-columns:1fr auto 1fr;gap:0;margin-top:2.4rem;align-items:stretch}
@media(max-width:680px){.chooser{grid-template-columns:1fr}}

/* ---- The bridge: one rail, one junction ----
   Gold is Kurdify (inside Kurdistan), green is KurdConnect (beyond it). Each rail is
   transparent where it meets its own card and solid where it meets the node, so the eye is
   pulled to the junction rather than to either side. The mark in the node is the roj, the
   same sun as .hero-roj, which is what the two sides actually share.
   Gradients are physical, so the horizontal ones are written for the RTL default (Sorani)
   and flipped under :root[dir=ltr]; the vertical mobile ones need no flip. */
/* Overhangs the 18px grid gap on both sides via negative margin, so the rails reach the card
   edges instead of stopping short and leaving the node floating in dead space. The auto track
   still sizes to the margin box (120 - 36 = 84px), so the cards themselves do not move. */
.cc-bridge{display:flex;align-items:center;justify-content:center;width:120px;align-self:center}
.ccb-rail{flex:1 1 auto;height:2px;border-radius:2px}
@media (prefers-reduced-motion:no-preference){.ccb-rail{animation:ccbRailFade 5s ease-in-out infinite}}
@keyframes ccbRailFade{0%,100%{opacity:.35}50%{opacity:1}}
.ccb-rail-a{background:linear-gradient(90deg,var(--gold),transparent)}
.ccb-rail-b{background:linear-gradient(90deg,transparent,var(--green))}
:root[dir=ltr] .ccb-rail-a{background:linear-gradient(90deg,transparent,var(--gold))}
:root[dir=ltr] .ccb-rail-b{background:linear-gradient(90deg,var(--green),transparent)}
.ccb-node{flex:none;width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  background:linear-gradient(160deg,color-mix(in srgb,var(--panel2) 92%,var(--gold)),var(--panel2));
  /* The hairline is gone; the knock-out ring against the page and a soft lift carry the shape
     instead, which is the same borderless treatment the chooser cards and stat tiles use. */
  box-shadow:0 0 0 7px var(--bg),0 6px 18px -8px rgba(0,0,0,.55),
             inset 0 1px 0 color-mix(in srgb,var(--gold) 18%,transparent)}
/* Slow breathing halo: the node's glow swells to a broad soft blur, then eases back down. */
@media (prefers-reduced-motion:no-preference){
  .ccb-node{animation:ccbGlow 5s ease-in-out infinite}
}
@keyframes ccbGlow{
  0%,100%{ box-shadow:0 0 0 7px var(--bg),0 6px 18px -8px rgba(0,0,0,.55),
    0 0 5px 0 color-mix(in srgb,var(--gold) 18%,transparent),
    inset 0 1px 0 color-mix(in srgb,var(--gold) 18%,transparent) }
  50%{ box-shadow:0 0 0 7px var(--bg),0 6px 18px -8px rgba(0,0,0,.55),
    0 0 30px 8px color-mix(in srgb,var(--gold) 55%,transparent),
    inset 0 1px 0 color-mix(in srgb,var(--gold) 30%,transparent) }
}
.ccb-node svg{width:19px;height:19px;color:var(--gold);animation:ccbSunPulse 5s ease-in-out infinite}
@keyframes ccbSunPulse{ 0%,100%{opacity:.82;transform:scale(.94)} 50%{opacity:1;transform:scale(1.06)} }
@media (prefers-reduced-motion:reduce){ .ccb-node svg{animation:none} }
@media(max-width:680px){
  /* Stacked cards: the rail turns vertical so the join survives the single-column layout
     instead of disappearing with the middle track. */
  /* 54px left only 7px of rail either side of the node, which read as a stub rather than a
     join. 92px gives each rail ~26px, matching the desktop proportion. */
  .cc-bridge{width:auto;margin-inline:0;height:92px;flex-direction:column;justify-self:center}
  .ccb-rail{width:2px;height:auto;flex:1 1 auto}
  .ccb-rail-a,:root[dir=ltr] .ccb-rail-a{background:linear-gradient(180deg,transparent,var(--gold))}
  .ccb-rail-b,:root[dir=ltr] .ccb-rail-b{background:linear-gradient(180deg,var(--green),transparent)}
  /* Mobile stack was reading as one crowded column: bridge card, chooser cards and stat
     strip sat with barely any air between them. Give each block real separation. */
  .chooser{gap:22px;margin-top:2rem}
  .choose-card{padding:1.7rem 1.6rem}
}
/* Flat, square, flush pair: no radius, no per-card outline. The two cards sit edge to edge
   against the .cc-bridge column (chooser gap is 0) so the rail+node glow is the only seam
   between them, instead of two separately-bordered boxes floating apart. */
.choose-card{position:relative;display:block;background:var(--panel);border-radius:0;padding:2rem;text-align:start;overflow:hidden;transition:transform .18s,box-shadow .18s;color:var(--text)}
/* The rotating conic-gradient ring that used to run around this card was REMOVED 2026-09-04
   (owner: "make these more neat"). A 1.5px masked ring is a border by any name, and it broke
   the borderless law twice over: it drew a rim on a container, and the two cards ran their
   rings at different angles and in opposite directions, so a pair that is geometrically
   identical (both 152.4px at 1440/1725/1920, measured) read as mismatched. Depth now comes
   from fill and a real drop shadow; see the .cam-cards block near the end of this file.
   Nothing else on the site uses .choose-card, so the ring is gone rather than scoped away.
   Do not reintroduce it, and do not replace it with box-shadow:0 0 0 1px, which is the same
   border spelled differently. */
.choose-card:hover{transform:translateY(-4px);box-shadow:0 18px 44px rgba(0,0,0,.28)}
.choose-card .cc-glow{position:absolute;inset-inline-end:-60px;top:-60px;width:200px;height:200px;border-radius:50%;filter:blur(30px);opacity:.5;pointer-events:none}
.choose-card.in .cc-glow{background:radial-gradient(circle,rgba(224,182,74,.5),transparent 70%)}
.choose-card.out .cc-glow{background:radial-gradient(circle,rgba(47,191,135,.45),transparent 70%)}
.cc-ic{width:56px;height:56px;border-radius:15px;display:flex;align-items:center;justify-content:center;margin-bottom:1rem;position:relative}
.choose-card.in .cc-ic{background:rgba(224,182,74,.14);color:var(--gold)}
.choose-card.out .cc-ic{background:rgba(47,191,135,.14);color:var(--green)}
.cc-ic svg{width:28px;height:28px}
.choose-card h3{font-size:1.35rem;margin-bottom:.35rem}
.choose-card p{color:var(--muted);font-size:.92rem;margin-bottom:1.1rem}
.cc-go{display:inline-flex;align-items:center;gap:8px;font-weight:800;font-size:.9rem}
.choose-card.in .cc-go{color:var(--gold)}
.choose-card.out .cc-go{color:var(--green)}
.cc-go svg{width:16px;height:16px;transition:.18s}
.choose-card:hover .cc-go svg{transform:translateX(-4px)}
:root[dir=ltr] .choose-card:hover .cc-go svg{transform:translateX(4px)}
.cc-tag{position:absolute;inset-inline-end:1.4rem;top:1.4rem;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;padding:.25rem .6rem;border-radius:100px;background:var(--panel2);color:var(--muted)}

/* ---- sections ---- */
section.block{padding:clamp(2.6rem,6vw,4.5rem) 0;scroll-margin-top:88px}
.s-head{max-width:720px;margin-bottom:2rem}
/* Trailing call-to-action at the end of a section, under a card grid. These were hand-set inline
   at 1.2rem/1.6rem per page, which read as cramped: the button sat almost against the cards above
   it and the section boundary below. One rule, so the rhythm is the same on every page. */
.sec-cta{margin-top:clamp(1.9rem,3.2vw,2.9rem);text-align:center}
/* "Free to list, free to use" band. Replaced 132 lines of plan cards on the landing page: price
   belongs on /pricing, after someone has seen the value. */
.free-band{max-width:760px;margin:0 auto;text-align:center;background:var(--panel);border-radius:20px;padding:clamp(1.6rem,4vw,2.6rem)}
.free-band h2{margin:.4rem 0 .6rem}
.free-band > p{color:var(--muted);max-width:56ch;margin:0 auto}
.free-list{list-style:none;margin:1.4rem auto 0;padding:0;display:grid;gap:.6rem;
  max-width:34rem;text-align:start}
.free-list li{display:flex;align-items:flex-start;gap:.6rem;color:var(--text)}
.free-list svg{width:19px;height:19px;flex:none;margin-top:.15rem;color:var(--green)}
.free-cta{display:flex;flex-wrap:wrap;gap:.7rem;justify-content:center;margin-top:1.6rem}
.s-head.center{margin-inline:auto}
.s-head .kicker{color:var(--gold);font-weight:800;font-size:.78rem;text-transform:uppercase;letter-spacing:.1em;margin-bottom:.6rem}
.s-head h2{font-size:clamp(1.5rem,3.6vw,2.3rem)}
.s-head p{color:var(--muted);font-size:1rem;margin-top:.7rem}
.divider{border:none;margin:0}

/* ---- feature / value cards ---- */
.grid{display:grid;gap:16px}
.grid.g2{grid-template-columns:repeat(2,1fr)}
.grid.g3{grid-template-columns:repeat(3,1fr)}
.grid.g4{grid-template-columns:repeat(4,1fr)}
@media(max-width:900px){.grid.g3,.grid.g4{grid-template-columns:repeat(2,1fr)}}
/* Queue 351: a lone card stranded alone on the last row (odd total over these 2 columns) spans
   the full row instead. General for ANY item count, same precedent as .pag-grid/.hjobs-row in
   the app shell: :last-child:nth-child(2n+1) only ever matches when the last card is alone. The
   3-card .pledge grid is the one that currently hits this; a 12- or 6-card .grid.g3 elsewhere on
   this page divides evenly and the selector never matches there. */
@media(min-width:561px) and (max-width:900px){
  .grid.g3>:last-child:nth-child(2n+1){grid-column:1/-1}
}
@media(max-width:560px){.grid.g2,.grid.g3,.grid.g4{grid-template-columns:1fr}}
/* Borderless (see the full treatment further down); the surface and its glow separate the
   cards. This early declaration is kept for the layout only. */
.fcard{background:var(--panel);border:none;border-radius:var(--r);padding:1.5rem;transition:.15s;display:flex;flex-direction:column;height:100%}
.grid.g3,.grid.g4,.grid.g2{align-items:stretch}
.fcard:hover{transform:translateY(-3px);}
.fcard .f-ic{width:48px;height:48px;border-radius:13px;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,rgba(224,182,74,.16),rgba(47,191,135,.08));color:var(--gold);margin-bottom:1rem}
.fcard .f-ic svg{width:24px;height:24px}
.fcard h3{font-size:1.1rem;margin-bottom:.45rem}
.fcard p{color:var(--muted);font-size:.9rem}
.fcard .f-more{display:inline-flex;align-items:center;gap:6px;margin-top:.8rem;font-size:.82rem;font-weight:700;color:var(--gold2)}
/* .f-more is a real <a>, and it measured 22px in en and 23px in ckb against the 44px floor, on
   all four 320 combinations and all four 375 ones. Clean at 768 and 1280, which is the floor
   behaving correctly: it is a touch rule, so it is met at touch widths rather than by inflating
   a small inline link under a cursor. Counted before changing a shared rule, because .fcard has
   173 instances across eight pages: .f-more is on exactly ONE element in the whole of site/
   (scoring.html) and zero in the app's index.html, so this is a shared selector with a single
   user today. It is fixed here rather than in that page so the next .f-more inherits the floor
   instead of re-earning the finding. */
@media(max-width:560px){.fcard .f-more{min-height:44px}}
.fcard ul{list-style:none;margin-top:.7rem;display:flex;flex-direction:column;gap:.4rem}
.fcard ul li{color:var(--muted);font-size:.86rem;display:flex;gap:8px;align-items:flex-start}
.fcard ul li svg{width:15px;height:15px;color:var(--green);flex:none;margin-top:3px}

/* ---- stats strip ---- */
.stat-strip{display:flex;gap:16px;flex-wrap:wrap;justify-content:center;margin-top:2.4rem}
.hstat{position:relative;overflow:hidden;background:linear-gradient(160deg,var(--panel),color-mix(in srgb,var(--gold) 6%,var(--panel)));border-radius:16px;padding:1.3rem 1.5rem 1.15rem;text-align:center;min-width:140px;box-shadow:0 10px 26px -14px rgba(0,0,0,.5);transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease}
.hstat::before{content:"";position:absolute;top:0;inset-inline:0;height:3px;background:linear-gradient(90deg,transparent,var(--gold),transparent);opacity:.85}
.hstat:hover{transform:translateY(-3px);box-shadow:0 16px 34px -14px rgba(0,0,0,.6);}
.hstat b{display:block;font-size:1.9rem;font-weight:800;color:var(--gold);line-height:1;letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.hstat span{color:var(--muted);font-size:.78rem;margin-top:.45rem;display:block;letter-spacing:.01em}

/* ---- alternating showcase rows ---- */
.showrow{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center;padding:clamp(2rem,5vw,3.4rem) 0}
.showrow.rev .show-media{order:2}
@media(max-width:800px){.showrow{grid-template-columns:1fr;gap:22px}.showrow.rev .show-media{order:0}}
.show-txt .kicker{color:var(--gold);font-weight:800;font-size:.76rem;text-transform:uppercase;letter-spacing:.1em;margin-bottom:.6rem}
.show-txt h3{font-size:clamp(1.3rem,3vw,1.9rem);margin-bottom:.7rem}
.show-txt p{color:var(--muted);font-size:.96rem;margin-bottom:1rem}
.show-list{list-style:none;display:flex;flex-direction:column;gap:.6rem}
.show-list li{display:flex;gap:10px;align-items:flex-start;font-size:.92rem}
.show-list li svg{width:18px;height:18px;color:var(--green);flex:none;margin-top:3px}
/* Round 2026-08-22, changes 2 & 4: .show-list (the two Pro-page checklists) and .free-list
   (the pricing-band checklist) share the same one-line-per-row target at 390px. Scoped to
   the li, not the base list rule, so the desktop/tablet gap and sizing are untouched. */
@media(max-width:480px){
  .show-list li,.free-list li{font-size:clamp(11.5px,3.1vw,15px);letter-spacing:-0.01em;gap:8px;white-space:normal}
}
/* Sponsored caption under the plan-comparison heading (change 3, 2026-08-22): plain text,
   no border, sits between the h2 and the lead paragraph. */
.sponsored-note{font-size:12px;color:var(--muted);margin:2px 0 10px}
/* min-width:0 -- queue 424 (origin 367). Below ~343px this grid item's automatic minimum size
   was set by its widest descendant's UNWRAPPABLE content (.mini-row's non-wrapping chip row
   inside .pts-card, scrollWidth ~237px, despite the row's own overflow-x:auto), so the whole
   box, its border, background AND the ::after glow all overflowed the wrap by up to ~23px and
   got hard-clipped by body{overflow-x:hidden} -- the flat vertical edge reported in 367.
   min-width:0 removes that forced floor; the row still scrolls internally if it ever needs to,
   it just no longer forces this box wider than its actual track. Verified: 320px width no
   longer overflows (box left 24px, matching every other width) and the mini-row's own content
   (237px) fits inside the corrected 272px-280px available width with room to spare, so nothing
   is cropped or newly scrollable. */
.show-media{position:relative;isolation:isolate;background:var(--panel);border-radius:20px;padding:1.4rem;min-height:230px;display:flex;align-items:center;justify-content:center;min-width:0}
/* GLOW ONLY. THE RING IS GONE. Owner request 2026-08-31: "the outer glow should not look
   trimmed or have a border, it is supposed to be a glow."

   What stood here was a MOVING LIGHT border:0
   xor'd down to a 1.5px band, sweeping around the frame. Two things were wrong with it and
   they are the same thing.
   1. It is a border. The borderless law keeps a line alive only when the line draws a
      PICTURE; this one framed a container, which is the exact case the law deletes. A
      gradient rim carved out with a mask is still a rim.
   2. The conic gradient is transparent for 58% of the turn, so only an ARC of that ring was
      ever lit and the line always ended in two hard cut-offs part-way along an edge. On a
      phone, where the card is 342px of a 390px viewport and the cut sits right next to the
      screen edge, that reads as a border someone trimmed -- which is the report.

   The ::after bloom is what is left, and it was always the real glow: it sat at opacity .5
   behind a 1.5px near-white glint that shouted over it. It carries the sweep now and is
   lifted to .78 to take back the light the ring was contributing.

   THE BLUR IS CAPPED BY THE VIEWPORT, NOT BY TASTE. body{overflow-x:hidden} clips at the
   body box, and at 390px this card measures x=24..366, so there are exactly 24px of room
   outside its right edge. A blurred box paints out to roughly inset + 1.5*blur, so
   inset:-6px with blur:11px reaches ~22.5px and stays inside that 24px. blur:14px reaches
   ~27px and the glow is hard-clipped by the body edge again -- the same flat vertical cut,
   only softer. Anything wider than this pair has to move the card in from the gutter first.

   z-index:-2 under `isolation:isolate` on the parent, with an opaque var(--panel) fill on
   the card itself, is what keeps the glow strictly OUTSIDE the box: it is painted behind an
   opaque surface, so only the part that clears the border-box is ever seen. */
@property --sweep{syntax:'<angle>';inherits:false;initial-value:0deg}
.show-media::after{content:"";position:absolute;inset:-6px;border-radius:inherit;
  pointer-events:none;z-index:-2;opacity:.78;filter:blur(11px);
  background:conic-gradient(from var(--sweep),transparent 0 62%,color-mix(in oklab,var(--gold) 55%,transparent) 78%,color-mix(in oklab,var(--green) 50%,transparent) 90%,transparent 100%)}
@media (prefers-reduced-motion:no-preference){
  .show-media::after{animation:smSweep 6s linear infinite}
}
@keyframes smSweep{to{--sweep:360deg}}

/* ---- mock UI bits used in showcases ---- */
.mini-card{background:var(--panel2);border-radius:14px;padding:1rem;width:100%}
.mini-row{display:flex;align-items:center;gap:12px;margin-bottom:.9rem}
.mini-row:last-child{margin-bottom:0}
/* Queue 429: a chip row is a rail wherever it appears, not in the two places it was patched one
   at a time. `.listing-card .mini-row:last-child` (below) and `.pts-card .mini-row` (extras.css)
   each got this treatment on their own, and the showcase `.mini-card` that has neither was still
   pushing a green pill 50px past a 250px viewport in en and 27px in ckb, measured against a
   freshly built dist. Matching on `:has(> .pill)` keeps it to rows that actually hold chips:
   `.mini-row` is also used for logo-plus-name rows, and making THOSE flex:none would stop a long
   name shrinking and create the overflow this rule exists to remove. Where :has() is not
   supported the rule simply does not apply and the row behaves as it does today. */
.mini-row:has(> .pill){flex-wrap:nowrap;gap:7px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.mini-row:has(> .pill)::-webkit-scrollbar{display:none}
.mini-row:has(> .pill)>*{flex:none}
.mini-logo{width:46px;height:46px;border-radius:11px;flex:none;display:grid;place-items:center;background:linear-gradient(135deg,var(--panel),var(--panel2));color:var(--gold);font-weight:800}
.mini-logo svg{width:22px;height:22px}
.mini-name{font-weight:700;font-size:.92rem}
.mini-sub{color:var(--muted);font-size:.76rem}
.pill{display:inline-flex;align-items:center;gap:5px;font-size:.68rem;font-weight:800;padding:.22rem .6rem;border-radius:100px}
.pill.gold{background:var(--gold);color:var(--goldink,#231a05)}
.pill.green{background:rgba(47,191,135,.16);color:var(--greentext)}
.pill.muted{background:var(--panel);color:var(--muted)}
.pill svg{width:12px;height:12px}
.verified{display:inline-flex;align-items:center;gap:5px;color:var(--green);font-size:.78rem;font-weight:800}
.verified svg{width:16px;height:16px}

/* ---- premium claimed-business listing mock (index.html .listing-card) ---- */
.listing-card{position:relative;overflow:hidden;padding:1.15rem;
  background:
    radial-gradient(120% 100% at 100% 0%, color-mix(in oklab,var(--green) 9%,transparent), transparent 55%),
    linear-gradient(180deg, color-mix(in oklab,var(--panel) 55%,var(--panel2)), var(--panel2));
  box-shadow:0 16px 36px -24px color-mix(in oklab,#000 80%,transparent)}
.listing-card::before{content:"";position:absolute;inset-inline:0;top:0;height:1px;
  background:linear-gradient(90deg,transparent,color-mix(in oklab,var(--green) 45%,transparent),transparent)}
.listing-card .mini-logo{width:50px;height:50px;border-radius:13px;color:var(--gold);
  background:linear-gradient(145deg, color-mix(in oklab,var(--gold) 22%,var(--panel)), var(--panel2));
  box-shadow:0 6px 14px -8px color-mix(in oklab,var(--gold) 60%,transparent)}
.listing-card .mini-name{font-size:.98rem;letter-spacing:-.01em}
.listing-card .mini-sub{font-size:.78rem}
.listing-card .verified{padding:.28rem .6rem;border-radius:99px;font-size:.72rem;
  background:color-mix(in oklab,var(--green) 15%,transparent);
  border:0;
  box-shadow:0 0 12px -4px color-mix(in oklab,var(--green) 55%,transparent)}
/* Queue 351: chip row never wraps (house rule). */
.listing-card .mini-row:last-child{gap:7px;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.listing-card .mini-row:last-child::-webkit-scrollbar{display:none}
.listing-card .mini-row:last-child>*{flex:none}
.listing-card .pill{padding:.3rem .66rem;font-size:.7rem}
/* Borderless (owner rule 2026-08-19, reasserted 2026-08-22 on a screenshot of this pill).
   The frame is gone and the fill widens to do its job: the old 22%->13% ladder leaned on the
   34% border to hold its edge, so dropping the border alone would have let the pill dissolve
   into the card. Measured after the change, not assumed. */
.listing-card .pill.green{border:0;
  background:linear-gradient(180deg, color-mix(in oklab,var(--green) 30%,transparent), color-mix(in oklab,var(--green) 19%,transparent))}
.listing-card .pill.gold{background:linear-gradient(180deg,var(--gold2),var(--gold));
  box-shadow:0 3px 10px -5px color-mix(in oklab,var(--gold) 70%,transparent)}
.listing-card .pill.muted{background:color-mix(in oklab,var(--text) 5%,var(--panel))}
.listing-card .pill.muted svg{color:var(--gold)}

/* countdown */
.countdown{display:flex;gap:8px;margin-top:.7rem}
/* `.cd-box`, `.cd-box b` and `.cd-box span` DELETED 2026-09-06, queue #828 (owner call). They
   styled a countdown mockup whose markup is gone: `.cd-box` matched 0 elements on all 55 built
   pages in real Chrome, and no class attribute anywhere in the build names it. The bare
   `.countdown` rule above is left standing on purpose - it was not part of the task - but it is
   dead too. `.rung` below is NOT dead: 6 elements, measured, do not sweep it with this. */

/* loyalty ladder */
.ladder{display:flex;gap:10px;flex-wrap:wrap;margin-top:.6rem}
/* Carries the treatment the deleted .cd-box used to share (#828): a tight contact shadow that
   seats the tile plus a wide soft one that lifts it, no edge, including the #822 fix. */
.rung{flex:1;min-width:90px;border:none;border-radius:16px;padding:1rem .9rem;text-align:center;
  background:linear-gradient(180deg,color-mix(in srgb,var(--panel2) 94%,transparent),var(--panel));
  box-shadow:0 2px 4px -2px rgba(0,0,0,.55),
             0 14px 26px -16px rgba(0,0,0,.9)}
/* var(--goldtext), not var(--gold) (queue #492): this is gold used AS text, on the rung's own
   gold-tinted gradient (.rung.g1/.g2/.g3 below), which is exactly what --goldtext exists for.
   b.rung-w "Credit" measured 4.05:1 as --gold; unaffected in dark theme (--goldtext:var(--gold)
   there, so this is a no-op change on that side). */
.rung b{display:block;font-size:1.6rem;font-weight:800;color:var(--goldtext)}
/* A rung whose value is a WORD rather than a figure. 1.6rem is sized for "+100" and "20%"; the
   referral ladder ends on "Credit", which at that size is wider than its own rung and wrapped in
   every language. Sorani "کرێدیت" and Arabic "رصيد" are the long ones. */
/* The word rung ('Credit') sits beside numeric rungs set at 1.6rem. It was already stepped
   down once to 1.02rem so a word would not shout next to figures; the owner asked for it
   smaller again on 2026-08-06 (queue 201 item 3). .86rem keeps it clearly a label rather
   than a value, and still reads at 375px, where it is the only text in its rung. */
.rung b.rung-w{font-size:.86rem;line-height:1.32;letter-spacing:-.01em}
.rung.g1{background:linear-gradient(180deg,color-mix(in srgb,var(--gold) 7%,var(--panel2)),var(--panel))}
.rung.g2{background:linear-gradient(180deg,color-mix(in srgb,var(--gold) 12%,var(--panel2)),var(--panel))}
/* The top rung is the only one that glows: same two-stop stack as .rung, with the lift tinted
   gold instead of black. #822 and the dropped inset edge as above. */
.rung.g3{background:linear-gradient(180deg,color-mix(in srgb,var(--gold) 18%,var(--panel2)),var(--panel));
  box-shadow:0 2px 4px -2px rgba(0,0,0,.55),
             0 16px 30px -16px rgba(224,182,74,.4)}
.rung span{font-size:.72rem;color:var(--muted);display:block;margin-top:.2rem}

/* ---- pricing ---- */
/* Plan columns are centred on the page and capped, so three cards stay a tidy
   block instead of stretching edge to edge on wide screens. */
/* first-year international-card offer, above the plan grid */
.card-offer{display:flex;align-items:center;gap:20px;flex-wrap:wrap;max-width:1040px;margin:0 auto 26px;
  padding:20px 24px;border-radius:16px;border:0;background:rgba(47,191,135,.08)}
/* THE SAME HUE FOR THE TEXT AND ITS OWN TRANSLUCENT FILL IS THE DEFECT. A literal #2fbf87 is
   the DARK theme's green; over the card's own rgba(47,191,135,.08) fill on a light page it
   composites to green-on-pale-green at 2.06:1, under even the 3:1 large-text floor. The number
   takes the themed --green, which is the darker #0f7a4c in light mode, so the pair separates. */
.card-offer .co-pct{font-size:2.4rem;font-weight:800;line-height:1;color:var(--green);flex:none;letter-spacing:-.02em}
.card-offer .co-txt{flex:1;min-width:min(100%,260px);display:flex;flex-direction:column;gap:6px}
.card-offer .co-txt b{font-size:1.05rem}
.card-offer .co-txt span{opacity:.8;font-size:.92rem;line-height:1.55}
@media(max-width:560px){.card-offer{gap:14px;padding:18px}.card-offer .co-pct{font-size:2rem}}

.price-grid{display:grid;grid-template-columns:repeat(3,minmax(0,340px));gap:18px;
  align-items:stretch;justify-content:center;max-width:1080px;margin-inline:auto}
@media(max-width:860px){.price-grid{grid-template-columns:minmax(0,420px)}}
/* Item 4 restyle (2026-08-31): premium card treatment, names/prices untouched.
   Depth now comes from a per-tier gradient wash and a lift on hover, not a rim:
   .plan.feat keeps its gold cast at rest and gets no border-color at all any more. */
.plan{background:linear-gradient(160deg,color-mix(in srgb,var(--panel2) 55%,var(--panel)),var(--panel) 60%);
  border-radius:22px;padding:2rem 1.9rem;display:flex;flex-direction:column;position:relative;
  box-shadow:0 20px 44px -30px rgba(0,0,0,.5);
  transition:transform .25s cubic-bezier(.2,.7,.2,1),box-shadow .25s}
.plan:hover{transform:translateY(-4px);box-shadow:0 28px 56px -28px rgba(0,0,0,.55)}
.plan.feat{background:linear-gradient(160deg,color-mix(in srgb,var(--gold) 10%,var(--panel2)),var(--panel) 62%);
  box-shadow:0 26px 56px -28px color-mix(in srgb,var(--gold) 30%,transparent)}
.plan.feat:hover{box-shadow:0 32px 64px -26px color-mix(in srgb,var(--gold) 38%,transparent)}
.plan:nth-child(3){background:linear-gradient(160deg,color-mix(in srgb,var(--green) 7%,var(--panel2)),var(--panel) 62%)}
.plan .plan-tag{position:absolute;top:-13px;inset-inline-start:1.9rem;background:linear-gradient(135deg,var(--gold),color-mix(in srgb,var(--gold) 70%,#fff));color:var(--goldink,#231a05);font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;padding:.32rem .85rem;border-radius:100px;box-shadow:0 6px 16px -6px color-mix(in srgb,var(--gold) 55%,transparent)}
.plan h3{font-size:1.15rem}
.plan .price{font-size:2.7rem;font-weight:800;margin:.7rem 0 .1rem;line-height:1;letter-spacing:-.03em}
.plan .price small{font-size:.95rem;font-weight:600;color:var(--muted)}
.plan .plan-bill{color:var(--muted);font-size:.78rem;font-weight:600;margin:.2rem 0 .55rem}
.plan .plan-bill b{color:var(--text);font-weight:700}
.plan .plan-desc{color:var(--muted);font-size:.88rem;min-height:2.4em}
.plan ul{list-style:none;margin:1.2rem 0;display:flex;flex-direction:column;gap:.7rem;flex:1}
.plan ul li{display:flex;gap:9px;align-items:flex-start;font-size:.9rem}
.plan ul li svg{width:17px;height:17px;color:var(--green);flex:none;margin-top:3px}
.plan ul li.off{color:var(--muted);opacity:.6}
.plan ul li.off svg{color:var(--muted)}
/* Paid add-on row: reads as an extra you buy, not as an included feature. */
.plan ul li.addon{color:var(--gold2);font-weight:700;
  padding-top:.7rem;margin-top:.1rem}
.plan ul li.addon svg{color:var(--gold)}
/* Card headings, price and CTA centre; the feature list stays start-aligned,
   because centred checklists are measurably harder to scan. */
.plan h3,.plan .price,.plan .plan-desc{text-align:center}
.plan .plan-desc{margin-inline:auto}

/* sponsorship cards */
.spon-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media(max-width:680px){.spon-grid{grid-template-columns:1fr}}
.spon{background:linear-gradient(150deg,var(--panel),var(--panel2));border-radius:18px;padding:1.6rem}
.spon h4{font-size:1.05rem;display:flex;align-items:center;gap:9px}
.spon .sp-ic{width:36px;height:36px;border-radius:10px;background:rgba(224,182,74,.14);color:var(--gold);display:flex;align-items:center;justify-content:center}
.spon .sp-ic svg{width:19px;height:19px}
.spon .sp-price{font-size:1.9rem;font-weight:800;margin:.5rem 0 .2rem}
.spon .sp-price small{font-size:.9rem;color:var(--muted);font-weight:600}
.spon p{color:var(--muted);font-size:.88rem}

/* payment methods */
/* Auto-fit rather than a fixed 3, so the row stays balanced as payment methods
   are added or removed (USDT was removed; the backend rejects it). */
.pay-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px;margin-top:1.2rem}
@media(max-width:640px){.pay-row{grid-template-columns:1fr}}
.pay{background:var(--panel);border-radius:14px;padding:1.1rem;display:flex;gap:12px;align-items:center}
.pay .pay-ic{width:44px;height:44px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.8rem}
.pay .pay-ic svg{width:22px;height:22px}
.pay .fib{background:rgba(224,182,74,.14);color:var(--gold)}
.pay .zc{background:rgba(224,87,79,.14);color:var(--red)}
.pay b{font-size:.95rem;display:block}
.pay span{color:var(--muted);font-size:.78rem}

/* A method that cannot take money yet must not sit here looking identical to one that can.
   ZainCash has neither merchant credentials nor a wallet number for the hand-confirmed path,
   so the card is dimmed and badged rather than removed: it is a real intention, not a live
   option. Same badge treatment as Kurdify credit on the features page. */
.pay.is-soon{opacity:.62}
.pay .soon{display:inline-block;font-size:.58rem;font-weight:800;letter-spacing:.04em;
  color:var(--goldink,#231a05);background:var(--gold);padding:.1rem .45rem;border-radius:99px;
  vertical-align:middle;margin-inline-start:.4rem}

/* ---- influencer levels ---- */
.lvl-scroll{overflow-x:visible;padding-bottom:0}
.lvl-track{display:flex;gap:12px;min-width:min-content;justify-content:center;flex-wrap:wrap}
.lvl{position:relative;flex:none;width:150px;background:var(--panel);border-radius:15px;padding:1.1rem;text-align:center;overflow:hidden}
.lvl::after{content:"";position:absolute;inset:0;z-index:0;background-image:url(https://images.unsplash.com/photo-1451481357743-7d9b21edeb15?w=600&q=55&auto=format&fit=crop);background-size:cover;background-position:center;opacity:.1;filter:blur(2px);pointer-events:none}
/* A light travels around each level card's edge: a rotating conic gradient masked to the
   1px border ring. Staggered per card so the lights chase around the row. */
@property --lvl-a{syntax:'<angle>';inherits:false;initial-value:0deg}
.lvl::before{content:"";position:absolute;inset:0;border-radius:inherit;padding:1px;pointer-events:none;z-index:0;
  background:conic-gradient(from var(--lvl-a),transparent 0 62%,color-mix(in srgb,var(--gold) 92%,#fff) 78%,color-mix(in srgb,var(--green) 85%,transparent) 88%,transparent 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}
.lvl>*{position:relative;z-index:1}

@media (prefers-reduced-motion:no-preference){
  .lvl::before{animation:lvlSpin 4.5s linear infinite}
  .lvl:nth-child(2)::before{animation-delay:-.55s}
  .lvl:nth-child(3)::before{animation-delay:-1.1s}
  .lvl:nth-child(4)::before{animation-delay:-1.65s}
  .lvl:nth-child(5)::before{animation-delay:-2.2s}
  .lvl:nth-child(6)::before{animation-delay:-2.75s}
  .lvl:nth-child(7)::before{animation-delay:-3.3s}
}
@keyframes lvlSpin{to{--lvl-a:360deg}}
.lvl .lvl-n{font-size:.72rem;font-weight:800;color:var(--gold);text-transform:uppercase;letter-spacing:.05em}
.lvl .lvl-f{font-size:1.5rem;font-weight:800;margin:.3rem 0}
.lvl .lvl-lb{color:var(--muted);font-size:.74rem}
.lvl .lvl-dot{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--gold),var(--green));margin:0 auto .6rem;display:flex;align-items:center;justify-content:center;color:var(--goldink,#231a05)}
.lvl .lvl-dot svg{width:17px;height:17px}
/* Owner request 2026-08-06: all seven levels in ONE row on a phone, not a horizontal scroller.
   A scroller hides the ladder, which is the entire point of the block: L1 to L7 only means
   something when you can see both ends at once.
   Seven columns at 375px is about 46px each, so the tile has to give something up. The repeated
   "followers+" label goes, because printing it seven times says nothing the heading has not
   already said, and that is what buys the number enough room to stay legible. */
@media(max-width:640px){
  .lvl-scroll{overflow-x:visible}
  .lvl-track{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;flex-wrap:nowrap;min-width:0}
  .lvl{width:auto;min-width:0;padding:.5rem .15rem;border-radius:10px}
  .lvl .lvl-dot{width:18px;height:18px;margin:0 auto .3rem}
  .lvl .lvl-dot svg{width:10px;height:10px}
  .lvl .lvl-n{font-size:.56rem;letter-spacing:.02em}
  /* #458: "500K" measured 3px past its tile at .82rem. Tabular figures make every level tile the
     same width, so the widest label decides, and 500K is it. The tenth of a rem back plus the
     tracking is enough for the widest value the ladder can hold. */
  .lvl .lvl-f{font-size:.76rem;margin:.12rem 0 0;letter-spacing:-.02em}
  .lvl .lvl-lb{display:none}
}

/* ---- CTA band ---- */
.cta-band{background:radial-gradient(70% 120% at 50% -10%,rgba(224,182,74,.16),transparent 62%),linear-gradient(135deg,rgba(224,182,74,.1),rgba(47,191,135,.07));border-radius:24px;padding:clamp(2rem,5vw,3.4rem);text-align:center;position:relative;overflow:hidden}
.cta-band h2{font-size:clamp(1.5rem,4vw,2.3rem);margin-bottom:.7rem}
.cta-band p{color:var(--muted);max-width:560px;margin:0 auto 1.6rem;font-size:1rem}
.cta-band .hero-cta{justify-content:center}

/* ---- legal (privacy / terms) ---- */
.legal{max-width:820px;margin:0 auto;padding:clamp(2rem,5vw,3.4rem) 0}
.legal .updated{color:var(--muted);font-size:.85rem;margin-bottom:2rem}
.legal h2{font-size:1.3rem;margin:2.2rem 0 .7rem;padding-top:.4rem}
.legal h3{font-size:1.05rem;margin:1.4rem 0 .5rem}
.legal p{color:var(--muted);margin-bottom:.9rem;font-size:.95rem}
.legal ul{margin:0 0 1rem;padding-inline-start:1.3rem;color:var(--muted)}
.legal ul li{margin-bottom:.5rem;font-size:.93rem}
.legal a{color:var(--gold2)}
.legal .toc{background:var(--panel);border-radius:var(--r);padding:1.3rem 1.5rem;margin-bottom:2rem}
.legal .toc h4{font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-bottom:.7rem}
.legal .toc ol{padding-inline-start:1.2rem;color:var(--text)}
.legal .toc ol li{margin-bottom:.35rem;font-size:.9rem}
.callout{background:var(--panel2);border-radius:14px;padding:1.1rem 1.3rem;margin:1.2rem 0;display:flex;gap:12px}
.callout svg{width:20px;height:20px;color:var(--gold);flex:none;margin-top:2px}
.callout p{margin:0;color:var(--text);font-size:.9rem}

/* ---- FAQ ---- */
/* FAQ: one card per question with air between them (2026-07-30 polish), instead of the old
   single hard-edged box of cramped rows. The open item earns a gold hairline and a tinted
   summary, so the active question reads at a glance. */
.faq{display:flex;flex-direction:column;gap:12px}
.faq details{border-radius:16px;background:var(--panel);overflow:hidden;transition:border-color .2s}
.faq summary{padding:1.15rem 1.35rem;cursor:pointer;font-weight:700;font-size:.98rem;line-height:1.45;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:14px;transition:background .15s}
.faq summary:hover{background:var(--panel2)}
.faq details[open] summary{background:color-mix(in srgb,var(--gold) 5%,var(--panel))}
.faq summary::-webkit-details-marker{display:none}
.faq summary .fq-ic{width:20px;height:20px;color:var(--gold);transition:transform .25s cubic-bezier(.22,1,.36,1);flex:none}
.faq details[open] summary .fq-ic{transform:rotate(45deg)}
.faq .fq-body{padding:1rem 1.35rem 1.25rem;color:var(--muted);font-size:.94rem;line-height:1.7;max-width:68ch}
@media(prefers-reduced-motion:reduce){.faq details,.faq summary,.faq summary .fq-ic{transition:none}}

/* ---- footer ---- */
footer{padding:3rem 0 1.5rem;margin-top:3rem;color:var(--muted);font-size:.85rem}
footer{position:relative}
footer::before{content:"";position:absolute;top:-1px;inset-inline:0;height:2px;background:linear-gradient(90deg,transparent,var(--gold),var(--green),transparent);opacity:.55}
.foot-grid{display:grid;grid-template-columns:1.7fr 1fr 1fr 1fr 1fr;gap:30px;padding-block:20px 8px}
/* 5 columns crowd below ~1040px, so drop the brand onto its own row first. */
@media(max-width:1040px) and (min-width:721px){.foot-grid{grid-template-columns:1fr 1fr 1fr 1fr;gap:26px}.foot-brand{grid-column:1/-1;margin-bottom:.4rem}.foot-brand p{max-width:none}}
@media(max-width:720px){.foot-grid{grid-template-columns:1fr 1fr;gap:20px 24px}.foot-brand{grid-column:1/-1;margin-bottom:.4rem}.foot-brand p{max-width:none}}
@media(max-width:420px){.foot-grid{grid-template-columns:1fr}}
/* social row */
.foot-social{display:flex;gap:10px;margin-top:1.1rem}
.foot-social a{display:grid;place-items:center;width:40px;height:40px;border-radius:11px;background:var(--panel);color:var(--text);opacity:.85;transition:.15s}
.foot-social a:hover{color:var(--gold);opacity:1;transform:translateY(-2px);}
.foot-social svg{width:19px;height:19px}
.foot-brand p{color:var(--muted);font-size:.86rem;margin:.6rem 0 0;max-width:320px;line-height:1.55}
.foot-col h5{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;color:var(--goldtext);margin-bottom:.9rem;font-weight:800}
.foot-col a{display:block;color:var(--text);opacity:.75;font-size:.88rem;padding:.32rem 0;text-decoration:none}
.foot-col a:hover{color:var(--gold);opacity:1}
.foot-bottom{margin-top:26px;padding:16px 0 0;text-align:center;color:var(--muted);font-size:.82rem}
.foot-bottom span{color:var(--gold2);font-weight:700}

/* ---- loading / error states (shared) ---- */
.state{display:none;padding:2.4rem 1rem;text-align:center;color:var(--muted)}
.state.on{display:block}
.spinner{width:34px;height:34px;border-top-width:0;border-radius:50%;margin:0 auto 1rem;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.state .st-ic{width:40px;height:40px;color:var(--red);margin:0 auto .8rem}
.state .st-retry{margin-top:1rem}

@media(prefers-reduced-motion:reduce){*{animation-duration:.001ms!important;transition-duration:.001ms!important;scroll-behavior:auto!important}}

/* ============================================================
   PRELOADER, ENTRY MOTION, MOBILE LAYER  (added 2026-07-09)
   ============================================================ */

/* ---- preloader ---- */
#pre{position:fixed;inset:0;z-index:9999;background:var(--bg);display:grid;place-items:center;
  /* Failsafe: if JS never runs, fade out on our own so content is reachable. */
  animation:preFailsafe .5s ease 40s forwards}
#pre.done{opacity:0;visibility:hidden;transition:opacity .55s ease,visibility .55s ease}
html.preloading{overflow:hidden}
/* The typewriter preloader (.pre-in / .pre-type / #preText / .pre-bar / .pre-skip) was
   replaced by the sun-bloom orb, whose styles live in extras.css as .pl-*. Its markup is gone
   from all 14 pages that load this file, so those rules were dead and are removed here. That
   also retires the progress bar's animated bar width, which was the last layout-property
   animation in this file.
   .pre-sun stays: #pre still carries it, and the self-contained pages under cases/ ship their
   own copies of the old preloader markup and CSS, so nothing there depends on this file. */
.pre-sun{width:54px;height:54px;color:var(--sun);margin:0 auto 1.5rem;animation:preSpin 14s linear infinite}
@keyframes preSpin{to{transform:rotate(360deg)}}
@keyframes preFailsafe{to{opacity:0;visibility:hidden}}

/* ---- scroll entry motion (only armed once JS is alive, so no-JS keeps content visible) ---- */
/* #829, 2026-09-06: same shape as the .rv-stagger fix below. `html.js-motion .reveal.rv-in`
   used to carry `transform:none`, and at (0,3,1) it outranked every hover lift on the page,
   which are all (0,2,0) or (0,3,0). That is what pinned .fcard (39 cards) and .aio-card (3)
   after the .rv-stagger half was already fixed - two separate reveal systems, the same one
   declaration, and fixing one still measured 9 of 12 grids dead. The transition stays on the
   unscoped rule so it applies in both states. The hero's own focus-in below keeps
   `transform:none` on its .rv-in rule: nothing in the hero has a hover lift to pin. */
html.js-motion .reveal{
  transition:opacity .65s cubic-bezier(.22,1,.36,1),transform .65s cubic-bezier(.22,1,.36,1)}
html.js-motion .reveal:not(.rv-in){opacity:0;transform:translateY(20px)}
html.js-motion .reveal.rv-in{opacity:1}

/* ---- premium hero entrance: a "focus-in" (blur -> sharp) that rises and settles,
        distinct from the generic scroll reveal used elsewhere on the page ---- */
html.js-motion .hero .eyebrow.reveal,
html.js-motion .hero h1.reveal,
html.js-motion .hero .hero-lead.reveal,
html.js-motion .hero .hero-us.reveal,
html.js-motion .hero .hero-cta.reveal{
  /* TIMING, retuned 2026-09-04. This was opacity 1.5s / transform 1.6s / filter 1.35s from a
     22px blur, and the owner photographed the hero lead mid-entrance and read it as ghosted.
     He was looking at a real problem: this is ABOVE-THE-FOLD COPY, and it is also carrying a
     second animation at the same time (hbRise, on .hero h1 / .eyebrow / .hero-lead in
     index.html, .7s with delays to .48s), so the two compound. Measured before: the headline
     was not readable until 960ms and the lead until 1113ms on this machine, and every one of
     those milliseconds is spent on a machine with less headroom than this one, behind a hero
     canvas that is also drawing.
     The focus-in is kept because it is the hero's character; it is simply not allowed to hold
     the sentence hostage. Blur starts at 14px rather than 22px, so there is less to undo, and
     the transitions land inside the craft floor's 150-300ms guidance scaled for a hero rather
     than at one and a half seconds. */
  opacity:0; transform:translateY(52px) scale(.955); filter:blur(14px);
  transition:opacity .62s cubic-bezier(.16,1,.3,1),
             transform .78s cubic-bezier(.16,1,.3,1),
             filter .5s cubic-bezier(.16,1,.3,1);
  will-change:opacity,transform,filter;
}
/* the headline gets a touch more travel + a settle-scale for extra presence */
html.js-motion .hero h1.reveal{transform:translateY(58px) scale(.94)}
html.js-motion .hero .eyebrow.reveal.rv-in,
html.js-motion .hero h1.reveal.rv-in,
html.js-motion .hero .hero-lead.reveal.rv-in,
html.js-motion .hero .hero-us.reveal.rv-in,
html.js-motion .hero .hero-cta.reveal.rv-in{
  opacity:1; transform:none; filter:blur(0);
}
/* the hero arc fades up a touch later so it settles after the copy */
html.js-motion .hero .hero-viz.reveal{opacity:0;transform:translateY(24px);
  transition:opacity 1.1s cubic-bezier(.16,1,.3,1) .15s, transform 1.1s cubic-bezier(.16,1,.3,1) .15s}
html.js-motion .hero .hero-viz.reveal.rv-in{opacity:1;transform:none}

/* one-time sheen sweeping across the gold headline word, after it settles.
   The clip-gradient exists only to carry the transient highlight; the resting and
   reduced-motion state is solid gold, so this is motion, not gradient text. */
.hero h1 span{
  background:linear-gradient(100deg,var(--gold) 0%,var(--gold) 38%,#f7e2a6 50%,var(--gold) 62%,var(--gold) 100%);
  background-size:250% 100%; background-position:120% 0;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:transparent;
  animation:heroSheen 2.4s cubic-bezier(.22,1,.36,1) .55s 1 both;
}
@keyframes heroSheen{ to{ background-position:0 0 } }
@media (prefers-reduced-motion:reduce){
  .hero h1 span{animation:none;background:none;color:var(--gold);-webkit-text-fill-color:var(--gold)}
}
/* The gold-sheen rule above also matches the comma wrapper <span class="hcma">,
   which tinted the comma gold. Force it back to normal text colour so only the
   highlighted word ("one place") stays gold. */
.hero h1 .hcma{
  background:none !important;
  -webkit-background-clip:border-box; background-clip:border-box;
  color:var(--text) !important; -webkit-text-fill-color:var(--text) !important;
  animation:none !important;
}

/* Section headlines carry the same treatment the hero h1 has always had: one gold phrase,
   with a sheen that sweeps across it once, the first time the headline scrolls into view.
   The resting state is solid gold, so a headline whose sheen never fires (reduced motion,
   background tab, no IntersectionObserver, JS off) still reads at full contrast. The
   clip-gradient carries the transient highlight only, it is not gradient text. */
.hl{color:var(--gold)}
.hl.lit{
  background:linear-gradient(100deg,var(--gold) 0%,var(--gold) 38%,#f7e2a6 50%,var(--gold) 62%,var(--gold) 100%);
  background-size:250% 100%; background-position:120% 0;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:transparent;
  animation:hlSheen 1.9s cubic-bezier(.22,1,.36,1) 1 both;
}
@keyframes hlSheen{ to{ background-position:0 0 } }
@media (prefers-reduced-motion:reduce){
  .hl.lit{animation:none;background:none;color:var(--gold);-webkit-text-fill-color:var(--gold)}
}

@media(prefers-reduced-motion:reduce){
  html.js-motion .hero .eyebrow.reveal,
  html.js-motion .hero h1.reveal,
  html.js-motion .hero .hero-lead.reveal,
  html.js-motion .hero .hero-us.reveal,
  html.js-motion .hero .hero-cta.reveal,
  html.js-motion .hero .hero-viz.reveal{filter:none;transform:none}
  .hero h1 span{animation:none;background:none;-webkit-text-fill-color:currentColor;color:var(--gold)}
}

/* ---- mobile ---- */
@media(max-width:900px){
  .nav .wrap{height:64px;gap:10px}
  .mobile-menu{top:64px}
  /* 44px minimum touch target (WCAG 2.5.5) */
  .icon-btn,.burger{width:44px;height:44px}
  .lang-btn{height:44px;padding:0 .75rem}
  .mobile-menu a{min-height:44px;display:flex;align-items:center}
  .mm-lang{min-height:44px;display:inline-flex;align-items:center}
  /* Owner request 2026-08-03: the theme control moves into the burger menu on phones, and
     the wrapper loses its pill. With one button left inside it, the border and glass panel
     drew a box around a single icon and read as a second, competing control next to the
     burger. The buttons keep their own 44px targets, so nothing shrinks below WCAG 2.5.5. */
  .nav-actions{background:none;border:0;box-shadow:none;padding:0;border-radius:0}
  .nav-actions #themeBtn{display:none}
  /* Lighter glyphs, same hit area (owner request 2026-08-03). Only the drawn mark shrinks:
     the buttons stay 44px, so the touch target does not move. The burger carries inline
     width/height attributes in the markup, which CSS overrides. */
  .burger svg{width:19px;height:19px}
  .lang-btn svg{width:13px;height:13px}
}
@media(max-width:400px){
  /* Icon-only language button so brand + 3 controls stay on ONE row at 320px. */
  .lang-btn #langLabel{display:none}
  .lang-btn{width:44px;padding:0;justify-content:center}
}
@media(max-width:640px){
  /* Announcement banner: one line, never two. Text shrinks rather than wraps. */
  .topbanner{font-size:.74rem;gap:8px;white-space:nowrap;padding-inline:10px}

  /* Hero CTAs: identical width, identical height, single line each. */
  .hero-cta{display:grid;grid-template-columns:1fr;gap:10px;width:100%;max-width:340px;margin-inline:auto}
  .hero-cta .btn{width:100%;justify-content:center;white-space:nowrap}
  .hero-cta .btn.lg{padding:.9rem 1rem;font-size:.94rem}

  /* Slightly smaller display type, while small text stays >= 12px for legibility. */
  .hero h1{font-size:clamp(1.7rem,7.2vw,2.2rem);line-height:1.16}
  .hero-lead{font-size:.95rem}
  .hero-us{font-size:.88rem}
  .s-head h2{font-size:clamp(1.45rem,5.8vw,1.9rem)}
  .fcard h3{font-size:1rem}
  .fcard p{font-size:.88rem}
  .cc-tag{font-size:.75rem}
  .eyebrow{font-size:.68rem}
}

/* Motion-safe: entry animation must never hide content for reduced-motion users. */
@media(prefers-reduced-motion:reduce){
  html.js-motion .reveal{opacity:1;transform:none}
  .pre-sun{animation:none}
}

/* ---- mobile tap targets + legibility floor (footer, banner, brand) ---- */
@media(max-width:640px){
  .foot-col h5{font-size:.75rem}                 /* was .72rem = 11.5px */
  .foot-col a{min-height:44px;display:flex;align-items:center}
  .brand{min-height:44px}
  /* No link in the banner any more, so no 44px tap-target requirement. */
  .topbanner{min-height:36px;padding-block:.35rem}
}

/* ============================================================
   NAV GROUPING, FULL-SCREEN MENU, ADVANCED CARD STYLING
   ============================================================ */

/* Brand absorbs the free space so the controls sit together instead of the
   burger drifting to the far edge (space-between used to strand it). */
.nav .wrap{justify-content:flex-start}
.brand{margin-inline-end:auto}
.nav-links{margin-inline:auto}
.nav-actions{gap:10px}
/* True centring, desktop only. Three auto margins split the leftover space between a ~90px
   brand and a ~190px actions pill, so the links were centred in the gap rather than on the
   page and sat visibly off-axis. A 1fr auto 1fr grid pins the middle column to the real
   centre whatever the two sides weigh, which also stops the row shifting as the language
   changes and the link words change width. Scoped above 900px because the burger is display
   none there, so exactly three children take part; below it the flex row above still rules
   and centring is moot with the links hidden. */
@media(min-width:901px){
  .nav .wrap{display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
  .brand{grid-column:1;justify-self:start;margin-inline-end:0}
  .nav-links{grid-column:2;justify-self:center;margin-inline:0}
  .nav-actions{grid-column:3;justify-self:end}
}
@media(max-width:900px){
  .nav-links{margin-inline:0}
  .burger{margin-inline-start:10px}
}

/* ---- full-screen mobile menu ---- */
.mobile-menu{position:fixed;inset:0;top:0;width:100%;height:100dvh;max-height:none;
  background:var(--bg);border:0;box-shadow:none;padding:0;z-index:70;overflow:auto;
  flex-direction:column;gap:0}
.mobile-menu.open{display:flex;animation:mmIn .28s cubic-bezier(.22,1,.36,1)}
@keyframes mmIn{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:none}}
html.menu-open{overflow:hidden}
.mm-top{display:flex;align-items:center;justify-content:space-between;
  height:64px;padding-inline:clamp(16px,4vw,40px);flex:none}
.mm-top .brand{margin:0;font-size:1.15rem}
.mm-close{width:44px;height:44px}
.mm-links{display:flex;flex-direction:column;justify-content:center;flex:1;
  padding:clamp(16px,5vw,40px);gap:6px}
.mm-links a{padding:.9rem .4rem;font-size:1.35rem;font-weight:800;color:var(--text);
  border-radius:12px;min-height:56px;display:flex;align-items:center;gap:14px;text-decoration:none}
.mm-links a:last-child{border-bottom:0}
.mm-links a:hover,.mm-links a.nav-on{color:var(--gold);background:transparent}
/* The burger menu was the one navigation surface with no icons: the desktop rail has had them
   all along, so on a phone, the screen where scanning matters most, every row looked the same.
   The mark sits in a tinted tile so the column has an edge to read down, and it inherits the
   link's own colour, which is what carries the gold hover and the active state through to it. */
.mm-links .mm-ic{flex:none;width:38px;height:38px;border-radius:11px;display:grid;place-items:center;
  background:color-mix(in srgb,currentColor 11%,transparent);
  border:0;
  transition:background .15s ease,border-color .15s ease}
.mm-links .mm-ic svg{width:19px;height:19px}
.mm-links a:hover .mm-ic,.mm-links a.nav-on .mm-ic{background:color-mix(in srgb,var(--gold) 16%,transparent);}
.mm-links .mm-lbl{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(prefers-reduced-motion:reduce){.mm-links .mm-ic{transition:none}}
.mobile-menu > .btn.block{margin:0 clamp(16px,5vw,40px) calc(24px + env(safe-area-inset-bottom));
  width:auto;min-height:52px}

/* Theme control inside the burger menu (owner request 2026-08-03). It left the top bar so the
   nav carries the brand, one language button and the burger and nothing else. Built as a
   labelled row rather than a bare icon: in a full-screen menu an unlabelled moon has no
   neighbours to give it context, and the label names the mode it switches TO. */
.mm-foot{flex:none;padding:0 clamp(16px,5vw,40px) calc(20px + env(safe-area-inset-bottom))}
.mm-theme{display:flex;align-items:center;gap:14px;width:100%;min-height:56px;
  margin-top:8px;padding:.9rem .4rem;background:none;border:0;border-radius:12px;
  color:var(--text);font-family:inherit;font-size:1.05rem;font-weight:700;
  text-align:start;cursor:pointer}
.mm-theme:hover{color:var(--gold)}
.mm-theme:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.mm-theme-ic{display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:38px;height:38px;border-radius:11px;background:var(--panel2);color:var(--gold)}
.mm-theme-ic svg{width:19px;height:19px}

/* ---- stats: gradient ring, tabular numerals, even 2x2 on mobile ---- */
.stat-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:2.6rem}
/* Borderless: the gradient ring drew a hard edge on every tile, so the strip read as four
   boxes instead of four figures. The surface alone separates them now. */
.hstat{position:relative;background:var(--panel);
  border:none;border-radius:20px;padding:1.75rem 1.35rem 1.55rem;text-align:center;
  min-width:0;overflow:hidden;transition:transform .25s cubic-bezier(.22,1,.36,1),box-shadow .25s}
.hstat::after{content:"";position:absolute;inset-inline-start:-40%;top:-60%;width:60%;height:220%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.06),transparent);
  transform:skewX(-18deg);opacity:0;transition:opacity .3s}
.hstat:hover{transform:translateY(-4px);box-shadow:0 16px 38px rgba(0,0,0,.32)}
.hstat:hover::after{opacity:1;animation:shine 1.1s ease}
@keyframes shine{from{inset-inline-start:-40%}to{inset-inline-start:120%}}
/* direction:ltr + isolate, or RTL bidi renders "16+" as "+16". */
/* Lining + tabular figures so the four numbers share one baseline and one advance width,
   which is what makes a stat strip read as measured rather than typed. Tracking eased off
   -.03em: at this size it was pulling the digits into each other. */
.hstat b{display:block;font-size:clamp(1.75rem,5vw,2.45rem);font-weight:800;color:var(--gold);
  line-height:1.04;letter-spacing:-.015em;
  font-variant-numeric:lining-nums tabular-nums;font-feature-settings:"lnum" 1,"tnum" 1;
  direction:ltr;unicode-bidi:isolate}
.hstat span{color:var(--muted);font-size:.8rem;line-height:1.5;margin-top:.7rem;display:block;text-wrap:balance}
@media(max-width:640px){.stat-strip{grid-template-columns:1fr 1fr;gap:10px}}
/* #458: the clamp floor of 1.75rem is 28px, and at two tiles to a row on a 390px viewport the
   tile's content box is about 165px. "+261,286" at 28px with tabular figures measures 171px, so
   the number was clipped by 6px on /for-users and by 24px in Sorani, where the Arabic-Indic
   digits are wider. The number is LIVE (it is the listing count and it grows), so a font-size
   tuned to today's value would clip again on its own; the floor drops far enough that another
   digit still fits, and min-width:0 lets the track shrink instead of the text spilling. Measured
   at 390 and at 320 in both locales after the change. */
@media(max-width:420px){
  .hstat{min-width:0}
  .hstat b{font-size:clamp(1.15rem,6.2vw,1.6rem);letter-spacing:-.025em}
}
/* At 320 the 6.2vw term resolves to 19.8px and "+261,286" was still 2px over. The count only
   grows, so this floor is set for one more digit than today's value rather than for today's. */
@media(max-width:340px){
  .hstat b{font-size:1.02rem;letter-spacing:-.03em}
}

/* ---- feature cards: borderless, corner glow on hover, icon lift ----
   Borderless, matching .choose-card and .src-card. The old treatment drew a 1px --line
   border at rest and swapped in a masked 1px gradient ring on hover; against the dark panel
   that ring read as a hard gold outline rather than a highlight. Separation now comes from
   the surface itself (a slight top-lighter gradient) plus depth on hover, and the accent
   arrives as a soft corner glow instead of an edge. */
.fcard{position:relative;border:none;border-radius:var(--r);
  background:linear-gradient(180deg,color-mix(in srgb,var(--panel2) 60%,var(--panel)),var(--panel));
  padding:1.5rem;overflow:hidden;box-shadow:0 10px 26px -20px rgba(0,0,0,.9);
  transition:transform .3s cubic-bezier(.22,1,.36,1),box-shadow .3s}
/* Corner glow, not an outline. Sits behind the content (h3/p/.f-ic are position:relative). */
.fcard::before{content:"";position:absolute;inset-inline-end:-70px;top:-70px;width:190px;height:190px;
  border-radius:50%;background:radial-gradient(circle,rgba(224,182,74,.30),transparent 68%);
  filter:blur(26px);opacity:0;transition:opacity .35s,transform .35s;pointer-events:none}
/* The glow is an absolutely-positioned pseudo-element, so it paints above non-positioned
   block content. Without this the blur would wash over the heading and body text. */
.fcard > *{position:relative;z-index:1}
.fcard:hover{transform:translateY(-6px);box-shadow:0 22px 48px rgba(0,0,0,.34)}
.fcard:hover::before{opacity:.85;transform:scale(1.12)}
/* The glow is decorative; the card must not animate for reduced-motion users. */
@media(prefers-reduced-motion:reduce){.fcard:hover{transform:none}.fcard:hover::before{transform:none}}
.fcard .f-ic{transition:transform .3s cubic-bezier(.22,1,.36,1),box-shadow .3s}
.fcard:hover .f-ic{transform:translateY(-2px) scale(1.06);box-shadow:0 10px 24px rgba(224,182,74,.18)}

/* ---- everything-in-one-place cards ---- */
.aio-grid{gap:18px}
/* Borderless, same reasoning as .fcard above: this card already carries .aio-ring as its
   corner glow, so the outline was a second competing edge. */
.aio-card{position:relative;border:none;border-radius:20px;
  background:linear-gradient(180deg,color-mix(in srgb,var(--panel2) 60%,var(--panel)),var(--panel));
  padding:1.7rem 1.5rem;overflow:hidden;box-shadow:0 10px 26px -20px rgba(0,0,0,.9);
  transition:transform .3s cubic-bezier(.22,1,.36,1),box-shadow .3s}
.aio-card:hover{transform:translateY(-6px);box-shadow:0 24px 52px rgba(0,0,0,.34)}
.aio-ring{position:absolute;inset-inline-end:-70px;top:-70px;width:190px;height:190px;border-radius:50%;
  background:radial-gradient(circle,rgba(224,182,74,.30),transparent 68%);filter:blur(26px);
  opacity:.55;pointer-events:none;transition:opacity .35s,transform .35s}
.aio-card:hover .aio-ring{opacity:.9;transform:scale(1.12)}
.aio-ic{position:relative;width:52px;height:52px;border-radius:15px;display:flex;align-items:center;
  justify-content:center;color:var(--gold);margin-bottom:1.1rem;
  background:linear-gradient(135deg,rgba(224,182,74,.18),rgba(47,191,135,.09));
  border:none;transition:transform .3s cubic-bezier(.22,1,.36,1)}
.aio-card:hover .aio-ic{transform:rotate(-6deg) scale(1.06)}
.aio-ic svg{width:25px;height:25px}
.aio-card h3{position:relative;font-size:1.12rem;margin-bottom:.5rem}
.aio-card > p{position:relative;color:var(--muted);font-size:.92rem}
.aio-card ul{position:relative;list-style:none;margin-top:1.1rem;display:flex;flex-direction:column;gap:.6rem}
.aio-card li{display:flex;gap:9px;align-items:flex-start;color:var(--text);font-size:.88rem;opacity:.9}
.aio-ck{flex:none;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;
  justify-content:center;background:rgba(47,191,135,.14);color:var(--green);margin-top:2px}
.aio-ck svg{width:11px;height:11px}
/* Queue 351: this lost to the compound .grid.g3,.grid.g4{grid-template-columns:repeat(2,1fr)}
   rule above (higher specificity, two classes vs one), so aio-grid rendered 2 columns down to
   560px instead of the single column this rule always intended, stranding the 3rd card alone
   in a half-empty last row. Matching specificity restores the original intent. */
@media(max-width:900px){.grid.g3.aio-grid{grid-template-columns:1fr}}

/* ============================================================
   Features page expansion (2026-07-10): equal-height cards,
   bidi-safe mixed runs, plan comparison table, page mocks.
   ============================================================ */
.grid .fcard{display:flex;flex-direction:column;height:100%}
.fcard h3,.fcard p{text-align:start;unicode-bidi:isolate}
.fcard .f-mock{margin-top:auto;padding-top:1rem}
/* Queue 351 created this for the language-pill mock on site/index.html and kept it inline there.
   Queue 355 found site/features.html needed the same row, so it moves here: a pattern used by
   two marketing pages belongs in the stylesheet both of them load, or the two copies drift.
   The plain .f-mock is deliberately untouched, because it is also the wrapper for non-chip mock
   content (a stacked sponsored-listing row, a stats block) that is supposed to stack. */
.f-mock-chips{display:flex;gap:8px;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.f-mock-chips::-webkit-scrollbar{display:none}
.f-mock-chips>*{flex:none}
.countdown{flex-wrap:wrap}
/* review mock: owner reply bubble */
/* Border pass, 2026-08-31: surface-ladder measured this at 1:1 against its neighbour
   once the review-reply left border was removed; a firmer fill replaces it. */
.rev-reply{margin-top:10px;background:color-mix(in srgb,var(--text) 6%,var(--panel));border-radius:10px;padding:.6rem .8rem;font-size:.82rem;color:var(--muted)}
.rev-reply b{display:block;font-size:.72rem;color:var(--gold);margin-bottom:2px}
/* analytics mock bars */
.mbar{display:flex;align-items:center;gap:8px;font-size:.72rem;color:var(--muted)}
.mbar+.mbar{margin-top:7px}
.mbar .mb-l{flex:none;width:86px}
.mbar .mb-t{flex:1;height:7px;border-radius:99px;background:var(--panel2);overflow:hidden}
.mbar .mb-f{display:block;height:100%;border-radius:99px;background:linear-gradient(90deg,var(--gold),var(--green))}
.mbar b{color:var(--text);font-variant-numeric:tabular-nums}
/* plan comparison table: wide content scrolls inside its wrapper, never the page */
.cmp-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:var(--r);background:var(--panel)}
.cmp{width:100%;min-width:620px;border-collapse:collapse;font-size:.88rem}
.cmp th,.cmp td{padding:.75rem 1rem;text-align:start}
.cmp thead th{background:var(--panel2);font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);white-space:nowrap}
.cmp thead th b{display:block;color:var(--text);font-size:1rem;letter-spacing:0;text-transform:none}
.cmp thead th.hot b{color:var(--gold)}
.cmp thead th .cmp-note{font-weight:600}
.cmp tbody tr:last-child td{border-bottom:none}
.cmp td.c,.cmp th.c{text-align:center}
.cmp td.c svg{width:16px;height:16px;vertical-align:middle}
.cmp .ok{color:var(--green)}
.cmp .no{color:var(--muted);opacity:.45}
/* Mobile: the table still scrolls sideways, but the feature column no longer leaves with it.
   Without this the row label slid out of view exactly when you scrolled to reach Pro+, so the
   ticks you were comparing had nothing left to name them. The pinned column carries its own
   background and a hairline edge so the scrolling columns pass behind it rather than through
   it. Also a smaller min-width and tighter padding, so less of the table is off-screen to
   begin with. */
@media(max-width:700px){
  .cmp{min-width:470px;font-size:.75rem}
  .cmp th,.cmp td{padding:.45rem .55rem;line-height:1.35}
  .cmp thead th{font-size:.62rem;letter-spacing:.05em}
  .cmp thead th b{font-size:.82rem}
  .cmp thead th .cmp-note{font-size:.68rem}
  .cmp th:first-child,.cmp td:first-child{position:sticky;inset-inline-start:0;z-index:2;
    background:var(--panel);min-width:150px;max-width:176px}
  .cmp thead th:first-child{background:var(--panel2)}
  .cmp td.c,.cmp th.c{min-width:60px}
  .cmp td.c svg{width:13px;height:13px}
  /* Zebra instead of hairlines: fill-based separation per the borderless rule. The tint mixes
     from --text so it survives the light theme, and the sticky first cell repeats it opaquely
     so scrolling columns still pass behind, not through. */
  .cmp tbody tr:nth-child(even) td{background:color-mix(in srgb,var(--text) 4%,var(--panel))}
}

/* ============================================================
   Features page: scroll-driven staggered "flow" (2026-07-11)
   Different layout (offset bento rhythm) + a real scroll effect:
   cards rise & fade in on entry, and a soft gold glow tracks each
   card through the viewport. Uses the independent translate/scale
   properties so the :hover lift still composes. Falls back to the
   site's existing .reveal one-shot where scroll-driven animations
   aren't supported, and to fully-visible for reduced motion.
   ============================================================ */
.flow{gap:22px}
.flow .fcard{position:relative;border-radius:calc(var(--r) + 6px);
  background:linear-gradient(180deg,color-mix(in srgb,var(--gold) 5%,var(--panel)),var(--panel))}
.flow .fcard>*{position:relative;z-index:1}
.flow .fcard::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:0;
  background:radial-gradient(130% 90% at 50% -12%,rgba(224,182,74,.16),transparent 62%)}
.flow .fcard .f-ic{box-shadow:0 8px 22px rgba(224,182,74,.10)}
/* Flow cards reveal through the shared .reveal/.rv-in system (site.js MOTION_SEL already
   includes .fcard), so they animate on scroll on EVERY page, Safari included. The old
   Chromium-only animation-timeline:view() effect and the editorial margin stagger were
   removed here because they broke alignment and never revealed in Safari. */

/* Hide image source/credit chips (no source mention on imagery) */
.kband-credit,.kbx-credit{display:none!important}
/* Where a photograph's licence requires attribution anyway (CC BY-SA), the credit moves off
   the image and onto the page as one quiet line above the footer, which satisfies the licence
   without putting a source chip back on the imagery. */
/* No opacity here on purpose: fading text blends it toward the background and makes the
   contrast depend on whatever is behind it. The muted token is quiet enough on its own and
   measures 7.97:1, so the line stays readable for the people the attribution is actually for. */
.img-credits{color:var(--muted);font-size:.72rem;line-height:1.6;text-align:center;padding:0 1rem 1.4rem;margin:0}

/* ---- Giveaway promo (app-style card on the real C43 photo) ---- */
.gvp-card{position:relative;overflow:hidden;border-radius:22px;padding:26px 22px;background:linear-gradient(150deg,var(--panel) 0%,var(--panel2) 100%)}
.gvp-orbs{position:absolute;inset:0;pointer-events:none;z-index:0}
.gvp-orbs span{position:absolute;border-radius:50%;filter:blur(46px);opacity:.5}
.gvp-orbs span:first-child{width:260px;height:260px;background:radial-gradient(circle,var(--gold),transparent 70%);top:-90px;inset-inline-end:-60px}
.gvp-orbs span:last-child{width:220px;height:220px;background:radial-gradient(circle,var(--green),transparent 70%);bottom:-100px;inset-inline-start:-50px;opacity:.28}
.gvp-visual{position:absolute;inset:0;margin:0;border:0;border-radius:0;overflow:hidden;pointer-events:none}
.gvp-visual::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:1;background:linear-gradient(0deg,rgba(4,6,8,.92),rgba(4,6,8,.76) 50%,rgba(4,6,8,.88)),radial-gradient(120% 130% at 50% 42%,transparent 38%,rgba(4,6,8,.62))}
.gvp-visual img{width:100%;height:100%;object-fit:cover;object-position:center 70%;display:block}
.gvp-visual::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:2;opacity:.1;mix-blend-mode:overlay;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23g)'/></svg>");background-size:140px 140px}
.gvp-body{position:relative;z-index:1}
.gvp-kick{display:inline-flex;align-items:center;gap:7px;font-weight:800;font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--gold);border-radius:999px;padding:5px 12px}
.gvp-kick svg{width:14px;height:14px}
.gvp-title{margin:.7rem 0 .3rem;font-size:clamp(1.5rem,5vw,2.2rem);line-height:1.12;text-wrap:balance}
.gvp-sub{color:var(--muted);margin:0 0 1.1rem;max-width:52ch;text-wrap:pretty}
.gvp-pill{display:inline-flex;align-items:center;gap:6px;margin:.1rem 0 1.1rem;padding:.32rem .7rem;border-radius:999px;font-size:.74rem;font-weight:800;letter-spacing:.01em;color:var(--gold2);background:color-mix(in srgb,var(--gold) 14%,transparent)}
.gvp-pill svg{width:14px;height:14px;flex:none}
.gvp-prizes{display:grid;grid-template-columns:1fr;gap:10px;margin-bottom:1.3rem;align-items:stretch}
/* Border pass, 2026-08-31: this used to separate from .gvp-card's panel gradient with a
   1px ring (extras.css's now-removed .gvp-p1 box-shadow); surface-ladder measured the fill
   alone at 1.034:1 against its neighbour once that ring was gone, under the 1.06 floor. A
   firmer fill replaces it rather than restoring an edge. */
.gvp-prize{display:flex;align-items:center;gap:12px;border-radius:14px;padding:12px 14px;background:color-mix(in srgb,var(--text) 6%,var(--panel));min-height:62px}
/* The gold outline is gone (owner request). It was never a selected state, which is what
   blocked this: it marked FIRST PRIZE, and first place is already said twice over by the
   gold tier badge and the gold medal icon, against silver for second and bronze for third.
   Dropping the ring loses no information and stops one row shouting over the other two. */
.gvp-p1{}
.gvp-tier{flex:none;min-width:44px;padding:5px 6px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;border-radius:11px;background:var(--panel2);color:var(--gold)}
.gvp-ic{display:block;line-height:0}
.gvp-ic svg{width:22px;height:22px;display:block}
.gvp-ord{font-size:.58rem;font-weight:800;line-height:1;letter-spacing:.02em;opacity:.9}
.gvp-p1 .gvp-tier{background:linear-gradient(135deg,var(--gold),var(--gold2));color:var(--goldink,#231a05)}
.gvp-p2 .gvp-ic{color:#cbd5db}
.gvp-p3 .gvp-ic{color:#cd9b6a}
.gvp-pname{font-weight:500;font-size:.9rem;line-height:1.28;min-width:0;overflow-wrap:anywhere}
.gvp-howtitle{font-weight:800;font-size:.95rem;margin:0 0 .7rem;letter-spacing:-.01em}
.gvp-groups{display:grid;gap:.8rem;align-items:stretch;margin-bottom:.4rem}
.gvp-grp{display:flex;flex-direction:column;background:color-mix(in srgb,var(--text) 6%,color-mix(in srgb,var(--panel2) 60%,transparent));border-radius:14px;padding:.85rem .95rem}
.gvp-grp-h{display:flex;align-items:center;gap:8px;font-size:.7rem;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:var(--gold2);margin:0 0 .6rem;padding-bottom:.55rem}
.gvp-grp-h svg{width:15px;height:15px;flex:none;color:var(--gold)}
.gvp-ways{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:9px}
.gvp-grp .gvp-ways{margin:0}
.gvp-ways li{display:flex;align-items:center;gap:10px;color:var(--text);font-weight:600;font-size:.92rem;min-height:24px}
.gvp-ways li svg{flex:none;width:20px;height:20px;color:var(--gold)}
.gvp-foot{display:flex;flex-wrap:wrap;align-items:center;gap:12px 16px;margin-top:.9rem}
.gvp-draw{display:inline-flex;align-items:center;gap:7px;color:var(--muted);font-weight:700;font-size:.88rem}
.gvp-draw svg{width:16px;height:16px;color:var(--gold)}
.gvp-draw b{color:var(--text)}
.gvp-cta{margin-inline-start:auto;border:none;cursor:pointer;font:inherit;font-weight:800;color:var(--goldink,#231a05);background:linear-gradient(135deg,var(--gold),var(--gold2));border-radius:12px;padding:12px 18px;display:inline-block;text-decoration:none;text-align:center;transition:transform .15s,filter .15s}
.gvp-cta:hover{transform:translateY(-1px);filter:brightness(1.05)}
.gvp-fine{margin:1rem 0 0;color:var(--muted);font-size:.76rem;opacity:.9}
@media(min-width:640px){.gvp-groups{grid-template-columns:1fr 1fr}}
@media(min-width:720px){.gvp-card{padding:34px 32px}.gvp-prizes{grid-template-columns:repeat(3,1fr)}}
@media(min-width:860px){.gvp-card{padding:42px 40px}}
@media(max-width:600px){.gvp-foot{justify-content:center}.gvp-cta,[dir="rtl"] .gvp-cta{margin-inline:auto;width:100%}}
/* The card ALWAYS sits on the dark car photo + scrim, so overlaid text stays light in both themes. */
.gvp-card .gvp-title{color:#fff}
.gvp-card .gvp-sub,.gvp-card .gvp-howtitle,.gvp-card .gvp-fine,.gvp-card .gvp-draw{color:rgba(255,255,255,.82)}
.gvp-card .gvp-draw b{color:#fff}
.gvp-card .gvp-pname{color:#fff}
.gvp-card .gvp-ways li{color:rgba(255,255,255,.92)}
.gvp-card .gvp-prize{background:rgba(10,12,14,.55);border-width:0}
.gvp-card .gvp-p1{border-width:0}
/* The 2nd/3rd tier plate is a 12% white wash over a DARK panel, so it stays dark whatever the
   page theme is doing, and gold-as-text on it goes the wrong way in light mode: --gold2 resolves
   to #7a5804 and measured 1.88:1 on "3rd". The plate is committed dark, so its label is too. */
.gvp-card .gvp-tier{background:rgba(255,255,255,.12);color:#f2f5f4}
.gvp-card .gvp-p1 .gvp-ord{color:inherit}
.gvp-card .gvp-p1 .gvp-tier{background:linear-gradient(135deg,var(--gold),var(--gold2));color:var(--goldink,#231a05)}
.gvp-card .gvp-grp{background:rgba(10,12,14,.5);border-width:0}
.gvp-card .gvp-grp-h{color:#e6be5a;border-bottom-width:0}
.gvp-card .gvp-kick{color:#e6be5a;border-width:0}
.gvp-card .gvp-pill{color:#f0d488}

/* ==== The giveaway's 2026-08-12 finish pass, MOVED HERE from site/assets/extras.css =======
   Queue #489. Until 2026-08-21 this component was defined in two stylesheets and rendered two
   different ways depending on the page. extras.css carried a near-complete second copy plus
   this finish pass; index.html and for-users.html load extras.css after site.css so they got
   it, and for-business.html, preview.html and scoring.html render a giveaway and do not load
   extras.css at all, so on those three the owner's "remove the border around" request of
   2026-08-12 never arrived. Measured before the move at 1280 dark: .gvp-card .gvp-p1 computed
   box-shadow 'none' on /for-business against a gold 42% top sheen on / and /for-users.
   site.css is now the only definition and every page that renders a giveaway loads it.

   The original reasoning, kept because it is the reason these are not just deleted borders:
   a 1px outline does two jobs, separating the card from the page and drawing its shape. Delete
   it outright and the cards dissolve into the background, which is what makes "remove the
   borders" get asked a second time. So separation moves to the fill plus a top-edge sheen, and
   the border is set TRANSPARENT rather than removed so nothing shifts by a pixel and the hover
   states still have a border to colour.

   THREE RULES FROM extras.css WERE DELIBERATELY NOT CARRIED, each for a stated reason:
   - `.gvp-p1{box-shadow:none}`. site.css records the owner asking
     for that ring to go, and `.gvp-card .gvp-p1` below outranks it on every page anyway, so
     porting it would only resurrect the ring on a hypothetical giveaway outside a .gvp-card.
   - `.gvp-card .gvp-tier{color:var(--gold2)}`. It was overriding site.css's #f2f5f4, which
     carries a measured reason: the plate is a 12% white wash over a ground committed dark in
     both themes, and --gold2 resolves to #7a5804 in light, which measured 1.88:1 on "3rd".
     extras.css was winning that fight on / and /for-users, so dropping it is a fix.
   - `.gvp-ent`, `.gvp-card .gvp-ent` and `.gcine-chip .gvp-pname`. Dead on the marketing site:
     no site/*.html renders either class. They came across when the component was ported from
     the app, and the app's own index.html defines its own copies and never loads these sheets.
   ======================================================================================== */
/* Prize rows sit on the car photograph, so a light outline round each was drawing three hard
   rectangles over a picture. The translucent ground already separates them from the image. */
.gvp-prize{border-width:0}
/* Border pass, 2026-08-31: surface-ladder measured this at 1.034:1 against .gvp-card once
   its ring (already box-shadow:none here) was the only separation left; a darker, more
   opaque fill restores real contrast without bringing an edge back. */
.gvp-card .gvp-prize{background:rgba(6,8,9,.78);border-width:0;
  box-shadow:none}
/* First prize keeps a mark of its own, since it is what the section is selling. It moves from
   an outline to a lit top edge and a warmer ground, which reads as rank without a frame. */
.gvp-card .gvp-p1{border-width:0;
  background:linear-gradient(180deg,rgba(224,182,74,.16),rgba(10,12,14,.62) 62%);
  box-shadow:none}
.gvp-card .gvp-grp{border-width:0;background:rgba(6,8,9,.74);
  box-shadow:none}
.gvp-card .gvp-kick{border-width:0;background:rgba(255,255,255,.08)}
/* Second and third place: the ordinal reads on the pale plate, not in gold. Same reason as the
   .gvp-tier note above; this rule only ever lived in extras.css, so three pages never had it. */
.gvp-p2 .gvp-ord,.gvp-p3 .gvp-ord{color:#f2f5f4}
/* .gvp-sec{padding:1.4rem 0 2rem} is NOT carried across, and it was never live in extras.css
   either: `section.block` at line 365 is (0,1,1) against .gvp-sec's (0,1,0), so the element
   selector wins on specificity no matter which sheet loads last. Measured on the built page,
   before and after this move: the section computes 67.68px 0px both times, which is .block's
   clamp, not 1.4rem/2rem. Recorded rather than silently dropped so it does not get re-added as
   a fix; if the giveaway really needs its own section padding it has to be written as
   `section.gvp-sec` or scoped to the id. */
/* The tighter foot WAS live and is carried: extras.css set .4rem over site.css's .9rem. */
.gvp-foot{margin-top:.4rem}
[dir="rtl"] .gvp-cta{margin-inline-start:auto}
@media(min-width:720px){.gvp-ways{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.gvp-cta,[dir="rtl"] .gvp-cta{text-align:center}}

/* ===== Giveaway on phones =================================================================
   Owner request 2026-08-21: "make this section better: a bit smaller, more premium, on one
   line, with smaller fonts". The card had no small-screen type scale at all -- it went from
   the 720px padding step straight to the base rules, so a 375px phone read the same .9rem
   and 1rem sizes a 700px tablet did, inside 22px of padding. Everything below is scale and
   rhythm only: no colour, no token and no desktop rule is touched, and the composition is
   unchanged.

   "On one line" is read as the repeated element it is worst on: each prize row. One of three
   otherwise identical rows growing a second line is the thing that reads cheap. The title is
   brought down far enough to hold one line in Latin as well.

   SECOND COPY LIVES IN site/assets/extras.css AND WINS WHERE BOTH LOAD. This component is defined twice: site/assets/site.css
   carries the same block, and index.html and for-users.html load extras.css AFTER site.css,
   so on those two pages every duplicated property here beats it. The three other pages that
   render a giveaway (for-business, preview, scoring) do not load extras.css and are served by
   the site.css copy. The two blocks are therefore deliberately identical; dropping either one
   gives the same component two different mobile scales depending on the page. Cost of finding
   this out: one whole build-and-measure cycle, because the site.css block measured as having
   no effect at all. Filed as its own queue task. Keep them in step, or delete one copy of the
   component and repoint the three pages.

   The CTA is deliberately NOT shrunk. It is the only tap target in here and already sits near
   the 44px floor, so it gets an explicit min-height instead of a smaller padding. */
@media(max-width:560px){
  .gvp-card{padding:18px 15px;border-radius:18px}
  .gvp-kick{font-size:.63rem;padding:4px 10px;gap:6px}
  .gvp-kick svg{width:12px;height:12px}
  .gvp-title{font-size:1.2rem;line-height:1.18;margin:.55rem 0 .25rem;letter-spacing:-.02em}
  .gvp-sub{font-size:.82rem;line-height:1.5;margin:0 0 .85rem}
  .gvp-pill{font-size:.67rem;padding:.26rem .6rem;margin:.05rem 0 .85rem;gap:5px}
  .gvp-pill svg{width:12px;height:12px}
  .gvp-prizes{gap:7px;margin-bottom:1rem}
  /* Queue #490: gap 9px->6px, row padding-inline 10px->7px, tier min-width 36px->32px and its
     own padding-inline 5px->4px. Reclaims ~13px for .gvp-pname (177px->190px at 320px), which
     is exactly the margin prize 3's ckb string needed to wrap two lines instead of three
     (measured: 189px is the narrowest width that still gives two lines, 177px gave three).
     Every prize row gets it, not just the third, so the column stays one width per language. */
  .gvp-prize{gap:6px;padding:8px 7px;min-height:46px;border-radius:12px}
  .gvp-tier{min-width:32px;padding:4px 4px;border-radius:9px;gap:0}
  .gvp-ic svg{width:17px;height:17px}
  .gvp-ord{font-size:.5rem}
  /* line-height 1.28, matching the desktop rule, not the tighter 1.24 this breakpoint used to
     carry: this row was written for one line and now routinely wraps to two (ckb, kmr) or three
     (ckb, before the width fix above) at 320px, and the extra leading reads better on stacked
     Vazirmatn than the tighter value tuned for a single line. */
  .gvp-pname{font-size:.79rem;line-height:1.28}
  .gvp-ent{font-size:.62rem;padding:.14rem .5rem}
  .gvp-howtitle{font-size:.85rem;margin:0 0 .55rem}
  .gvp-groups{gap:.6rem}
  .gvp-grp{padding:.7rem .75rem;border-radius:12px}
  .gvp-grp-h{font-size:.63rem;margin:0 0 .5rem;padding-bottom:.45rem}
  .gvp-grp-h svg{width:13px;height:13px}
  .gvp-ways{gap:7px}
  .gvp-ways li{font-size:.82rem;gap:8px}
  .gvp-ways li svg{width:17px;height:17px}
  .gvp-foot{gap:10px 12px;margin-top:.8rem}
  .gvp-draw{font-size:.79rem}
  .gvp-draw svg{width:14px;height:14px}
  .gvp-cta{min-height:44px;display:inline-flex;align-items:center;justify-content:center;
    padding:11px 18px;border-radius:11px}
  .gvp-fine{font-size:.7rem;margin-top:.85rem}
}

/* ===== Hero: responsive rhythm + the connection visual =====
   The headline previously carried a hardcoded <br>, which fought text-wrap:balance
   and stranded the comma on its own line at some widths. The <br> is gone; balance
   now picks the break per viewport. The highlighted phrase is kept whole. */
.hero .wrap.center{max-width:min(1180px,95vw);padding-inline:clamp(1rem,4vw,2rem)}
.hero h1{
  font-size:clamp(2.3rem,1.3rem + 4.4vw,4.6rem);
  line-height:1.05;letter-spacing:-.015em;
  margin:clamp(1rem,2.6vw,1.6rem) 0 clamp(.9rem,2.2vw,1.3rem);
  text-wrap:balance;
  max-width:20ch;margin-inline:auto;      /* stops 4-5 word orphan lines on wide screens */
  overflow-wrap:break-word}
.hero h1 span{white-space:nowrap}          /* "one place" never splits */
/* #458: that rule was written for the home hero, where the gold phrase is "one place" and holding
   it on one line is the whole point. It is not scoped to that hero, so it also caught
   /for-business's "Kurdistan and the diaspora", which measures 436px and cannot fit a 320px
   screen under any font size the hero uses. The text was cut off; the page only escaped a
   scrollbar because body carries overflow-x:hidden, which hides the symptom and not the cause.
   Below 430px no hero phrase on this site fits on one line, so nowrap stops applying there. */
@media(max-width:430px){.hero h1 span{white-space:normal}}
.hero .hero-lead{
  font-size:clamp(1rem,.94rem + .42vw,1.16rem);
  line-height:1.6;max-width:56ch;margin-inline:auto;text-wrap:pretty}
.hero .hero-us{
  max-width:50ch;margin-block:.85rem 0;
  font-size:.98rem;font-weight:600;letter-spacing:.005em;
  text-align:center;text-wrap:pretty;
  color:color-mix(in oklab,var(--gold) 60%,var(--text));opacity:.92}
@media(max-width:520px){
  .hero h1{max-width:14ch;line-height:1.12}
  .hero .hero-lead{font-size:1rem;line-height:1.58}
}

/* --- animated connection visual: Kurdistan <-> the Kurdish world --- */
.hero-canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.hv-lbl{position:absolute;bottom:2%;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:color-mix(in oklab,var(--text) 74%,transparent);transform:translateX(-50%)}
.hv-home{inset-inline-start:11%}
.hv-world{inset-inline-start:89%;color:color-mix(in oklab,var(--gold) 82%,var(--text))}

/* ---------- scrollytelling story timeline (the "ways to earn") ---------- */
.story{position:relative;max-width:820px;margin:clamp(1.6rem,4vw,3rem) auto 0}
.story-rail{position:absolute;inset-block:44px 44px;inset-inline-start:26px;width:2px;
  background:color-mix(in oklab,var(--gold) 14%,var(--line));border-radius:2px;overflow:hidden}
.story-fill{position:absolute;inset-inline:0;top:0;height:0;border-radius:2px;
  background:linear-gradient(var(--gold),var(--green));box-shadow:0 0 12px color-mix(in oklab,var(--gold) 55%,transparent)}
.story-step{position:relative;display:grid;grid-template-columns:54px 1fr;gap:clamp(16px,2.6vw,30px);
  align-items:start;padding-block:clamp(22px,4vw,44px)}
.story-node{width:54px;height:54px;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--panel);color:var(--muted);position:relative;z-index:2;
  transition:color .45s ease,border-color .45s ease,background .45s ease,box-shadow .45s ease,transform .45s cubic-bezier(.16,1,.3,1)}
.story-node svg{width:24px;height:24px}
.story-step.on .story-node{color:var(--gold);transform:scale(1.06);background:color-mix(in oklab,var(--gold) 12%,var(--panel));box-shadow:0 0 0 5px color-mix(in oklab,var(--gold) 9%,transparent),0 0 26px -4px color-mix(in oklab,var(--gold) 65%,transparent);}
.story-body{padding-top:5px}
.story-n{display:block;font-size:.78rem;font-weight:800;letter-spacing:.14em;margin-bottom:3px;
  color:color-mix(in oklab,var(--gold) 68%,var(--muted))}
.story-body h3{font-size:clamp(1.18rem,2.5vw,1.6rem);margin:0 0 .4rem;letter-spacing:-.01em}
.story-body p{color:var(--muted);line-height:1.66;max-width:54ch;margin:0}
/* reveal via the site-wide .reveal/.rv-in system (proven IntersectionObserver) so the
   steps are NEVER stuck invisible if the scroll-progress handler misbehaves */
html.js-motion .story-step.reveal{opacity:0;transform:translateY(38px);filter:blur(7px);
  transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .95s cubic-bezier(.16,1,.3,1),filter .8s ease}
html.js-motion .story-step.reveal.rv-in{opacity:1;transform:none;filter:blur(0)}
@media(prefers-reduced-motion:reduce){html.js-motion .story-step.reveal{opacity:1;transform:none;filter:none}}
@media(max-width:520px){
  .story-step{grid-template-columns:44px 1fr;gap:14px}
  .story-node{width:44px;height:44px}.story-node svg{width:20px;height:20px}
  .story-rail{inset-inline-start:21px}
}
.hero-viz{position:relative;width:min(780px,92vw);margin:clamp(1.8rem,4vw,2.8rem) auto 0;
  aspect-ratio:620/150;pointer-events:none;user-select:none}
.hero-viz svg{width:100%;height:100%;overflow:visible;display:block}
/* Arc: brighter, thicker, softly glowing so the connection reads as intentional
   rather than a faint hairline. */
.hero-viz .arc{fill:none;stroke:var(--gold);stroke-width:1.6;opacity:.62;
  stroke-dasharray:5 7;animation:hv-flow 5.5s linear infinite;
  filter:drop-shadow(0 0 3px color-mix(in oklab,var(--gold) 45%,transparent))}
.hero-viz .arc.b{animation-duration:7s;opacity:.44}
.hero-viz .arc.c{animation-duration:9s;opacity:.34}
.hero-viz .base{fill:none;stroke:color-mix(in oklab,var(--gold) 20%,var(--line2));stroke-width:1.2;opacity:.6}
.hero-viz .node{fill:var(--gold);filter:drop-shadow(0 0 5px color-mix(in oklab,var(--gold) 75%,transparent))}
.hero-viz .node.far{fill:var(--green);filter:drop-shadow(0 0 5px color-mix(in oklab,var(--green) 75%,transparent))}
.hero-viz .halo{fill:none;stroke:var(--gold);stroke-width:1.2;opacity:0;
  transform-box:fill-box;transform-origin:center;animation:hv-pulse 3.4s ease-out infinite}
.hero-viz .halo.far{stroke:var(--green)}
.hero-viz .n2 .halo{animation-delay:.85s}
.hero-viz .n3 .halo{animation-delay:1.7s}
.hero-viz .n4 .halo{animation-delay:2.55s}
.hero-viz .lbl{fill:color-mix(in oklab,var(--text) 74%,transparent);font-size:11px;font-weight:700;letter-spacing:.06em;
  text-anchor:middle;text-transform:uppercase}
.hero-viz .lbl.dest{fill:color-mix(in oklab,var(--gold) 82%,var(--text))}
.hero-viz .spark{fill:var(--gold2);opacity:1;
  filter:drop-shadow(0 0 4px color-mix(in oklab,var(--gold) 80%,transparent));
  animation:hv-travel 5.5s cubic-bezier(.45,0,.55,1) infinite}
.hero-viz .spark.b{animation-duration:7s;animation-delay:1.2s;fill:var(--green);
  filter:drop-shadow(0 0 4px color-mix(in oklab,var(--green) 80%,transparent))}

@keyframes hv-flow{to{stroke-dashoffset:-96}}
@keyframes hv-pulse{
  0%{opacity:.55;transform:scale(.6)}
  70%{opacity:0;transform:scale(2.6)}
  100%{opacity:0;transform:scale(2.6)}}
@keyframes hv-travel{
  0%{offset-distance:0%;opacity:0}
  8%{opacity:.95}
  92%{opacity:.95}
  100%{offset-distance:100%;opacity:0}}

@media(max-width:520px){
  .hero-viz{width:94vw;aspect-ratio:620/170}
  .hero-viz .lbl{font-size:13px}
}
/* Motion is decoration, never information. */
@media(prefers-reduced-motion:reduce){
  .hero-viz .arc,.hero-viz .halo,.hero-viz .spark{animation:none}
  .hero-viz .arc{stroke-dasharray:none;opacity:.3}
  .hero-viz .spark{opacity:0}
}

/* ---- giveaway: the three rewards, stated before the mechanics ---- */
.gv-rewards{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  gap:14px;margin:1.4rem auto 1.6rem;max-width:1000px}
/* Borderless by owner decision: the outlines read as three boxed columns rather than one
   band of rewards. The fill carries the surface instead, lifted a step so the cards still
   separate from the section background now that nothing outlines them. */
.gv-rw{background:linear-gradient(160deg,color-mix(in srgb,var(--panel2) 72%,var(--panel)),var(--panel2));
  border:0;border-radius:16px;padding:1.15rem 1.2rem;
  display:flex;flex-direction:column;gap:.4rem;text-align:start}
.gv-rw-ic{width:42px;height:42px;border-radius:12px;display:inline-flex;align-items:center;
  justify-content:center;background:color-mix(in oklab,var(--gold) 14%,transparent);
  color:var(--gold);border:0;
  margin-bottom:.25rem}
.gv-rw-ic svg{width:21px;height:21px}
.gv-rw b{font-size:1rem;font-weight:800;letter-spacing:-.01em}
.gv-rw span:last-child{color:var(--muted);font-size:.9rem;line-height:1.55;text-wrap:pretty}
@media(max-width:560px){.gv-rewards{gap:11px;margin:1.1rem auto 1.3rem}
  .gv-rw{padding:1rem}.gv-rw b{font-size:.96rem}}

/* ===== Staggered card reveal (scrollytelling) =====
   The existing .reveal/.rv-in system fires whole elements at once, and items
   scrolled into view got show(el,0), so a grid of cards popped simultaneously.
   Here the CONTAINER is observed and its children cascade via nth-child delays,
   so each card lands one after another. Pure CSS delays: no per-node JS.
   Gated on html.js-motion so a no-JS page still shows everything. */
/* #829, 2026-09-06: the entrance transform is scoped to `:not(.rv-in)` and the `.rv-in` rule no
   longer says `transform:none`. It used to, and that one declaration killed EVERY hover lift on
   this page: `html.js-motion .rv-stagger.rv-in > *` is (0,3,1) and every hover lift here is a
   class plus a pseudo-class, (0,2,0), so once a grid finished revealing the lift was pinned off
   for good. Measured with a real mouse in real Chrome, each grid scrolled in and given 1.4s to
   settle: 12 containers, 49 cards, 11 of 12 declared a lift and 0 of them moved. The same cards
   on /for-business, /for-users, /features and /pricing lifted normally the whole time, because
   extras.js (which applies .rv-stagger) ships on the home page only - that asymmetry was the
   tell. The transition stays on the unscoped rule so it applies in BOTH states; moving it into
   the `:not(.rv-in)` rule would make the element stop matching it the instant `.rv-in` lands and
   the entrance would snap instead of animating. */
html.js-motion .rv-stagger > *{
  transition:opacity .62s cubic-bezier(.22,1,.36,1),transform .62s cubic-bezier(.22,1,.36,1)}
html.js-motion .rv-stagger:not(.rv-in) > *{
  opacity:0;transform:translateY(22px) scale(.988)}
html.js-motion .rv-stagger.rv-in > *{opacity:1}
html.js-motion .rv-stagger.rv-in > *:nth-child(1){transition-delay:.02s}
html.js-motion .rv-stagger.rv-in > *:nth-child(2){transition-delay:.10s}
html.js-motion .rv-stagger.rv-in > *:nth-child(3){transition-delay:.18s}
html.js-motion .rv-stagger.rv-in > *:nth-child(4){transition-delay:.26s}
html.js-motion .rv-stagger.rv-in > *:nth-child(5){transition-delay:.34s}
html.js-motion .rv-stagger.rv-in > *:nth-child(6){transition-delay:.42s}
html.js-motion .rv-stagger.rv-in > *:nth-child(7){transition-delay:.50s}
html.js-motion .rv-stagger.rv-in > *:nth-child(8){transition-delay:.58s}
html.js-motion .rv-stagger.rv-in > *:nth-child(9){transition-delay:.66s}
html.js-motion .rv-stagger.rv-in > *:nth-child(n+10){transition-delay:.72s}

/* Card polish: a light edge that warms on hover, and a lift. Kept subtle so it
   reads as depth rather than decoration. */
.fcard{transition:transform .28s cubic-bezier(.22,1,.36,1),border-color .28s,box-shadow .28s;
  position:relative}
@media(hover:hover){
  .fcard:hover{transform:translateY(-4px);box-shadow:0 18px 44px rgba(0,0,0,.34);}
  /* #822: read `box-shadow:none 0 8px 26px ...` until 2026-09-04. The value contains var(), so
     the CSSOM returned it verbatim and only the computed value showed it dead. Measured with
     :hover forced on every card: 26 of 26 icons on /for-business and 25 of 25 on /features
     went from `none` to this glow. On / it changes nothing and never did - all 39 icons there
     are outranked, 14 by `.grid .fcard:hover .f-ic` in extras.css and 25 by the
     `#overview` / `#services` / `#pledge` rules that suppress the glow on purpose. Measuring
     the home page alone would have called this rule dead on eight pages. */
  .fcard:hover .f-ic,.fcard:hover .fc-ic{
    color:var(--gold2);
    box-shadow:0 8px 26px color-mix(in oklab,var(--gold) 20%,transparent)}
}
.fcard .f-ic,.fcard .fc-ic{transition:color .28s,box-shadow .28s}

@media(prefers-reduced-motion:reduce){
  html.js-motion .rv-stagger > *{opacity:1;transform:none;transition:none}
  .fcard,.fcard .f-ic,.fcard .fc-ic{transition:none}
  @media(hover:hover){.fcard:hover{transform:none}}
}

/* Progressive image loading (paired with imgFade() in site.js). The shimmer holds the image's
   space while it decodes; the image fades in on load. Scoped to .img-fx so no-JS pages are
   unaffected, and the motion is gated so reduced-motion users get the image instantly, no fade. */
.img-fx .img-lazy:not(.is-loaded){
  background-image:linear-gradient(100deg,var(--panel) 30%,var(--panel2) 50%,var(--panel) 70%);
  background-size:200% 100%;background-repeat:no-repeat;
}
@media (prefers-reduced-motion:no-preference){
  .img-fx .img-lazy{opacity:0;transition:opacity .6s ease}
  .img-fx .img-lazy.is-loaded{opacity:1}
  .img-fx .img-lazy:not(.is-loaded){animation:imgShimmer 1.5s linear infinite}
}
@keyframes imgShimmer{to{background-position:-200% 0}}

/* ---- sponsorship/boost mockup: gold border + Sponsored tag preview (desktop + phone frames).
   Same pattern as the business dashboard's Boost tab, ported here for the marketing pages. */
.bp-row{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center}
.bp-frame{background:var(--panel2);border:0;border-radius:14px;overflow:hidden;box-shadow:0 14px 32px -22px rgba(0,0,0,.7)}
.bp-desktop{flex:1 1 320px;max-width:420px}
.bp-phone{flex:0 0 168px;width:168px}
.bp-bar{display:flex;gap:5px;padding:8px 10px;background:var(--panel);border-bottom:0}
.bp-bar i{width:7px;height:7px;border-radius:50%;background:var(--line2)}
.bp-notch{height:16px;background:var(--panel);border-bottom:0;position:relative}
.bp-notch::after{content:"";position:absolute;top:4px;left:50%;transform:translateX(-50%);width:44px;height:6px;border-radius:99px;background:var(--line2)}
.bp-body{display:flex;flex-direction:column;gap:8px;padding:10px}
.bp-card{position:relative;display:flex;align-items:center;gap:8px;padding:8px;border-radius:10px;background:var(--panel)}
.bp-card.spon{border-width:0;background:color-mix(in srgb,var(--gold) 8%,var(--panel))}
.bp-thumb{width:30px;height:30px;border-radius:8px;background:var(--line2);flex:none}
.bp-card.spon .bp-thumb{background:color-mix(in srgb,var(--gold) 30%,var(--line2))}
.bp-g{flex:1;display:flex;flex-direction:column;gap:5px;min-width:0}
.bp-g b{display:block;height:7px;width:70%;border-radius:4px;background:var(--line2)}
.bp-g i{display:block;height:6px;width:45%;border-radius:4px;background:var(--line2);opacity:.7}
.bp-card.spon .bp-g b,.bp-card.spon .bp-g i{background:color-mix(in srgb,var(--gold) 40%,var(--line2))}
.bp-tag{position:absolute;top:-7px;inset-inline-end:8px;font-size:.6rem;font-weight:800;letter-spacing:.03em;color:var(--goldink,#231a05);background:var(--gold);padding:.1rem .5rem;border-radius:99px}

/* ===== Kurdify AI section (ported from the app 2026-07-24: proof bar, chat mockup, skills, comparison, agents). Strings are wired via data-i18n in site.js. ===== */
.app-suite{margin-top:3.2rem;padding-top:2.6rem}
.suite-wrap{display:flex;flex-wrap:wrap;justify-content:center;align-items:stretch;gap:clamp(14px,2vw,24px);margin-top:1.4rem}
.px-side{flex:1 1 340px;max-width:500px;display:flex;flex-direction:column;justify-content:center;gap:14px}
/* Wide screens put the section copy, the phone and the assistant cards on ONE centred row of
   three columns. .suite-wrap goes display:contents so its two children join the same flex row
   instead of forming a nested one; below 1180px nothing changes and the old stack returns. */
@media(min-width:1180px){
  .suite-row{display:flex;align-items:center;justify-content:center;
    gap:clamp(24px,3vw,48px);max-width:1400px;margin-inline:auto}
  .suite-row > .s-head{flex:0 1 380px;max-width:380px;margin-bottom:0}
  .suite-row .suite-wrap{display:contents}
  .suite-row .suite-phone{flex:0 0 auto}
  .suite-row .suite-cards{flex:0 1 480px;max-width:480px;
    display:flex;flex-direction:column;justify-content:center;gap:12px;margin-top:0}
}
@media(max-width:820px){.suite-phone{margin-inline:auto}}
/* Owner request 2026-08-12: centre this section's head on phones. The phone mockup under it is
   already centred by the rule above, so a start-aligned kicker, headline, chip and paragraph
   sitting over a centred device read as two different layouts stacked. Scoped to #kurdify-ai
   and to the phone range on purpose: .s-head is the shared section header for the whole page,
   and centring it globally would restyle every section from one screenshot of this one. The
   chip needs its own rule because text-align does not move an inline-flex box. */
@media(max-width:820px){
  #kurdify-ai .s-head{text-align:center;margin-inline:auto}
  #kurdify-ai .s-head .suite-onlyapp{margin-inline:auto}
}
.suite-phone{position:relative;width:264px;padding:34px 16px 24px;border-radius:40px;background:linear-gradient(165deg,var(--panel2),var(--panel));box-shadow:0 30px 60px -30px rgba(0,0,0,.8)}
.spx-island{position:absolute;top:16px;left:50%;transform:translateX(-50%);width:84px;height:20px;border-radius:100px;background:#060d10}
.sp-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.sp-app{aspect-ratio:1;border-radius:24%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;color:#0d1619}
.sp-app svg{width:26px;height:26px}
.sp-app em{font-style:normal;font-size:.5rem;font-weight:800;letter-spacing:.02em;opacity:.85}
.sp-c1{background:linear-gradient(150deg,var(--gold2),var(--gold))}
.sp-c2{background:linear-gradient(150deg,#e8907e,#d96a5c);color:#2a0f0a}
.sp-c3{background:linear-gradient(150deg,#43c99a,#1f9d6b);color:#04140d}
.sp-c4{background:linear-gradient(150deg,#9fb8c9,#6f8a9d);color:#0d1a22}
.sp-app.lk{background:color-mix(in srgb,var(--panel2) 80%,transparent);color:var(--muted)}
.sp-app.lk svg{width:18px;height:18px;opacity:.7}
.sp-note{margin-top:14px;text-align:center;font-size:.68rem;font-weight:700;color:var(--muted)}
.suite-cards{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:640px){.suite-cards{grid-template-columns:1fr}}
.suite-card{display:flex;align-items:center;gap:13px;background:var(--panel);border-radius:16px;padding:1rem 1.1rem;transition:border-color .15s,transform .15s}
.suite-card:hover{transform:translateY(-1px);}
.sc-ic{width:44px;height:44px;border-radius:13px;flex:none;display:flex;align-items:center;justify-content:center}
.sc-ic svg{width:22px;height:22px}
.suite-card b{display:block;font-size:.95rem;margin-bottom:.25rem}
.suite-card p{margin:0;font-size:.83rem;line-height:1.65;color:var(--muted);text-wrap:pretty}
.suite-locked{grid-column:1/-1;display:flex;align-items:center;justify-content:center;gap:.6rem;padding:.8rem 1rem;border-radius:14px;color:var(--muted);font-size:.85rem;font-weight:700;background:color-mix(in srgb,var(--gold) 4%,transparent)}
.suite-locked svg{width:16px;height:16px;color:var(--gold2);flex:none}
/* Kurdify AI: "why better than ChatGPT" comparison + specialist agents grid */
.pcmp{margin-top:2.6rem}
.pcmp-h{text-align:center;font-size:clamp(1.3rem,3.4vw,1.8rem);font-weight:800;text-wrap:balance;margin:0 0 1.25rem}
/* ONE TABLE ON BOTH HOSTS (owner request 2026-08-25: change this to the app's version).
   This block spent 2026-08-12 to 2026-08-20 becoming a continuous ruled panel: zero row-gap,
   corner radii only on the first and last child of each column, inset hairlines between rows,
   a gradient on the winning column and a coloured disc behind every icon. app.kurdify.app never
   took any of it and kept the plain version - eight separately rounded cards on a 10px grid, a
   flat fill per side, and a bare tick. That is the one the owner picked, so the values below are
   copied from index.html's `.pcmp-*` block rather than re-derived, and the divider/disc rules
   that used to follow this one are deleted rather than overridden, so the two hosts cannot drift
   back apart. The tick is `--green` here, not gold: the ruled version had to tint it gold to sit
   on a gold-ruled column, and with the rules gone the tick is the only mark that says "yes". */
.pcmp-table{display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:940px;margin-inline:auto}
.pcmp-colh{display:flex;align-items:center;justify-content:center;gap:9px;font-weight:800;font-size:.98rem;padding:12px 14px;border-radius:12px}
.pcmp-colh svg{width:18px;height:18px;flex:none}
.pcmp-us{background:color-mix(in srgb,var(--gold) 14%,var(--panel));border:none;color:var(--gold2)}
.pcmp-them{background:var(--panel2);border:none;color:var(--muted)}
.pcmp-cell{display:flex;align-items:flex-start;gap:9px;padding:13px 15px;border-radius:12px;font-size:.9rem;font-weight:600;line-height:1.42;text-wrap:pretty}
.pcmp-cell svg{width:17px;height:17px;flex:none;margin-top:1px}
.pcmp-yes{background:color-mix(in srgb,var(--gold) 8%,var(--panel));border:none;color:var(--text)}
.pcmp-yes svg{color:var(--green)}
.pcmp-no{background:var(--panel2);border:none;color:var(--muted)}
.pcmp-no svg{color:color-mix(in srgb,#e0685c 80%,var(--muted))}
.pag{margin-top:2.8rem}
.pag-h{text-align:center;font-size:clamp(1.3rem,3.4vw,1.8rem);font-weight:800;text-wrap:balance;margin:0 0 .3rem}
.pag-sub{text-align:center;color:var(--muted);margin:0 auto 1.35rem;max-width:52ch;text-wrap:pretty}
.pag-grid{display:flex;flex-wrap:wrap;justify-content:center;gap:10px;max-width:820px;margin-inline:auto}
.pag-card{position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:9px;
  background:var(--panel);border-radius:999px;padding:7px 16px 7px 8px;cursor:default;
  transition:border-color .22s ease,background-color .22s ease,transform .22s cubic-bezier(.2,.8,.25,1),box-shadow .22s ease}
/* A narrow highlight that sweeps across the pill once on hover. It sits on a negative z-index
   inside the pill's own stacking context, so it paints over the pill background but under the
   icon and label, and the pill never needs overflow:hidden (which would clip the icon ring). */
.pag-card::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;
  background:linear-gradient(105deg,transparent 38%,color-mix(in srgb,var(--gold) 20%,transparent) 50%,transparent 62%);
  background-size:240% 100%;background-position:140% 0;opacity:0;
  transition:opacity .2s ease,background-position .6s cubic-bezier(.25,.7,.3,1)}
.pag-card:hover{background:color-mix(in srgb,var(--gold) 7%,var(--panel));transform:translateY(-3px);box-shadow:0 12px 26px -16px rgba(224,182,74,.75),0 3px 10px -6px rgba(0,0,0,.65);}
.pag-card:hover::before{opacity:1;background-position:-40% 0}
.pag-ic{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--gold) 15%,var(--panel2));color:var(--gold);flex:none;
  transition:transform .22s cubic-bezier(.2,.8,.25,1),background-color .22s ease,box-shadow .22s ease}
.pag-card:hover .pag-ic{transform:scale(1.07);background:color-mix(in srgb,var(--gold) 26%,var(--panel2));
  box-shadow:none}
.pag-ic svg{width:18px;height:18px}
.pag-card b{font-size:.92rem;white-space:nowrap;transition:color .22s ease}
.pag-card:hover b{color:color-mix(in srgb,var(--gold) 22%,var(--text))}
/* "and more" is not an agent, so it reads as a ghost pill: muted, no gold lift.
   Owner request 2026-08-20 ("fix this design"): the dashed rim goes. After the border-removal
   rounds this was the only visible edge left in the agent chip row, so the one chip that is
   meant to be the QUIET one was the loudest object in it, and a dashed ring reads as a focus
   state stuck on. It stays quiet through its ground and its muted label instead.
   The resting ground sits BELOW the hover ground on purpose: the old resting state was
   transparent, so dropping the rim and taking the hover value for rest would have left the
   chip with no hover response at all. 14 rest / 30 hover keeps a real state change. */
.pag-card.pag-more{background:color-mix(in srgb,var(--line2) 14%,transparent);border:0}
.pag-card.pag-more .pag-ic{background:color-mix(in srgb,var(--line2) 50%,transparent);color:var(--muted)}
.pag-card.pag-more b{color:var(--muted);font-weight:600}
.pag-card.pag-more::before{display:none}
.pag-card.pag-more:hover{background:color-mix(in srgb,var(--line2) 30%,transparent);box-shadow:none;transform:translateY(-2px);}
.pag-card.pag-more:hover b{color:var(--text)}
.pag-card.pag-more:hover .pag-ic{background:color-mix(in srgb,var(--line2) 70%,transparent);color:var(--text);box-shadow:none}
@media(prefers-reduced-motion:reduce){
  .pag-card,.pag-card::before,.pag-ic{transition-duration:.01ms}
  .pag-card:hover,.pag-card.pag-more:hover{transform:none}
  .pag-card:hover .pag-ic{transform:none}
}
@media(max-width:560px){.pag-card{padding:6px 13px 6px 7px}.pag-card b{font-size:.86rem}.pag-ic{width:28px;height:28px}.pag-ic svg{width:16px;height:16px}}

/* ==== Comparison table and agent chips, 2026-08-12 =======================================
   Owner: "remove the border around, make better design and smaller font in mobile" for the
   table, and "make this all smaller in 2 rows for mobile" for the chips. */

/* The eight cells carried a 1px outline each until 2026-08-12; the fills carry the shape now
   and nothing is drawn around them. The inset row dividers and the two nth-child exemptions
   that lived here from 2026-08-12 to 2026-08-25 are GONE with the continuous-panel layout they
   belonged to (see the .pcmp block above): with a 10px row gap there is nothing for a divider
   to divide, and left behind they would have drawn a hairline across the top of every card. */

@media(max-width:560px){
  /* Smaller on phones. At .83rem the cells were running three and four lines each, so a
     three-row comparison filled a whole screen and the two sides no longer sat beside each
     other in one look, which is the only reason a comparison is a table. */
  .pcmp-h{font-size:clamp(1.15rem,5.2vw,1.4rem);margin-bottom:1rem}
  .pcmp-table{gap:7px}
  .pcmp-cell{padding:9px 10px;font-size:.76rem;gap:6px;line-height:1.45;border-radius:10px}
  .pcmp-cell svg{width:15px;height:15px;flex:none}
  .pcmp-colh{font-size:.78rem;padding:8px 9px;gap:6px;border-radius:10px}
  .pcmp-colh svg{width:16px;height:16px}
}

@media(max-width:560px){
  /* Seven chips in exactly two rows (owner request). This deliberately sets aside the standing
     "chip rows stay on one line" default, which is about a row silently wrapping into a ragged
     second line; two rows here are the asked-for shape, and flex-wrap with a centred main axis
     gives 4 + 3 centred rather than 4 + 3 ragged to one edge.

     The sizes are what make two rows possible rather than three: measured at 390px the row has
     342px of usable width, and the seven pills total roughly 580px, which is two rows with room
     to spare and three rows at the previous size. */
  .pag-grid{gap:7px}
  .pag-card{padding:4px 11px 4px 5px;gap:6px}
  .pag-card b{font-size:.75rem}
  .pag-ic{width:23px;height:23px}
  .pag-ic svg{width:13px;height:13px}
  .pag-h{font-size:clamp(1.15rem,5.2vw,1.4rem)}
  .pag-sub{font-size:.85rem;margin-bottom:1.1rem}
}
/* Kurdify AI chat mockup: styled like a real app screen (status bar, app bar, chat, input) */
/* Owner request 2026-08-20 (queue 479): make it a phone mockup again. What the 2026-08-20
   round deleted earlier that day was not a device, it was a gradient panel the full height of
   the row with no bezel, so it read as a decorative background column. The bezel is the whole
   point, so it is drawn as one: a 9px TRANSPARENT BORDER carrying the frame material through
   background-clip:border-box, with the screen painted on the padding box underneath it. That
   is what buys the inner radius for free (46 - 9 = 37) and what makes overflow:hidden clip the
   chat to the screen instead of to the outer shell. The dynamic island and the home indicator
   are drawn on top of the screen, not on the content, so no markup changed.
   The outer footprint STAYS 300px: 320px is a real width in the proof matrix and the marketing
   home measures 0 problems there, so the frame is paid for out of the screen, not the page.
   The palette pin below (.px-phone{--text:...}) is what keeps the screen readable in light
   theme and STAYS. */
.px-phone{width:300px;padding:0;display:flex;flex-direction:column}
/* One compound rule owns the frame, so a later reorder of the two single-class selectors
   cannot take half of it away, which is how the shell lost its background once already. */
.suite-phone.px-phone{position:relative;overflow:hidden;
  border:0;border-radius:46px;
  background:linear-gradient(180deg,#0f1d22,#0c171b) padding-box,
             linear-gradient(155deg,#3b4a52,#152126 34%,#0a1216 68%,#2e3d44) border-box;
  box-shadow:0 42px 72px -34px rgba(0,0,0,.85),
             0 0 0 1px color-mix(in srgb,#eaf4f2 8%,transparent),
             inset 0 1px 0 rgba(255,255,255,.10)}
/* The island sits in the gap the status bar already leaves between the clock and the icons. */
.suite-phone.px-phone::before{content:"";position:absolute;z-index:3;top:7px;left:50%;
  transform:translateX(-50%);width:78px;height:19px;border-radius:100px;background:#05090b;
  box-shadow:none}
.px-phone .spx-island{display:none}
.px-status{display:flex;align-items:center;justify-content:space-between;padding:13px 22px 7px;color:var(--text)}
.px-time{font-size:.74rem;font-weight:800;letter-spacing:.01em}
.px-stat-ic{display:inline-flex;align-items:center;gap:6px}
.px-stat-ic svg{height:11px;width:auto;color:var(--text)}
.px-stat-ic svg:nth-child(3){height:12px}
.px-appbar{display:flex;align-items:center;gap:10px;padding:6px 16px 12px;border-bottom:0}
.px-logo{width:34px;height:34px;border-radius:11px;background:linear-gradient(150deg,var(--gold2),var(--gold));color:var(--goldink,#231a05);display:flex;align-items:center;justify-content:center;flex:none;box-shadow:0 4px 12px -4px rgba(224,182,74,.6)}
.px-logo svg{width:19px;height:19px}
.px-abtx{display:flex;flex-direction:column;gap:1px;min-width:0}
.px-abtx b{font-size:.92rem;line-height:1.2}
.px-abmenu{width:18px;height:18px;color:var(--muted);margin-inline-start:auto;flex:none}
.px-live{display:inline-flex;align-items:center;gap:5px;font-size:.62rem;font-weight:700;color:var(--green)}
.px-live i{width:6px;height:6px;border-radius:50%;background:var(--green);box-shadow:0 0 6px var(--green);animation:dsnBeat 2.4s ease-out infinite;flex:none}
.px-live em{font-style:normal}
/* Shortened by owner decision (2026-07-30): the mockup ran taller than the column beside
   it. Tighter chat rhythm, tighter bubbles and a shorter phone shell, without dropping any
   of the steps the section's grounding claim depends on. */
.px-chat{display:flex;flex-direction:column;gap:8px;padding:12px 12px}
.px-row{display:flex;align-items:flex-end;gap:7px}
.px-ru{justify-content:flex-start}
.px-ra{justify-content:flex-end}
.px-aic{width:26px;height:26px;border-radius:9px;flex:none;background:linear-gradient(150deg,var(--gold2),var(--gold));color:var(--goldink,#231a05);display:flex;align-items:center;justify-content:center;order:2}
.px-aic svg{width:15px;height:15px}
.px-b{max-width:78%;padding:.5rem .7rem;border-radius:14px;font-size:.74rem;line-height:1.55;text-wrap:pretty;position:relative}
.px-u{background:color-mix(in srgb,var(--gold) 15%,var(--panel2));border:0;border-end-start-radius:5px}
.px-a{background:linear-gradient(155deg,color-mix(in srgb,var(--green) 8%,var(--panel2)),var(--panel2));border-end-end-radius:5px;display:flex;flex-direction:column;gap:4px}
.px-time2{font-size:.55rem;color:var(--muted);align-self:flex-end;opacity:.75}
.px-council{display:flex;align-items:center;gap:7px;align-self:flex-end;font-size:.6rem;color:var(--muted);font-weight:700;padding-inline-end:4px}
.px-council em{font-style:normal}
.px-avs{display:inline-flex;flex-direction:row-reverse}
.pxv{width:17px;height:17px;border-radius:50%;font-style:normal;font-size:.5rem;font-weight:900;color:#0c1417;display:flex;align-items:center;justify-content:center;border:0;margin-inline-start:-5px}
.pxv1{background:var(--gold)}.pxv2{background:var(--green)}.pxv3{background:#9fb8c9}
/* council of AI brains: the top models each weigh in, then Kurdify AI merges the best answer */
.px-brains{align-self:stretch;background:color-mix(in srgb,var(--text) 3%,var(--panel2));border-radius:12px;padding:7px 8px;display:flex;flex-direction:column;gap:5px}
.px-brains-h{display:flex;align-items:center;gap:6px;font-size:.56rem;font-weight:800;letter-spacing:.03em;text-transform:uppercase;color:var(--muted)}
.px-brains-h .px-avs{margin-inline-end:3px}
.px-brain{display:flex;align-items:center;gap:7px;font-size:.66rem;color:var(--text);line-height:1.35}
.pxb-name{flex:none;font-weight:900;font-size:.54rem;border-radius:6px;padding:2px 6px;color:#0c1417;letter-spacing:.02em}
.pxb-name.pxn1{background:var(--gold)}.pxb-name.pxn2{background:var(--green)}.pxb-name.pxn3{background:#9fb8c9}
.px-best{font-size:.55rem;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--green)}
/* Live "council thinking": each model's name-chip glows in turn, one after another. */
.pxb-name{position:relative;animation:pxThink 3.6s ease-in-out infinite}
.px-brain:nth-child(1) .pxb-name{animation-delay:0s}
.px-brain:nth-child(2) .pxb-name{animation-delay:.5s}
.px-brain:nth-child(3) .pxb-name{animation-delay:1s}
@keyframes pxThink{0%,70%,100%{box-shadow:0 0 0 0 transparent;filter:none}12%,30%{box-shadow:0 0 0 3px color-mix(in srgb,currentColor 22%,transparent);filter:brightness(1.12)}}
/* Consensus merge bar: the three answers converge into one decisive reply. */
.px-merge{display:flex;align-items:center;gap:7px;margin-top:1px}
.px-merge-bar{flex:1;height:4px;border-radius:100px;background:color-mix(in srgb,var(--text) 10%,transparent);overflow:hidden;position:relative}
.px-merge-bar i{position:absolute;inset:0 auto 0 0;width:0;border-radius:100px;background:linear-gradient(90deg,var(--gold),var(--green));animation:pxMerge 3.6s ease-in-out infinite}
html[dir="rtl"] .px-merge-bar i{inset:0 0 0 auto}
@keyframes pxMerge{0%{width:0;opacity:.5}55%{width:100%;opacity:1}80%,100%{width:100%;opacity:1}}
.px-merge-lbl{display:inline-flex;align-items:center;gap:4px;flex:none;font-size:.55rem;font-weight:800;color:var(--green);letter-spacing:.02em}
.px-merge-lbl svg{width:9px;height:9px}
/* Rich result card inside the assistant answer: a real Kurdify listing preview. */
.px-result{margin:3px 0 1px;background:color-mix(in srgb,var(--text) 4%,var(--panel));border-radius:11px;padding:7px 8px;display:flex;flex-direction:column;gap:5px}
.px-result-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.px-result-name{font-size:.74rem;font-weight:800;color:var(--text)}
.px-rate{display:inline-flex;align-items:center;gap:3px;flex:none;font-size:.64rem;font-weight:900;color:var(--gold2)}
.px-rate svg{width:11px;height:11px;color:var(--gold)}
/* Queue 351: chip rows never wrap to a second line (house rule). Horizontal rail with a
   hidden scrollbar, same pattern as #kurdify-ai .pag-grid above. */
.px-result-meta{display:flex;flex-wrap:nowrap;gap:5px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.px-result-meta::-webkit-scrollbar{display:none}
.px-result-meta>*{flex:none}
.px-chip{display:inline-flex;align-items:center;gap:4px;font-size:.54rem;font-weight:800;color:var(--muted);background:color-mix(in srgb,var(--text) 6%,transparent);border-radius:100px;padding:2px 7px;letter-spacing:.01em}
.px-chip-off{color:var(--goldink,#231a05);background:linear-gradient(135deg,var(--gold2),var(--gold));border-width:0}
.px-chip-open{color:var(--green)}
.px-chip-open i{width:5px;height:5px;border-radius:50%;background:var(--green);box-shadow:0 0 5px var(--green);animation:dsnBeat 2.4s ease-out infinite}
@media(prefers-reduced-motion:reduce){.pxb-name,.px-merge-bar i,.px-chip-open i{animation:none}.px-merge-bar i{width:100%}}
.px-inbar{margin-top:auto;padding:10px 12px 10px;border-top:0;display:flex;flex-direction:column;gap:9px}
/* Home indicator. A flex item rather than a positioned bar, so it cannot land on top
   of the input pill at any text length. */
.px-phone .px-inbar::after{content:"";align-self:center;width:96px;height:4px;border-radius:100px;background:color-mix(in srgb,var(--text) 26%,transparent);margin-top:1px}
.px-tools{display:flex;justify-content:center;gap:7px}
.px-tools span{display:inline-flex;align-items:center;gap:5px;font-size:.62rem;font-weight:700;color:var(--muted);border-radius:100px;padding:.3rem .7rem;background:color-mix(in srgb,var(--text) 3%,transparent)}
.px-tools svg{width:12px;height:12px}
.px-tools em{font-style:normal}
.px-field{display:flex;align-items:center;gap:8px;background:var(--panel2);border-radius:100px;padding:.5rem .5rem .5rem .95rem}
.px-ph{flex:1;font-size:.72rem;color:var(--muted);min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.px-send{width:30px;height:30px;border-radius:50%;flex:none;background:linear-gradient(135deg,var(--gold2),var(--gold));color:var(--goldink,#231a05);display:flex;align-items:center;justify-content:center}
.px-send svg{width:15px;height:15px}
html[dir="rtl"] .px-send svg{transform:scaleX(-1)}
.px-side{grid-template-columns:1fr;align-content:center}
/* redesigned AI side rail: surface-led panels, no outlines (owner 2026-07-16) */
.pxs-hero{background:linear-gradient(135deg,color-mix(in srgb,var(--gold) 9%,var(--panel)),var(--panel) 62%);border-radius:18px;padding:1.15rem 1.2rem}
.pxs-hero-top{display:flex;align-items:center;gap:12px;margin-bottom:.6rem}
.pxs-hero-t{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}
.pxs-hero-t b{font-size:1.02rem}
.pxs-hero>p{margin:0;font-size:.88rem;line-height:1.75;color:var(--muted);text-wrap:pretty}
.pxs-council{display:flex;align-items:center;gap:.75rem;margin-top:.95rem;background:color-mix(in srgb,var(--panel2) 72%,transparent);border-radius:12px;padding:.62rem .85rem;flex-wrap:wrap}
.pxs-arrow{display:grid;color:var(--muted)}
.pxs-arrow svg{width:17px;height:17px}
html[dir=rtl] .pxs-arrow svg{transform:scaleX(-1)}
.pxs-one{display:inline-flex;align-items:center;gap:.45rem;font-weight:750;font-size:.84rem;color:var(--green)}
.pxs-one svg{width:14px;height:14px;flex:none}
.pxs-feat{display:flex;align-items:flex-start;gap:13px;background:var(--panel);border-radius:16px;padding:.95rem 1.05rem}
/* Round 2026-08-20 item 4: feature icons scaled ~1.5x (40 -> 60, glyph 19 -> 28). */
.pxs-feat .fi{width:60px;height:60px;flex:none;border-radius:17px;display:grid;place-items:center;background:color-mix(in srgb,var(--gold) 12%,transparent);color:var(--gold)}
.pxs-feat .fi svg{width:28px;height:28px}
.pxs-feat b{display:block;font-size:.92rem;margin-bottom:.22rem}
.pxs-feat p{margin:0;font-size:.82rem;line-height:1.65;color:var(--muted);text-wrap:pretty}
.pxs-cta{align-self:flex-start;text-decoration:none;margin-top:.2rem}
@media(max-width:640px){.pxs-cta{align-self:stretch;text-align:center}}
.px-feats{display:flex;flex-direction:column;gap:.55rem;padding:0 .3rem}
.px-feats span{display:flex;align-items:center;gap:.6rem;font-size:.9rem;font-weight:650}
.px-feats svg{width:15px;height:15px;color:var(--green);flex:none;background:color-mix(in oklab,var(--green) 14%,transparent);border-radius:50%;padding:4px;box-sizing:content-box}
.px-feats em{font-style:normal}
.px-soonrow{padding:0 .3rem}
/* the phone mockup is always a dark device screen: pin its palette so it stays readable in light theme too */
/* A COMMITTED DARK ISLAND ON A PAGE THAT MAY BE LIGHT, so it restates the dark palette.
   --goldink and --goldtext must be restated with it: without them the phone mockup inherited
   the LIGHT theme's cream ink onto its own bright gold chip and measured 1.57:1. Any block that
   pins --gold has to pin both of its companions, or it pins half a pair. */
.px-phone{--text:#eaf4f2;--muted:#8fb0ad;--panel:#0f1d22;--panel2:#12252b;--line:#1e3a42;--line2:#295059;--green:#2fbf87;--gold:#e0b64a;--gold2:#f0cd6e;--goldink:#231a05;--goldtext:#e0b64a;color:var(--text)}
.px-appbar .px-abtx b,.px-b,.px-brain{color:var(--text)}
/* generated image + video result tiles inside the assistant bubble */
.px-media{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:3px;width:212px;max-width:100%}
.px-media .px-gen{aspect-ratio:4/3}
.px-genlbl{white-space:nowrap;max-width:calc(100% - 12px);overflow:hidden;text-overflow:ellipsis}
.px-gen{position:relative;border-radius:12px;overflow:hidden;aspect-ratio:16/10;display:flex;align-items:center;justify-content:center}
.px-scene{position:absolute;inset:0;width:100%;height:100%;display:block}
.px-genlbl{position:absolute;z-index:2;bottom:6px;inset-inline-start:6px;display:inline-flex;align-items:center;gap:4px;font-size:.5rem;font-weight:800;background:rgba(0,0,0,.55);color:#fff;padding:2px 7px;border-radius:100px;backdrop-filter:blur(3px)}
.px-genlbl svg{width:8px;height:8px;color:var(--gold2)}
.px-play{position:absolute;z-index:2;width:34px;height:34px;border-radius:50%;background:rgba(224,182,74,.92);display:flex;align-items:center;justify-content:center;box-shadow:0 4px 14px -3px rgba(0,0,0,.6)}
.px-play svg{width:14px;height:14px;color:var(--goldink,#231a05);margin-inline-start:2px}
/* gentle pulse/glow on the assistant logo mark (transform + opacity only) */
@keyframes pxLogoPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}
@keyframes pxLogoGlow{0%,100%{box-shadow:0 4px 12px -4px rgba(224,182,74,.55)}50%{box-shadow:0 6px 20px -3px rgba(224,182,74,.9)}}
.px-logo{animation:pxLogoPulse 2.8s ease-in-out infinite,pxLogoGlow 2.8s ease-in-out infinite}
.sc-ic.sp-c1{animation:pxLogoPulse 2.8s ease-in-out infinite,pxLogoGlow 2.8s ease-in-out infinite}
@media(prefers-reduced-motion:reduce){.px-logo,.sc-ic.sp-c1{animation:none}}
/* ---- Kurdify AI: data-grounded section (proof bar, pipeline, citation, skills) ---- */
/* Proof bar: the live counts that back the "it has read Kurdistan" claim. */
/* Same reasoning as .kai-grid: 4 tiles, so 2x2 then 4x1. Never 3 + 1. */
.kai-proof{display:flex;flex-wrap:wrap;justify-content:center;margin:1.3rem auto .2rem;max-width:600px;background:var(--panel);border-radius:14px;overflow:hidden}
.kai-pf{flex:1 1 130px;display:flex;align-items:center;justify-content:center;gap:.55rem;padding:.7rem .55rem;position:relative}
.kai-pf-ic{flex:none;width:28px;height:28px;border-radius:9px;display:grid;place-items:center;background:color-mix(in srgb,var(--gold) 14%,transparent);color:var(--gold)}
.kai-pf-ic svg{width:14px;height:14px}
.kai-pf-txt{display:flex;flex-direction:column;align-items:flex-start;line-height:1.2}
.kai-pf b{font-size:1.05rem;font-weight:800;color:var(--gold2);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.kai-pf span{font-size:.68rem;font-weight:700;color:var(--muted);white-space:nowrap}
@media(max-width:520px){.kai-proof{max-width:340px}.kai-pf{flex:1 1 45%}.kai-pf:nth-child(3)::before{display:none}}
/* Pipeline steps replacing the old vendor badges inside the phone mockup. */
.px-step{align-items:center}
.pxs-n{flex:none;width:17px;height:17px;border-radius:50%;display:grid;place-items:center;font-size:.58rem;font-weight:800;
  color:var(--gold2);background:color-mix(in srgb,var(--gold) 20%,transparent)}
/* three dots that read as "scanning the data" */
.px-scan{display:inline-flex;align-items:center;gap:3px;flex:none}
.px-scan i{width:5px;height:5px;border-radius:50%;background:var(--gold);opacity:.35;animation:kaiScan 1.4s ease-in-out infinite}
.px-scan i:nth-child(2){animation-delay:.18s}
.px-scan i:nth-child(3){animation-delay:.36s}
@keyframes kaiScan{0%,100%{opacity:.3}50%{opacity:1}}
/* the receipt line under the assistant's recommendation */
/* quoted customer voices inside the answer bubble */
.px-quotes{display:flex;flex-direction:column;gap:4px;margin:6px 0 5px}
/* tinted quote blocks, not side-striped list items */
.px-qt{display:block;font-size:.56rem;line-height:1.55;color:var(--text);opacity:.86;
  background:color-mix(in srgb,var(--gold) 8%,transparent);border-radius:8px;padding:.3rem .48rem}
.px-qt i{display:none}
.px-qt bdi::before{content:"\201C";color:var(--gold);margin-inline-end:1px}
.px-qt bdi::after{content:"\201D";color:var(--gold);margin-inline-start:1px}
.px-cite{display:inline-flex;align-items:center;gap:5px;margin:4px 0 2px;font-size:.58rem;font-weight:700;color:var(--muted)}
.px-cite svg{width:11px;height:11px;flex:none;color:var(--gold)}
.px-cite b{color:var(--gold2)}
/* Skills grid */
/* Sponsored-placement demo, replacing the countdown card in the "bring in customers" section
   (owner request 2026-08-03). Two rows: the sponsored one carries the gold ring and the tag,
   the plain one sits under it, which is the entire claim the copy makes. */
.spon-mock{display:flex;flex-direction:column;gap:8px}
.spon-row{display:flex;align-items:center;gap:10px;padding:.7rem .85rem;border-radius:12px;
  background:var(--panel2);font-size:.84rem}
.spon-row b{font-weight:700}
/* Direct-child combinator, not a bare descendant selector (queue #492). ":last-child" matches
   relative to its OWN parent, so the old ".spon-row span:last-child" also caught the "Sponsored"
   label span nested inside .spon-tag (svg, then this span, so this span IS .spon-tag's own last
   child), painting the badge text --muted at 2.87-4.18:1 instead of the --gold2 badge color its
   own .spon-tag rule declares. Scoping to a direct child leaves the city label (the intended
   target, and a genuine direct last child of .spon-row) untouched and stops it reaching into
   .spon-tag's own last child. */
.spon-row>span:last-child{margin-inline-start:auto;color:var(--muted);font-size:.78rem}
/* Borderless. The 1px gold frame here was a `box-shadow:none` ring rather than a
   `border`, which is why a grep for borders reported this row clean while the screenshot showed
   a frame; tools/border-audit.mjs now detects that shape too. The row still has to read as the
   LIFTED one against the plain row under it, and that was the frame's entire job, so the gold
   wash carries it instead: a wider gradient plus a lift shadow, no hairline. */
.spon-on{
  background:linear-gradient(150deg,color-mix(in srgb,var(--gold) 20%,var(--panel2)),color-mix(in srgb,var(--gold) 7%,var(--panel2)));
  box-shadow:0 6px 18px -10px color-mix(in srgb,var(--gold) 45%,transparent)}
/* Two changes, queue #492. This pill's text was --gold2 at 3.25:1 light / 4.43:1 dark, on a
   background that stacked a transparent 24% gold tint on top of .spon-on's OWN 20%/7% gold
   gradient underneath it: two translucent gold washes compounding into a mid-luminance ground
   that no ink in the gold family clears (measured every combination by hand: gold, gold2,
   goldtext and even goldink all land between 1.9:1 and 4.4:1 against it, because a background
   near the middle of the luminance range has no headroom at either end). Mixing the tint against
   the theme's own solid --panel2 instead of transparent stops it inheriting the row's warmth, so
   it reads as the same gold pill without the compounding, and clears comfortably either way:
   --goldtext on it measures 4.96:1 dark, 5.04:1 light (--gold2 alone was still short at 4.24:1
   light on this new ground, which is why the colour moved too, not just the background). */
.spon-tag{display:inline-flex;align-items:center;gap:5px;flex:none;font-size:.64rem;font-weight:800;
  letter-spacing:.04em;color:var(--goldtext);background:color-mix(in srgb,var(--gold) 24%,var(--panel2));
  border:0;border-radius:100px;padding:.18rem .5rem}
.spon-tag svg{width:11px;height:11px;flex:none}
/* Two fixes to how this row of cards is laid out (owner: "fix layout").

   1. The headings were resolving to align-self:center inside the flex card while the
      paragraph under them stayed at the start edge, so every card had a centred title over
      left-aligned body copy. No rule was setting it, it fell out of the flex parent, so the
      alignment is stated explicitly here rather than left to resolve.
   2. The demo under each card floats to the foot, so a longer paragraph pushes its own demo
      down instead of leaving the row ragged. */
.grid.g2.flow > .fcard{align-items:stretch}
.grid.g2.flow > .fcard > h3,.grid.g2.flow > .fcard > p{align-self:stretch;text-align:start}
.grid.g2.flow > .fcard .f-mock{margin-top:auto}

.kai-skills{margin-top:2.6rem}
.kai-sh{text-align:center;font-size:clamp(1.25rem,3.2vw,1.7rem);font-weight:800;text-wrap:balance;margin:0 0 1.3rem}
/* Explicit column counts, not auto-fit: there are 6 skills and auto-fit was resolving to
   5 across with a single orphan below. 6 divides evenly by 1, 2 and 3, so each breakpoint
   here yields full equal rows (6x1, 3x2, 2x3) and never a ragged tail. */
.kai-grid{display:grid;grid-template-columns:1fr;gap:12px}
@media(min-width:720px){.kai-grid{grid-template-columns:repeat(2,1fr)}}
/* A flat, even 3x2 (owner request 2026-08-03: "enhance the design, make it better").

   This replaces a zig-zag where cards 1, 4 and 5 spanned two columns AND switched to an
   icon-beside-text layout while the other three kept the icon above. The intent was to stop
   six identical cards reading as filler, but the cost was that no two rows shared a shape:
   the icons sat in two different places at two different sizes, the headings started at two
   different depths, and each row paired a wide card with a narrow one. It read as a grid that
   could not make up its mind rather than as deliberate rhythm.

   Six cards divide evenly by 1, 2 and 3, so every breakpoint fills its rows. The interest now
   comes from the content and the hover state, not from making three of the six a different
   shape. */
@media(min-width:1100px){.kai-grid{grid-template-columns:repeat(3,1fr)}}
/* Column flex, not block: it lets the source pill drop to the bottom of every card, so the
   pills line up across a row however long the description above them runs. Uneven pill depths
   were the other half of what made the old grid look unsettled. */
/* Owner request 2026-08-14: drop the drawn borders, make these read as glass. Owner again
   2026-08-20 (queue 480): the inset hairline that replaced the border was still an edge, and
   from a screenshot there is no difference between the two. Both are gone; the card now
   terminates on its own fill and a single top light, which is what the light theme has been
   doing since #455.
   BOTH THEMES ARE DEFINED ON PURPOSE. A translucent fill with only a dark branch composites
   over a light page to a flat grey slab: that is exactly how the shared header shipped at
   1.74:1 and sat there for a day. Note also that getComputedStyle cannot see backdrop-filter,
   because it composites at paint time, so the only honest check here is sampling real pixels
   in both themes. .kai-sk is used on site/index.html only, checked before editing this
   shared file. */
.kai-sk{position:relative;display:flex;flex-direction:column;align-items:flex-start;
  background:color-mix(in srgb,var(--panel2) 55%,transparent);
  -webkit-backdrop-filter:blur(14px) saturate(1.2);backdrop-filter:blur(14px) saturate(1.2);
  border:0;border-radius:18px;padding:1.3rem 1.35rem;overflow:hidden;
  /* Owner request 2026-08-20 (queue 480): no drawn edge on these cards. The edge was never a
     border property, it was the inset 1px ring on the line below, which is exactly the shape
     a `grep border` does not find. The fill and the top light are what terminate the card now. */
  box-shadow:none;
  transition:transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .3s,background-color .2s}
html[data-theme="light"] .kai-sk{
  background:color-mix(in srgb,#fff 58%,transparent);
  /* #455: the light theme drew its ring from --line, which is the border token wearing a
     box-shadow. Deleted. The top highlight alone carries the card in light, same as dark. */
  box-shadow:none}
.kai-sk::before{content:"";position:absolute;inset:0;background:radial-gradient(140px 100px at 100% 0%,color-mix(in srgb,var(--gold) 16%,transparent),transparent 70%);opacity:0;transition:opacity .3s;pointer-events:none}
/* Hover is the lift, the corner glow (::before) and the drop shadow. It used to raise the
   inset hairline to gold; with the hairline gone there is nothing left to tint, and the
   ::before wash is what carries the gold now. */
/* #822: both of these read `box-shadow:none 0 ...` until 2026-09-04, so the lift was the only
   thing the hover did in either theme (computed `none` on hover, dark and light, on dist/). */
.kai-sk:hover{transform:translateY(-4px);
  box-shadow:0 22px 40px -22px rgba(0,0,0,.6)}
html[data-theme="light"] .kai-sk:hover{
  box-shadow:0 18px 34px -22px rgba(0,0,0,.28)}
.kai-sk:hover::before{opacity:1}
/* Owner request 2026-08-20 (queue 480): nothing behind the icon. The 40px tile is gone rather
   than made transparent, so the glyph starts on the same line as the heading under it instead
   of sitting centred in an invisible box 7px to its inside. It grows 19 -> 26 to hold the same
   weight in the card without a tile to sit on. */
.kai-ski{position:relative;z-index:1;display:inline-flex;margin-bottom:.75rem;
  color:var(--gold);transition:transform .3s cubic-bezier(.22,1,.36,1)}
.kai-sk:hover .kai-ski{transform:scale(1.08) rotate(-4deg)}
.kai-ski svg{width:26px;height:26px}
.kai-sk b{position:relative;z-index:1;display:block;font-size:.95rem;margin-bottom:.32rem;text-wrap:pretty}
.kai-sk p{position:relative;z-index:1;margin:0 0 1rem;font-size:.84rem;line-height:1.68;color:var(--muted);text-wrap:pretty}
/* Pushes the pill to the foot of the card, which is what levels them across a row. */
.kai-sk .kai-src{margin-top:auto}
/* the data source behind each skill, so every claim is checkable */
.kai-src{position:relative;z-index:1;display:inline-flex;align-items:center;gap:5px;font-style:normal;font-size:.68rem;font-weight:700;color:var(--gold2);
  /* #480: the only real border property left in this block. Removed; the tint carries the
     pill on its own, raised 9% -> 15% so it still terminates without an outline. */
  background:color-mix(in srgb,var(--gold) 15%,transparent);border:0;border-radius:100px;padding:.25rem .62rem}
.kai-src::before{content:"";width:4px;height:4px;border-radius:50%;background:currentColor;flex:none}
@media(prefers-reduced-motion:reduce){.px-scan i{animation:none;opacity:.7}.kai-sk{transition:none}.kai-sk:hover{transform:none}}
/* "Only in the Kurdify App" pill under the section title */
/* The outline was removed on 2026-08-12 (owner request: "remove the borders"). Transparent
   rather than none, so the chip does not lose 2px of width and shift the text inside it. The
   gold tint stays and now carries the shape on its own. */
.suite-onlyapp{display:inline-flex;align-items:center;gap:6px;margin-top:.6rem;font-size:.7rem;font-weight:800;color:var(--gold2);background:color-mix(in srgb,var(--gold) 12%,transparent);border:0;border-radius:100px;padding:5px 12px}
.suite-onlyapp svg{width:13px;height:13px;flex:none}

/* Kurdify AI agents row: keep all specialist chips on a single line (owner 2026-07-24). Scrolls horizontally on narrow screens rather than wrapping or overflowing the page. */
/* The chip row never wraps (house rule), so it is a horizontal scroller. overflow-x:auto forces
   the computed overflow-y to auto as well, which was clipping the hover lift at the top and
   cutting the glow off the last pill. Pad the scroll box on every side and pull the padding
   back with a negative margin so the row keeps its position. `safe center` keeps the row
   centred while it fits, then falls back to start alignment once it overflows, instead of
   pushing the first pill into unreachable negative scroll space. */
#kurdify-ai .pag-grid{flex-wrap:nowrap;max-width:none;overflow-x:auto;overscroll-behavior-x:contain;
  /* Capture 5, "the outglow effect is trimmed a bit": overflow-x:auto forces overflow-y to auto
     as well (one axis visible and the other not computes to auto), so this rail clips its own
     children's hover glow vertically. It is not a scrollHeight problem, because a box-shadow is
     painted and never laid out, so nothing about the element's metrics reports it. Measured in
     pixels instead: a 4px vertical strip under a lit chip faded gold from R62 down to R14 and
     then went flat at R11 in ONE row, exactly at the rail's bottom edge, with the fade still in
     progress. The hover shadow reaches 12+26-16 = 22px below the card and the padding gave it 20.
     Padding raised with the negative margins moved by the same amount, so the net box is
     unchanged and only the paintable area grows. */
  justify-content:safe center;padding:24px 22px 30px;margin:-18px -22px -24px;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
#kurdify-ai .pag-grid::-webkit-scrollbar{display:none}
#kurdify-ai .pag-card{flex:0 0 auto}
/* Two rows on phones (owner request 2026-08-12), which REVERSES the 2026-07-24 decision
   directly above and sets aside the house "chip rows stay on one line" default. Written down
   rather than quietly overridden: the owner asked for this having seen the scroller, so the
   newer instruction wins, but ONLY below 560px. Above that the single-line scroller is
   untouched and is still the 2026-07-24 layout.

   This block has to sit AFTER the rules it overrides, not with the other phone rules further
   up the file. A media query adds no specificity, so an identical (0,2,0) selector earlier in
   the file loses on source order: the first attempt was written at the phone block around
   .pag-card and measured 1 row of 7 with a 664px scroll width inside a 386px box, which is
   exactly the scroller it was supposed to replace.

   Every property the scroller set has to be unwound, or the wrap cannot happen: flex-wrap
   because it is the pin itself, overflow-x because an auto scroll box never wraps its content,
   and the padding/negative-margin pair because it existed only to stop the scroll box clipping
   the hover lift. justify-content goes to plain center: `safe center` was there to protect the
   first pill from unreachable negative scroll space, and with no scroll box there is none. */
@media(max-width:560px){
  #kurdify-ai .pag-grid{flex-wrap:wrap;overflow-x:visible;justify-content:center;
    padding:8px 0 10px;margin:0}
}

/* ==== Premium type and rhythm pass (2026-07-30 audit fixes) =================================
   Leading, tracking and gutters tuned per script. One rule of thumb runs through all of it:
   tracking is a Latin tool. Arabic-script text (Sorani, Arabic) is a connected script, so any
   letter-spacing, positive or negative, degrades the joins; RTL therefore zeroes every tracked
   style and takes taller leading, which Vazirmatn needs anyway. */

/* Rhythm: body copy breathes a little more everywhere; leads most of all. */
body{line-height:1.65}
p{text-wrap:pretty}
.hero-lead{line-height:1.7}
.s-head p{line-height:1.68}
.fcard p,.aio-card p{line-height:1.62}
/* Missed by the 2026-07-30 pass and added on owner request 2026-08-06. .show-txt p carries the
   longest copy on the page, the paragraph beside each showcase visual, and it was still on the
   1.65 body default while shorter blocks around it had already been opened up. */
/* TIGHTENED BACK on owner request 2026-08-21 ("reduce the line height on this paragraph a bit
   for a more premium look"), which reverses the 2026-08-06 request above rather than missing it.
   1.72 -> 1.58: below the 1.65 body on purpose, so the block reads as set rather than as default
   copy. Applied to the shared .show-txt p idiom, not to the one paragraph in the screenshot:
   the home page alone stacks four of these and site.css is shared, so scoping it would leave
   21 identical paragraphs across 6 marketing pages set two different ways. Blast radius named
   because it is wider than the request: index, features, for-business, for-users, scoring,
   whatsapp. The RTL line below MUST move with it, for the reason recorded there. */
.show-txt p{line-height:1.58}

/* Latin display: a touch of negative tracking on the big sizes only. */
:root[dir=ltr] .hero h1,:root[dir=ltr] .hero .hero-h1{letter-spacing:-.025em}
:root[dir=ltr] .s-head h2{letter-spacing:-.022em}

/* Arabic-script overrides. */
:root[dir=rtl] body{line-height:1.75}
:root[dir=rtl] h1,:root[dir=rtl] h2,:root[dir=rtl] h3,:root[dir=rtl] h4,:root[dir=rtl] .brand{letter-spacing:0}
:root[dir=rtl] h1,:root[dir=rtl] h2{line-height:1.3}
:root[dir=rtl] .hero h1,:root[dir=rtl] .hero .hero-h1{line-height:1.24}
:root[dir=rtl] .hero-lead{line-height:1.85}
/* This line exists because the LTR value alone cannot serve both scripts: RTL body is 1.75,
   so an LTR number set against the 1.65 LTR body lands on Sorani and Arabic as the opposite
   move. Sorani is the default language, so the owner sees this half first. It was written when
   the request was to OPEN UP (1.72 LTR needed 1.9 here); the 2026-08-21 request is to tighten,
   so both move together and this now reads as a deliberate tightening in RTL too: 1.9 -> 1.72,
   the same proportion as 1.72 -> 1.58 above, landing just under the 1.75 RTL body exactly as
   1.58 lands just under the 1.65 LTR one. Same reason .hero-lead has its own RTL line above.
   Whichever direction the next request goes, MOVE THE PAIR. */
:root[dir=rtl] .show-txt p{line-height:1.72}
/* Same defect, already shipped: .fcard p and .aio-card p set 1.62, which is BELOW the 1.75 RTL
   body, so the 2026-07-30 "body copy breathes more everywhere" pass quietly squeezed the feature
   cards in Sorani and Arabic while opening them up in English. */
:root[dir=rtl] .fcard p,:root[dir=rtl] .aio-card p{line-height:1.82}
:root[dir=rtl] .kicker,:root[dir=rtl] .s-head .kicker,:root[dir=rtl] .show-txt .kicker,
:root[dir=rtl] .eyebrow,:root[dir=rtl] .cc-tag,:root[dir=rtl] .cmp thead th,
:root[dir=rtl] .foot-col h5,:root[dir=rtl] .vp-tag,:root[dir=rtl] .vpw-offer{letter-spacing:0}

/* Mobile gutters: raised to a 24px floor at the .wrap rules near the top of this file. */

/* Nav CTA: desktop and tablet only; on phones the hero CTA (now above the fold) and the
   mobile-menu button carry the same action, and the top bar has no room left at 390px. */
@media(max-width:700px){.nav .nav-cta{display:none}}

/* Touch targets: footer link rows and the score-modal close were well under 44px. */
.foot-col a{padding:.48rem 0}
.sm-x{width:38px;height:38px}

/* Micro-label floor: nothing user-readable below ~10.5px. */
.px-cite{font-size:.68rem}

/* The plan-comparison table scrolls sideways on phones; these local-attachment shadows make
   the cut-off edge visible so the swipe affordance is discoverable (works in both directions,
   so RTL needs no mirror). */
.cmp-wrap{background:
  linear-gradient(90deg,var(--panel) 30%,rgba(0,0,0,0)) 0 0/40px 100% no-repeat local,
  linear-gradient(270deg,var(--panel) 30%,rgba(0,0,0,0)) 100% 0/40px 100% no-repeat local,
  radial-gradient(farthest-side at 0 50%,rgba(0,0,0,.35),rgba(0,0,0,0)) 0 0/14px 100% no-repeat scroll,
  radial-gradient(farthest-side at 100% 50%,rgba(0,0,0,.35),rgba(0,0,0,0)) 100% 0/14px 100% no-repeat scroll,
  var(--panel)}

/* ==== Camera-frame hero v2 (owner feedback 2026-07-30 evening) ============================
   Full-bleed viewfinder. Headline pinned to the start corner under an "advanced" eyebrow rail,
   description in the bottom-start corner, the brand chooser cards and the live stat strip live
   INSIDE the frame, and the preloader's flag dial sits at the top end, slowed down. Logical
   properties throughout so RTL mirrors itself. */
/* padding-top here beat header.hero's own headover-compensated padding-top outright (a bare
   clamp() against calc(clamp() + var(--headover)), same specificity fight :has() already wins
   on class count) so the -var(--headover) rise in header.hero (owner request 2026-08-14: "the
   header sits ON the hero") was never paid back in full: the frame rose 100px behind the bar
   but only got ~24px of it back as padding, leaving the photo column 76px too high and directly
   behind the floating glass header -- the actual source of the white glow reported the same day,
   worst on bright carousel slides (band-mountains). Owner reversed the request 2026-08-14 later
   the same day ("header wont overlay"): restore the compensation here, in the rule that wins. */
.hero:has(.cam-hero){padding-top:calc(var(--headover,100px) + clamp(.9rem,2vw,1.6rem))}
/* One radius token for the three hero columns (owner request 2026-08-03: the photo column and
   the two brand cards were square-cornered and read as raw crops). Scoped to .cam-hero so the
   flat .choose-card used elsewhere on the site is untouched. */
.cam-hero{--cam-r:16px;position:relative;display:grid;grid-template-columns:minmax(26ch,2.2fr) minmax(0,1.3fr) minmax(0,1.3fr);grid-template-areas:"head head media" "copy cards media";column-gap:clamp(1.4rem,3.5vw,3.5rem);row-gap:clamp(1.2rem,2.6vw,2rem);align-content:start;text-align:start;padding:clamp(1.5rem,3.2vw,2.6rem) clamp(1.4rem,4vw,3.6rem);width:100%}
.cam-head{grid-area:head;justify-self:start;max-width:none;padding-inline-end:0}
.cam-hero h1,.cam-hero .hero-h1{text-align:start;margin:.9rem 0 0;max-width:18ch}
.cam-orb{position:absolute;inset-block-start:clamp(1.2rem,2.6vw,2rem);inset-inline-end:clamp(1.4rem,4vw,3.4rem)}
.cam-copy{grid-area:copy;align-self:start;justify-self:start;max-width:none;margin-top:-.4rem}
.cam-copy p,.cam-copy .hero-lead{text-align:start;margin-inline:0;max-width:none}
.cam-copy .hero-lead{font-size:clamp(.96rem,1.5vw,1.06rem);max-width:44ch}
/* The tagline is a second paragraph of the same block of copy, so it sits with it (owner
   request 2026-08-03) rather than in the opposite corner of the frame. It keeps its own
   measure, a touch narrower than the lead, so the two paragraphs read as statement and
   signature instead of one run of text. */
/* The gold statement is its own beat, not a fourth line of the paragraph above it (owner,
   2026-08-22: "better dividing"). Measured before changing: the rendered gap was 14px at 390
   and 16px at 1440, against a paragraph whose own line spacing is ~26px, so the line read as
   part of the paragraph. Two rules were fighting: .cam-us sets margin-top and .hero-us inside
   it sets margin-block .85rem, and with nothing between them the inner margin COLLAPSES out
   through the wrapper, so the larger of the two won and their sum never applied. flow-root ends
   the collapse, which is what makes the number written here the number that renders. */
.cam-us{max-width:38ch;margin-top:2rem;display:flow-root}
.cam-us .hero-us{margin:0;text-align:start;margin-inline:0;max-width:none}
/* Owner request 2026-07-31: the two brand cards stack instead of standing side by side, and
   run a size down, so the end column reads as one column of two rows rather than a second
   wall of text competing with the headline. */
/* Stretch, not end (owner request 2026-08-03: "increase their height"). The two brand cards
   sat at their content height, 144px each, while the copy column beside them ran 449px, so
   roughly 150px of the row went unused and the pair floated low against the full-height
   photograph on the other side. They split the row between them now. */
.cam-cards{grid-area:cards;align-self:stretch;display:flex;align-items:center}
/* Photo column at the outer edge of the viewfinder (owner request 2026-08-03). Same track
   width as the brand cards beside it, and it fills the row rather than sitting at a fixed
   aspect, so its top lines up with the copy and its bottom with the cards whatever the
   headline wraps to. It carries the same --cam-r radius as the two brand cards beside it, so
   the three columns read as one system. */
/* THE GROUND IS THE PAGE'S, NOT A PANEL'S (owner, 2026-09-05: "this one now has this lines,
   remove those, no lines needed"). The dither draws its marks on transparent, so whatever fill
   this box carries IS the picture's ground everywhere the marks do not cover -- which is most
   of the dark half of every photograph. --panel2 (#12252b) measures luminance 33-35 against the
   hero ground's 14.8, so the box outlined itself: a light rectangle edge down the end side and
   across the bottom, brightest exactly where the picture content is darkest. No border was ever
   declared; a 2.2x ground step draws one just as well. Transparent lets the hero's own gradient
   be the ground, so the dark half of the picture dissolves into the page and only the picture
   has an edge. Measured after: end columns 15.4 against page 14.8. */
/* The frame FEATHERS out instead of stopping at a rounded rectangle (owner, 2026-09-06: "fix
   this edges should be fade out"). The hard vertical cut was the right edge of the dither
   canvas at x=513 on a 1440 viewport, measured by scanning the hero for a column where most
   rows jump in luminance and hit-testing it: canvas.cam-eg < div.cam-media.
   Two linear masks intersected, not one radial: a radial eats the corners far harder than the
   sides and the picture loses its subject before its edge. `intersect` is the standard keyword
   and `source-in` is the -webkit- spelling of the same thing; both are set or Safari shows only
   the horizontal fade. This is a MASK, not a rim: no padding, nothing painted, so it is not the
   `mask-composite:exclude` ring the borderless gate looks for. */
.cam-media{grid-area:media;position:relative;overflow:hidden;align-self:stretch;
  min-height:100%;border-radius:var(--cam-r);background:transparent;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%),
                     linear-gradient(to bottom,transparent 0,#000 6%,#000 94%,transparent 100%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%),
             linear-gradient(to bottom,transparent 0,#000 6%,#000 94%,transparent 100%);
  mask-composite:intersect}
/* Slideshow. Every slide is stacked in the same box; only .on is opaque and sharp. The others
   sit blurred and slightly over-scaled, so the change reads as a rack focus rather than a
   crossfade: the incoming frame resolves INTO focus while the outgoing one softens away. */
.cam-media img,.cam-media .cam-eg{position:absolute;inset:0;width:100%;height:100%;display:block;
  object-fit:cover;object-position:center 45%}
/* The slide, rebuilt 2026-08-03 (owner: "still not smoothly changing, make the effect go right
   to left faster than the zoom, without glitch").

   THE GLITCH, and why this looks over-engineered: the Ken Burns `animation` and the crossfade
   `transition` were both driving `transform`. A running animation beats a transition on the same
   property, so the instant .on came off, transform SNAPPED from wherever the zoom had reached to
   the resting value before the transition could take over. That jump was the glitch, and no
   amount of retiming fixes it.

   The fix is to stop them sharing a property. `scale` and `translate` are independent longhands,
   so the zoom animates `scale` while the slide transitions `translate` and neither can clobber
   the other. Do NOT collapse these back into a `transform` shorthand.

   Both animated properties are compositor-friendly. The old animated `filter:blur()` is gone on
   purpose: blurring a full-bleed photograph repaints it every frame, which is the actual reason
   the change stuttered. Smoothness was the ask, so it lost. */
/* The doubled `.cam-slide.cam-slide` is a specificity guard, not a typo: the progressive-image
   layer's `.img-fx .img-lazy.is-loaded{opacity:1}` is three classes and would otherwise outrank
   a two-class rule here and force every stacked slide visible at once. imgFade() also skips this
   box now, so this is belt and braces; keep both. */
/* CINEMATIC PASS, owner request 2026-08-06: "it should also move from right to left and then blur
   in blur out to the other image, normally and smooth."
   Two things changed and one constraint had to be respected.
   THE DRIFT moved onto `transform`, while the slide's entry and exit stay on the `translate`
   longhand. That is not stylistic: both wanted to move the image horizontally, and one property
   cannot carry an animation and a transition at once. The individual transform properties
   (translate/scale) are applied BEFORE `transform` by spec, so the two compose instead of
   fighting, and both remain compositor-friendly.
   THE BLUR PASS IS GONE (owner request 2026-08-14): the crossfade read as a stray dark/blurred
   smear at the frame edge during the .8s window, reported and pointed at directly. Plain
   translate+opacity crossfade now, no filter animation, so there is nothing to repaint mid-fade
   either. */
/* 2026-08-29 (owner request: "the image moving from top right to bottom corner moving then to
   right bottom and go to top left moving around and fade in to other image"). The pass shrank
   from 26% to 12% and slowed from .8s to 1s, so the change now reads as a FADE with a drift
   still running underneath it rather than as a slide. The pass is not removed: without any
   travel the outgoing frame stops dead mid-circuit, which reads as a stall. site.js OUT_MS
   tracks this duration; move one and move the other. */
/* assets/electric-gaze.js renders each photograph as a dither into a <canvas class="cam-eg">
   and hides the <img> behind it. The canvas is listed in THIS rule, and in .on/.out and the
   reduced-motion block below, rather than carrying its own copy of the timing: camKen and the
   1s crossfade have to stay in exactly one place. site.js OUT_MS already tracks that duration,
   and a third copy inside the script is how the dither and the photograph would come to
   disagree about where the frame is. Remove .cam-eg from these four selectors and the effect
   goes back to sitting still while the composition moves, which is the failure that took it
   off the page on 2026-09-04 (HEAD 33c7d47). */
.cam-media .cam-slide.cam-slide,
.cam-media .cam-eg{
  opacity:0;translate:12% 0;
  transition:translate 1s cubic-bezier(.32,.72,0,1),opacity 1s cubic-bezier(.4,0,.2,1);
  will-change:translate,opacity;backface-visibility:hidden}
.cam-media .cam-slide.cam-slide.on,
.cam-media .cam-eg.on{opacity:1;translate:0 0;
  /* The drift runs for the whole hold, so the frame is never completely still. It is now a
     four-corner circuit rather than one pan (see camKen), 6.9s since 2026-09-06: four legs
     at 6.4s read as a nervous camera rather than a deliberate one. */
  animation:camKen 6.9s forwards}
/* .out is applied by heroSlides() for the length of the transition only. Without it the outgoing
   frame would fall back to the resting rule and retreat back out to the RIGHT, reading as a
   bounce; it has to keep travelling LEFT for the motion to be one continuous right-to-left pass. */
/* `scale:1` here is load-bearing. camKen ends at 1 and holds it only while .on is applied, so
   without this the outgoing frame POPS 1 -> 1.1 (back to the waiting scale) the instant it
   starts leaving. Measured: it did. It leaves at the size the zoom left it. */
/* `transform` here is load-bearing for exactly the reason `scale:1` was: camKen holds its end
   state only while .on is applied, so without restating it the outgoing frame would POP back to
   the un-drifted transform the instant it starts leaving. It leaves from where the drift left it. */
.cam-media .cam-slide.cam-slide.out,
.cam-media .cam-eg.out{opacity:0;translate:-12% 0;
  transform:scale(1.15) translate(4%,4%)}
/* The photographs stay in the DOM, keep their classes and keep driving the slideshow; they
   are only invisible. transition:none is load-bearing. Without it the slide inherits the 1s
   opacity transition from the rule above and spends a full second fading out UNDERNEATH the
   dither on first paint, which reads as the effect failing to cover the photograph. The
   attribute is written by the script only after a frame has actually rendered, so a browser
   that cannot sample the image (a tainted canvas, a decode failure) keeps the plain
   slideshow it already had rather than showing an empty box. */
.cam-media[data-eg] .cam-slide.cam-slide{opacity:0;transition:none}
/* Zoom out AND pan right to left in one animation, on one property, so they cannot desynchronise.
   THE SCALE NEVER REACHES 1, and that is the whole constraint. A translate only stays inside the
   frame while there is overscan to cover it: at scale S the image hangs (S-1)/2 over each edge, so
   ending at scale(1) translateX(-3.5%) pulled the photograph off its own box and exposed the panel
   behind it. Reported immediately: "the image should never be out, fill in the section".
   Ending at 1.12 leaves 6% of overscan each side against a 3% shift, so the frame is always
   covered, with margin, at both ends of the drift. */
/* FOUR WAYPOINTS, one property. The frame reads the top-right of the picture, drops to the
   bottom edge, crosses to the bottom-right corner and finishes on the top-left, easing at each
   turn so it reads as a camera move and not as a bounce. Which corner is on screen is the
   OPPOSITE of the sign: translating the image right shows the reader more of its left side, so
   "show the top-right" is translate(-x,+y).

   THE SCALE NEVER REACHES 1, and that is the whole constraint, now on both axes rather than
   one. At scale S the image hangs (S-1)/2 over each edge and a translate of a% moves it a*S.
   The worst case here is the last waypoint: 4% at scale 1.15 is a 4.6% shift against 7.5% of
   overscan, so the frame stays covered with margin. Raise the translate or drop the scale and
   the panel behind the photograph shows through at the corners, which is exactly the failure
   the owner reported on 2026-08-06: "the image should never be out, fill in the section".

   Per-keyframe timing functions rather than one on the animation: with a single ease the four
   legs run at four different speeds and the circuit limps. */
@keyframes camKen{
  0%  {transform:scale(1.22) translate(-4%,4%);  animation-timing-function:cubic-bezier(.45,.05,.55,.95)}
  34% {transform:scale(1.2) translate(0%,-4%);   animation-timing-function:cubic-bezier(.45,.05,.55,.95)}
  62% {transform:scale(1.18) translate(-4%,-4%); animation-timing-function:cubic-bezier(.45,.05,.55,.95)}
  100%{transform:scale(1.15) translate(4%,4%)}}
/* The burn: a short bloom of warm light over the frame as a slide lands, keyed to the brand
   gold rather than a white flash, which would read as a page error. Driven by a class the
   script toggles, so it fires once per change and never loops. */
.cam-burn{position:absolute;inset:0;pointer-events:none;opacity:0;mix-blend-mode:screen;
  background:radial-gradient(120% 90% at 50% 40%,color-mix(in srgb,var(--gold) 55%,transparent),transparent 70%)}
.cam-media.burning .cam-burn{animation:camBurn 1.1s ease-out}
@keyframes camBurn{0%{opacity:0}18%{opacity:.5}100%{opacity:0}}
/* Reduced motion gets the first photograph and nothing else: no fade, no blur, no burn, and
   the script never starts its timer. */
@media(prefers-reduced-motion:reduce){
  /* Doubled to match the specificity guard on the rules above, or these would lose and
     reduced-motion users would still get the slide and the zoom. Clears `scale`/`translate`,
     not `transform`: the motion moved onto those longhands (see the note above). */
  .cam-media .cam-slide.cam-slide,
  .cam-media .cam-eg{transition:none;will-change:auto;filter:none}
  .cam-media .cam-slide.cam-slide.on,
  .cam-media .cam-eg.on{animation:none;transform:none;translate:0 0;filter:none}
  .cam-media.burning .cam-burn{animation:none}
}
/* EQUAL HEIGHTS, and this is the rule that guarantees it (owner request 2026-09-04). The
   chooser is a one-column grid whose height is content-driven, so grid-auto-rows:1fr sizes
   every row to the tallest one: the two cards are the same height whatever either sentence
   wraps to. Measured after the 09-04 pass: both 178.4px at 1440, 1725 and 1920. Phones drop
   back to grid-auto-rows:auto on purpose, see the max-width:900px block below. */
/* NATURAL HEIGHT, CENTRED IN THE COLUMN -- not stretched to fill it. The chooser used to carry
   flex:1, so the pair grew to whatever the column happened to be, and the column is set by the
   headline row, which wraps to three lines at 1440 and two at 1725. Stretching put that whole
   difference INSIDE the cards as empty space under the last line of copy: measured with a Range
   over the text node (a getBoundingClientRect on the paragraph cannot see it, because the
   paragraph's box is the thing being stretched), the dead space under the text ran 46px at
   1725, 102px at 1440 and 138px at 1024. That is the same hole the 09-04 pass was closing,
   moved inside the card.
   grid-auto-rows:1fr on an AUTO-height grid still equalises the two rows to the taller card, so
   the pair stays identical; align-items:center on .cam-cards then centres it, and whatever the
   column has spare reads as symmetric margin above and below a correctly proportioned pair
   rather than as a void inside two stretched panels. */
.cam-cards .chooser{margin-top:0;gap:12px;grid-template-columns:minmax(0,1fr);
  flex:0 1 auto;width:100%;grid-auto-rows:1fr;align-items:stretch}
/* Top-aligned, not centred. While the rows are 1fr the two cards are the same height, so
   anchoring the content to the top puts card A's icon, title and first line on exactly the
   same baselines as card B's. Centring only aligned them while both paragraphs happened to
   wrap to the same number of lines, and silently stopped the day one of them did not. */
/* The column runs the full height of the frame as of 2026-09-04, so the two cards are taller
   than their own copy needs, and where that slack goes decides whether the pair still reads as
   a pair.
   CENTRING THE CONTENT WAS TRIED FIRST AND IS WRONG. It aligns the two titles only while both
   paragraphs happen to wrap to the same number of lines. At 1440 the cards are 315px wide,
   KurdConnect's sentence takes three lines and Kurdify's takes two, and centring splits that
   one-line difference in half: measured h3 top offsets 141.3px and 130.6px, so the two titles
   sat 10.7px apart on a pair whose whole point is that it is identical. Nothing at 1725 shows
   it, which is how it would have shipped.
   The rows are auto/auto/1fr instead. The head and the title size to themselves, the paragraph
   takes every remaining pixel, and the slack lands inside the paragraph's own box below its
   last line. The two titles are then on the same baseline BY CONSTRUCTION, at any width and
   whatever either sentence wraps to. */
.cam-cards .choose-card{padding:clamp(1.35rem,1.9vw,1.9rem) clamp(1.25rem,1.7vw,1.7rem);
  display:grid;grid-template-rows:auto auto 1fr;align-content:start;row-gap:0;
  border-radius:var(--cam-r)}
/* The icon and the tag sit in one flex row (.cc-head, added to the markup 2026-09-04), so
   they share a centre line by construction. They used to be a flow element and an absolutely
   positioned pill set from the card's own top edge, which left them 10px out of alignment
   with each other: icon centre 449px, tag centre 438.6px, measured at 1440. */
.cam-cards .choose-card .cc-head{display:flex;align-items:center;justify-content:space-between;
  gap:.75rem;margin-bottom:clamp(1rem,1.5vw,1.35rem)}
.cam-cards .choose-card .cc-ic{width:clamp(38px,3vw,46px);height:clamp(38px,3vw,46px);
  border-radius:13px;margin-bottom:0}
.cam-cards .choose-card .cc-ic svg{width:clamp(20px,1.6vw,24px);height:clamp(20px,1.6vw,24px)}
.cam-cards .choose-card h3{font-size:clamp(1.1rem,1.15vw,1.28rem);line-height:1.4;margin-bottom:.36rem}
.cam-cards .choose-card p{font-size:clamp(.855rem,.85vw,.93rem);line-height:1.66;margin-bottom:0;max-width:46ch}
.cam-cards .cc-tag{position:static;inset:auto;font-size:.62rem;font-weight:700;
  padding:.28rem .6rem;flex:none}
.cam-cards .choose-card .cc-glow{width:150px;height:150px;inset-inline-end:-45px;top:-45px}
/* The counts live inside the copy block now (owner request 2026-08-03), directly under the
   tagline, so they read as evidence for the sentence above them rather than as a separate
   corner of the frame. No grid area and no WhatsApp-button clearance: the button is at the
   opposite, inline-end corner. */
.cam-stats{margin-top:1.75rem}
.cam-stats .stat-strip{margin-top:0}
/* Note for whoever narrows this column again: the photo column took about a sixth of the
   copy width, which is enough to wrap "پێداچوونەوەی ڕاستەقینە" onto a second line at 1440.
   That is the designed behaviour, not a defect. The strip below already carries
   text-wrap:balance and container-query type for exactly this, so the label splits into two
   balanced lines inside a tile that stays the same height as its neighbours. Do not add
   padding or font-size overrides up here: they lose to the container-query rules further
   down the file and only look like they work. */
/* the "advanced" eyebrow: tracked micro-label, no rail.
   THE GOLD RAIL IS GONE (owner, 2026-09-05: "dont want see line"). It was a ::after at
   flex:1, height:1px, so it ran ~302px from the label to the frame edge and read as a rule
   drawn across the top of the hero rather than as part of the label. A 1px gradient bar is a
   border by another mechanism; the label carries itself on its own colour and tracking.
   `width:100%` stays: it binds the label's start edge to the head column's edge, which is
   what the h1 under it aligns to. Do not put the rail back. */
.cam-head .eyebrow{background:none;border:none;padding:0;border-radius:0;display:flex;align-items:center;gap:10px;width:100%;color:color-mix(in srgb,var(--gold) 78%,var(--muted));font-size:.72rem}
:root[dir=ltr] .cam-head .eyebrow{text-transform:uppercase;letter-spacing:.16em}
.cam-corners{position:absolute;inset:clamp(8px,1.2vw,16px);pointer-events:none}
.cam-corners i{position:absolute;width:clamp(22px,3vw,34px);height:clamp(22px,3vw,34px);border:0}
.cam-corners i:nth-child(1){inset-block-start:0;inset-inline-start:0;border-block-start-width:0;border-inline-start-width:0;border-start-start-radius:10px}
.cam-corners i:nth-child(2){inset-block-start:0;inset-inline-end:0;border-block-start-width:0;border-inline-end-width:0;border-start-end-radius:10px}
.cam-corners i:nth-child(3){inset-block-end:0;inset-inline-start:0;border-block-end-width:0;border-inline-start-width:0;border-end-start-radius:10px}
.cam-corners i:nth-child(4){inset-block-end:0;inset-inline-end:0;border-block-end-width:0;border-inline-end-width:0;border-end-end-radius:10px}
/* the preloader dial, scaled down and slowed to feel ambient rather than loading */
.cam-sun{width:auto;height:auto;margin:0;animation:none;color:var(--gold)}
.cam-sun.pre-sun .pl-orb{width:104px;height:104px}
.cam-sun .pl-sun{width:42px;height:42px;animation-duration:20s,7s}
.cam-sun .pl-orb::before{animation-duration:7s}
.cam-sun .pl-ring{animation-duration:5.5s}
.cam-sun .pl-ring2{animation-duration:7.5s}
.cam-sun .pl-ring3{animation-duration:12s}
.cam-sun .pl-sweep{animation-duration:11s}
.cam-sun .pl-glow{animation-duration:4.5s}
.cam-sun .pl-ripple{animation-duration:6.5s}
.cam-sun .pl-ripple2{animation-delay:3.25s}
@media(prefers-reduced-motion:reduce){.cam-sun *{animation:none!important}}
@media(max-width:900px){
  /* Owner request 2026-07-30: the mobile hero reads as ONE centred block. Rows sit
     close together, the headline is centred like everything else, and the eyebrow is
     sized against the viewport so it always holds a single line. */
  .cam-hero{grid-template-columns:1fr;grid-template-areas:"head" "copy" "cards" "stats";row-gap:.55rem;padding:1.4rem 1.2rem 1.6rem;text-align:center}
  /* Shown on phones too (owner request 2026-08-03), but as a banner rather than the tall
     desktop column. At full height it would push the brand cards off the first screen; as a
     banner under the headline it sets the place and still leaves the cards above the fold.
     It takes its own grid row, between the copy and the cards.
     2:1 rather than 16/9 (owner request 2026-08-06). At 375px that is 351x176 instead of
     351x197, so it gives 21px back to the fold while staying wide enough to read as a
     photograph of a place rather than a letterbox strip. */
  .cam-hero{grid-template-areas:"head" "copy" "media" "cards" "stats"}
  /* Two overrides are needed for the ratio to actually hold, and both were found by measuring
     rather than by reading: 2/1 kept computing as 1.875 (336.6x179.5 instead of 336.6x168.3).
     align-self:start undoes the desktop `stretch`, since a stretched grid item fills its row and
     ignores aspect-ratio. min-height:0 undoes the desktop `min-height:100%`, which was doing the
     same thing by a different route. */
  /* The bottom margin was .15rem, which on top of the .55rem row-gap left about 11px between the
     photograph and the two brand cards under it. At that distance the picture read as the top of
     the first card rather than as its own element (owner request: "gap between the image and the
     card"). .7rem puts the total near 20px: a deliberate break, not a hole. */
  .cam-media{display:block;grid-area:media;aspect-ratio:2/1;width:100%;align-self:start;
    min-height:0;border-radius:14px;margin:.55rem 0 .7rem}
  /* Less height on phones, same request. Two things were inflating these cards:
     grid-auto-rows:1fr forced both to the height of the taller one, so KurdConnect's longer
     sentence padded out the Kurdify card with dead space; and the desktop padding and 40px icon
     carried over unchanged to a 375px screen. Natural heights plus tighter internals, and
     justify-content goes back to start because centring only mattered while rows were equal. */
  .cam-cards .chooser{grid-auto-rows:auto;gap:8px}
  .cam-cards .choose-card{padding:1rem 1rem}
  .cam-cards .choose-card .cc-head{margin-bottom:.6rem}
  .cam-cards .choose-card .cc-ic{width:32px;height:32px;border-radius:9px}
  .cam-cards .choose-card .cc-ic svg{width:17px;height:17px}
  .cam-cards .choose-card h3{font-size:1rem}
  .cam-cards .choose-card p{font-size:.82rem;line-height:1.5}
  /* One centred column on phones: the tagline goes back under the lead it belongs with, and
     the strip loses the desktop button clearance because nothing sits beside it here. */
  .cam-us{max-width:none;margin-top:1.75rem}
  .cam-us .hero-us{text-align:center}
  .cam-stats{padding-inline-end:0}
  .cam-head{justify-self:center;max-width:none;padding-inline-end:0}
  /* header.hero prefix: the flatten rule inline in index.html pins .82rem at
     (0,2,1), so the mobile size needs the same header.hero anchor to win */
  header.hero .cam-head .eyebrow{justify-content:center;width:auto;white-space:nowrap;font-size:clamp(.54rem,2.6vw,.7rem)}
  :root[dir=ltr] .cam-head .eyebrow{letter-spacing:.06em}
  /* the ::after rail this used to hide is gone from the base rule as of 2026-09-05 */
  /* the big orb already sits right above; the inline sun glyph only eats line width here */
  .cam-head .eyebrow svg{display:none}
  .cam-hero h1,.cam-hero .hero-h1{line-height:1.05;margin-top:.45rem;margin-bottom:.25rem}
  .cam-hero .cam-head h1,.cam-hero .cam-head .hero-h1{text-align:center;margin-inline:auto}
  .cam-copy{justify-self:center;align-self:start}
  /* .hero-split carries margin-top:2.6rem for the desktop layout, where the copy column sits
     beside the cards and needs the offset. On phones the rows are stacked, so that margin
     became a 61px hole between the headline and the sentence under it (owner request
     2026-08-03). The row-gap above already separates them. */
  .cam-copy .hero-split{margin-top:0}
  .cam-copy p,.cam-copy .hero-lead,.cam-copy .hero-us{text-align:center}
  .cam-orb{grid-area:orb;position:static;justify-self:center;margin:.2rem auto 0}
  .cam-hero{align-items:center}
  .cam-sun.pre-sun .pl-orb{width:84px;height:84px}
  .cam-sun .pl-sun{width:34px;height:34px}
  .cam-cards{align-self:start}
}

/* ==== Hero premium pass, 2026-08-12 ======================================================
   Owner request: "make this section better layout, more advanced and looking more premium,
   better fully mobile optimised". Deliberately placed AFTER the 900px block above so these
   win where they overlap, and every phone change below re-declares inside its own query.
   Nothing here moves an element to a different grid area or removes a component: the three
   columns, the stacked brand cards, the tagline sitting under the lead and the counts sitting
   under the tagline are all owner decisions from 2026-07-31 and 2026-08-03 and they stand.
   What changes is the execution of four things the renders showed:

     1. a 42px hole between the headline and the sentence under it
     2. a photograph so narrow it read as a crop rather than a picture
     3. four boxed stat tiles wrapping into a 2x2 block, which is the single most generic
        shape on the page and was competing with the two brand cards beside it
     4. a coloured bloom on each brand card                                                */

/* 1. The hole. .hero-split carries margin-top:2.6rem for the ORIGINAL centred hero, where the
      copy followed the headline in normal flow. In the camera frame the copy is a grid item
      that starts on the same row line as the brand cards, so that margin is not separation,
      it is 42px of dead air pushing the lead below the top of the cards beside it. The phone
      block above already zeroed it for the same reason; it was never zeroed at desktop. */
.cam-hero .cam-copy .hero-split{margin-top:0}

/* 2. The photograph. It was measured at 333x712 in a 1440 frame: a 1:2.1 sliver, which is why
      it read as a raw crop of something rather than a view of Erbil. The end column takes the
      width back off the headline track, which had 26ch of minimum for an 18ch headline and was
      running slack. Now roughly 430px wide, a portrait plate rather than a strip. */
.cam-hero{grid-template-columns:minmax(22ch,1.85fr) minmax(0,1.15fr) minmax(0,1.5fr)}

/* 3. The counts, debossed (owner request 2026-08-12: "make this bevel upside with inner shadow
      so it looks like it is in", with a pressed pill as the reference). The tiles stay tiles.
      What changes is which way the light falls: they were RAISED, with a gradient fill, a gold
      rule across the top and a drop shadow under them, so four of them beside two raised brand
      cards gave the frame six things all floating at once. Pressed into the panel instead, they
      read as wells cut into the surface the cards sit on, and the hierarchy resolves.

      The recipe, because "inner shadow" alone does not produce a bevel: light comes from above,
      so the TOP inside edge falls into shade (inset 0 2px 5px dark) and the BOTTOM inside edge
      catches the light as a 1px lip (inset 0 -1px 0 white). The fill has to be DARKER than the
      surface around it or nothing reads as recessed however the shadows are tuned. The outer
      1px light line under the tile is the near lip of the hole; without it the shape looks
      painted on rather than cut in.

      Specificity note: the inline <style> in index.html styles `.stat-strip .hstat` at (0,2,0),
      so every rule here is anchored on .cam-hero to clear it. Unanchored, these silently lose
      and the tiles stay raised while the file claims otherwise. */
.cam-hero .cam-stats .hstat{
  background:color-mix(in srgb,var(--panel) 82%,#000);
  border:0;
  box-shadow:inset 0 2px 5px rgba(0,0,0,.55),
             inset 0 1px 1px rgba(0,0,0,.4),
             inset 0 -1px 0 rgba(255,255,255,.055),
             0 1px 0 rgba(255,255,255,.035);
  transition:background .25s ease,box-shadow .25s ease}
/* The gold rule that ran across the top of each tile is what read as a raised edge catching
   light from the front. A recessed surface has no such edge. */
.cam-hero .cam-stats .hstat::before,.cam-hero .cam-stats .hstat::after{content:none}
/* Raised-card hover on a recessed element fights its own shadow. It presses further instead. */
.cam-hero .cam-stats .hstat:hover{transform:none;
  background:color-mix(in srgb,var(--panel) 74%,#000);
  box-shadow:inset 0 3px 7px rgba(0,0,0,.62),
             inset 0 1px 1px rgba(0,0,0,.45),
             inset 0 -1px 0 rgba(255,255,255,.07),
             0 1px 0 rgba(255,255,255,.045)}
/* The icon chip keeps its raised treatment on purpose: an object sitting IN a well is the
   whole read, and it is the one thing that should still catch light. */
.cam-hero .cam-stats .hstat b{font-variant-numeric:tabular-nums;letter-spacing:-.015em}

/* 4. The bloom. House rule, and it is the one thing that reads as generated on sight: a warm
      accent on a dark ground must not glow. The 30px-blurred coloured disc bleeding out of the
      corner is gone and stays gone; the warm corner is a stop in the card's own background
      stack instead, so it is part of the surface rather than a light source floating over it. */
.cam-cards .choose-card .cc-glow{display:none}

/* ONE ACCENT FOR BOTH CARDS (owner request 2026-09-04: "more neat orange"). The pair used to
   run gold on Kurdify and green on KurdConnect, which is the bridge metaphor from the version
   of this hero that still had a rail and a junction node between the two cards. That bridge
   was removed 2026-07-31; the two hues outlived the thing they were explaining and were left
   making an identical pair of cards look like two unrelated components.
   The orange is DERIVED, not imported: a mix of this project's own --gold and --red, so it
   moves with the palette and flips with the theme (dark ~#e0924c, light ~#a35518) instead of
   pinning a literal hex that belongs to no token. Do not replace it with a named orange. */
.cam-hero .cam-cards{--cc-accent:color-mix(in srgb,var(--gold) 62%,var(--red) 38%)}
/* The warm corner sits behind the icon, and the icon sits at the INLINE start, so the gradient
   position has to flip with direction: a gradient is physical and knows nothing about dir. */
.cam-hero .cam-cards .choose-card{--cc-corner:100%}
:root[dir=ltr] .cam-hero .cam-cards .choose-card{--cc-corner:0%}

.cam-cards .choose-card{
  background:
    radial-gradient(78% 62% at var(--cc-corner) 0%,
      color-mix(in srgb,var(--cc-accent) 10%,transparent),transparent 64%),
    linear-gradient(180deg,color-mix(in srgb,var(--panel2) 92%,transparent),var(--panel));
  /* A drop shadow, and nothing else. This declaration read `box-shadow:none 0 22px 46px...`
     from 2026-08 until 2026-09-04: dering.py replaced the leading ring with the keyword `none`
     instead of deleting it, which is not a valid shadow list, so the WHOLE declaration was
     dropped and both cards shipped with no shadow at all. Nothing reported it because the
     result still looks like a deliberate flat card. If you strip a ring out of a shadow list
     again, delete the token, and then read box-shadow back off the live element. */
  box-shadow:0 20px 44px -30px rgba(0,0,0,.9);
  transition:transform .3s cubic-bezier(.22,1,.36,1),box-shadow .3s ease,background .3s ease}
/* Hover lifts and warms. No rim appears, thickens or changes colour: the borderless law covers
   hover, focus and active, not just the resting state. */
.cam-cards .choose-card:hover{transform:translateY(-2px);
  background:
    radial-gradient(78% 62% at var(--cc-corner) 0%,
      color-mix(in srgb,var(--cc-accent) 15%,transparent),transparent 64%),
    linear-gradient(180deg,color-mix(in srgb,var(--panel2) 96%,transparent),var(--panel));
  box-shadow:0 26px 52px -28px rgba(0,0,0,.95)}
/* The icon chip and the tag are the two places the orange is allowed to be loud, and both
   carry it as a FILL. Beats the .choose-card.in/.out gold-and-green pair on class count. */
.cam-cards .choose-card .cc-ic{background:color-mix(in srgb,var(--cc-accent) 15%,transparent);
  color:var(--cc-accent)}
.cam-cards .choose-card .cc-tag{background:color-mix(in srgb,var(--cc-accent) 16%,transparent);
  color:color-mix(in srgb,var(--cc-accent) 78%,var(--text))}
/* The brand tag and the status pill are one group at the head's inline end, so the head keeps
   its two-thing shape (mark at the start, labels at the end) whether or not the status is
   there. Without the wrapper, space-between would spread three children and the icon, tag and
   pill would each drift to a different place on the two cards. */
.cam-cards .choose-card .cc-labels{display:flex;align-items:center;gap:.4rem;min-width:0}
/* Quieter than the brand tag on purpose: it is a status, not a second name. No accent fill,
   because the accent is what marks the two products, and a "Soon" wearing it would read as a
   third brand. Same pill geometry so the two sit on one line without a jog. */
.cam-cards .choose-card .cc-soon{font-size:.6rem;font-weight:700;letter-spacing:.04em;
  padding:.28rem .55rem;border-radius:100px;flex:none;white-space:nowrap;
  background:color-mix(in srgb,var(--text) 9%,transparent);
  color:color-mix(in srgb,var(--text) 62%,transparent)}
:root[dir=rtl] .cam-cards .choose-card .cc-soon{letter-spacing:0}
@media(prefers-reduced-motion:reduce){.cam-cards .choose-card,.cam-cards .choose-card:hover{transition:none;transform:none}}

@media(max-width:900px){
  /* The 2x2 of counts was filling a whole phone screen between the tagline and the photograph,
     so the brand cards, which are the only two links in the hero, started below the fold. The
     tiles keep their debossed treatment and their 2-up grid; they just stop being tall. */
  .cam-hero .cam-stats{margin-top:1.75rem}
  .cam-hero .cam-stats .hstat{padding:.75rem .6rem .7rem}
  .cam-hero .cam-stats .hstat b{font-size:1.2rem}
  .cam-hero .cam-stats .hstat span{font-size:.68rem;line-height:1.35;text-wrap:balance}
  .cam-hero .cam-stats .hs-ic{width:26px;height:26px}
  .cam-hero .cam-stats .hs-ic svg{width:14px;height:14px}
  /* A touch more of the picture. 2/1 was chosen to buy back 21px of fold; with the stat block
     no longer eating a screen above it there is room for 16/9, which is enough for the towers
     and the sky to both be in the frame instead of a letterbox band of middle. */
  .cam-media{aspect-ratio:16/9}
}
/* Note for the next reader, because it looks like a hero bug in a screenshot and is not one:
   the WhatsApp button (.kx-wa) that appears to sit on top of the first brand card's KURDIFY tag
   is position:fixed, pinned 18px off the bottom inline-start corner of the VIEWPORT at z-index 60.
   Measured 2026-08-12. Padding on .cam-hero cannot move it, and a full-height element screenshot
   of the hero renders it wherever it happened to be in the viewport, which is what produced that
   image. It floats over every section of every page by design. If it genuinely has to clear
   something, the fix belongs on .kx-wa, not here. */

/* Hero orb in the preloader's flag colors, slower and smoother (owner request 2026-07-30):
   the single dial ring carries the red arc over a green arc on a faint gold base, turning
   at half the old speed; the pulse breathes over 9s instead of 5.5. */
.ho-r1{border-width:0;
  border-top-width:0;
  border-inline-end-width:0;
  box-shadow:0 0 18px -6px color-mix(in srgb,var(--gold) 45%,transparent)}
.ho-ring{animation-duration:18s}
.ho-core{animation-duration:9s}
.ho-rays{animation-duration:70s}
.ho-stage{animation-duration:22s}

/* Stat strip inside the frame: compact tiles, start-aligned under the headline instead of a
   full-width band of oversized cards (owner feedback 2026-07-30). */

.cam-stats .stat-strip{display:flex;flex-wrap:nowrap;gap:12px;width:fit-content;max-width:100%;overflow-x:auto;scrollbar-width:none}
.cam-stats .stat-strip::-webkit-scrollbar{display:none}
.cam-stats .hstat{flex:none;padding:.8rem 1.15rem;min-width:0}
.cam-stats .hstat b{font-size:1.45rem}
.cam-stats .hstat span{font-size:.68rem;margin-top:.3rem}


/* "Who is Kurdify for": editorial split header, heading at the start and the path line at the
   end of the same baseline, instead of a centered stack (owner feedback 2026-07-30). */
#who .s-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(24ch,38ch);column-gap:2.5rem;align-items:end;max-width:none;text-align:start;margin-inline:0}
#who .s-head .kicker{grid-column:1;grid-row:1}
#who .s-head h2{grid-column:1;grid-row:2;margin:0}
#who .s-head p{grid-column:2;grid-row:1/3;align-self:end;justify-self:end;max-width:38ch;margin:0;text-align:start}
@media(max-width:760px){#who .s-head{grid-template-columns:1fr}#who .s-head p{grid-column:1;grid-row:3;justify-self:start;margin-top:.5rem}}

/* Stat tiles: a bit wider (owner feedback 2026-07-30) */
.cam-stats .hstat{padding:.95rem 1.7rem}
.cam-stats .hstat b{font-size:1.55rem}

/* ==== Camera-frame hero on phones (2026-08-02) ==========================================
   The desktop frame is the reference; this makes the phone carry it instead of a sliced
   copy of it. The mobile block further up already stacks the frame into one column, but
   that column was a plain 1fr track, so any row with an intrinsic minimum wider than the
   phone stretched the whole track past the viewport: the stat strip is width:fit-content
   and the copy and cards carry ch-based max-widths. Measured in English at 390px, every
   row sat 380px wide starting 19px in, so the lead sentence, the tagline and both brand
   cards were cut off against the frame while document.scrollWidth still read 390 and hid
   the fact. Clamp the track, and let the rows obey it. */
@media(max-width:900px){
  .cam-hero{grid-template-columns:minmax(0,1fr)}
  .cam-head,.cam-copy,.cam-us,.cam-cards,.cam-stats{min-width:0;width:100%;max-width:100%}
  .cam-copy .hero-lead,.cam-us .hero-us,.cam-hero h1,.cam-hero .hero-h1{max-width:100%}
  .cam-cards .choose-card p{max-width:none}
}
/* The stat strip had the same shape of bug at every width, phone or not. It was a
   hug-width scroll rail centred inside its grid cell, and a centred flex line that
   overflows spills past BOTH edges with the leading tile parked outside the scroll origin,
   where no swipe can reach it. In English at 1440px that sliced the first and the last tile
   mid-word, with the scrollbar hidden and nothing to suggest the row could move at all.
   The tiles hold four short numbers and carry no content that needs a fixed width, so they
   share the column instead of queueing for it: an equal-cell grid that always fits, no
   scrolling, all four numbers readable. */
.cam-stats{min-width:0}
.cam-stats .stat-strip{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  width:100%;max-width:100%;gap:8px;overflow:visible;margin-inline:0;container-type:inline-size}
.cam-stats .hstat{padding:.95rem .5rem}
.cam-stats .hstat span{text-wrap:balance}
/* The tile is now as wide as the column allows rather than as wide as it likes, so the
   number has to answer to the tile. Six figures with a separator (+261,011) is the widest
   real value /api/stats can produce, and it is what the size is solved against: the cell is
   (container - 3 gaps) / 4, the numeral run measures about 4.6x its own font size, so the
   fluid term keeps the widest number on one line all the way down without dropping it below
   a readable floor. Never let it wrap, a stat that breaks mid-number reads as two stats. */
.cam-stats .stat-strip .hstat b{white-space:nowrap;font-size:clamp(1.05rem,calc(5.2cqi - 6px),1.55rem)}
/* Two per row at every width (owner request 2026-08-03, reversing the one-row-of-four call made
   earlier the same day). What changed in between: the hero gained a third column holding the
   Erbil photograph, which took roughly a sixth of the copy column's width with it. A quarter of
   what was left was no longer enough for a label, so every one of the four wrapped and the row
   read as cramped. Two per row gives each label double the width on one line, and the numbers
   sit at the top of their fluid range instead of the bottom. */
@media(max-width:700px){
  .cam-stats .stat-strip{gap:6px}
  .cam-stats .hstat{padding:.7rem .35rem;border-radius:12px}
  .cam-stats .hstat .hs-ic{width:26px;height:26px;border-radius:8px}
  .cam-stats .hstat .hs-ic svg{width:14px;height:14px}
  /* A single long label word ("categories", "بازرگانی") is wider than a quarter of a small
     phone, so the label is allowed to break inside a word rather than push its tile out. */
  .cam-stats .hstat span{font-size:clamp(.5rem,2.6cqi,.6rem);line-height:1.35;margin-top:.25rem;
    overflow-wrap:anywhere;hyphens:auto}
  /* The desktop floor of the fluid number (1.05rem) is wider than a quarter of a 360px screen,
     so the phone row needs its own, lower floor or the widest count is clipped by its tile. */
  .cam-stats .stat-strip .hstat b{font-size:clamp(.62rem,calc(5.2cqi - 4px),1.35rem)}
}

/* ==== Announcement banner on phones (2026-08-03) =========================================
   The banner text is admin-set, in four languages, so its length is not knowable from here.
   The mobile rule above intended "shrinks rather than wraps" but pinned .74rem and, being the
   later of the two phone rules, it also overrode the smaller .68rem set at 520px. With the
   current sentence that ran 412px wide inside a 390px screen: one line, as designed, and 22px
   of it off the edge, which is how the whole page ended up with horizontal scroll. Size it
   against the viewport so it genuinely shrinks, ease the uppercase tracking, and drop the
   decorative sun on the narrowest screens where every pixel is sentence. */
@media(max-width:640px){
  .topbanner{font-size:clamp(.5rem,2.35vw,.74rem);padding-inline:10px}
  :root[dir=ltr] .topbanner{letter-spacing:.05em}
}
@media(max-width:430px){
  .topbanner{gap:0}
  .topbanner svg{display:none}
  /* The English string still ran 381px wide inside a 375px viewport, the last 3px of horizontal
     overflow on the home page. Dropping the uppercase tracking rather than letting the line wrap
     keeps the rule written above this ("one line, never two, text shrinks rather than wraps")
     and buys far more than the 6px needed: at ~51 characters, .05em is roughly 22px. Measured
     2026-08-14: home scrollWidth 378 -> 375 at 375px in en. */
  :root[dir=ltr] .topbanner{letter-spacing:0}
}

/* ---- creator programme, folded into for-users.html from the retired creators.html
   (owner decision 2026-08-06). Carried over verbatim so the section looks exactly as it did;
   the page chrome rules (.cr-nav, .cr-hero) stayed behind because for-users has its own. */
.cr-wrap{max-width:1080px;margin:0 auto;padding:3rem 1.4rem}
.cr-steps{display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;counter-reset:st}
@media(max-width:820px){.cr-steps{grid-template-columns:repeat(2,1fr)}}
@media(max-width:480px){.cr-steps{grid-template-columns:1fr}}
.cr-step{position:relative;background:var(--panel);border-radius:16px;padding:1.4rem 1.2rem}
.cr-step .n{width:38px;height:38px;border-radius:11px;display:grid;place-items:center;background:color-mix(in oklab,var(--gold) 13%,transparent);color:var(--gold);font-weight:800;font-size:1.1rem;margin-bottom:.8rem}
.cr-step h3{font-size:1rem;margin:0 0 .3rem}
.cr-step p{font-size:.85rem;color:var(--muted);margin:0;line-height:1.55}
.cr-calc{margin-top:2.4rem;background:linear-gradient(135deg,color-mix(in oklab,var(--gold) 9%,transparent),color-mix(in oklab,var(--green) 7%,transparent));border-radius:20px;padding:1.8rem}
.cr-calc h2{font-size:clamp(1.3rem,3.4vw,1.9rem);margin:0 0 .3rem;text-align:center}
.cr-calc .cc-sub{text-align:center;color:var(--muted);font-size:.86rem;margin:0 0 1.4rem}
.cc-row{display:flex;flex-wrap:wrap;align-items:center;gap:1.2rem;justify-content:center}
.cc-slider{flex:1;min-width:240px;max-width:420px}
.cc-slider label{display:flex;justify-content:space-between;font-size:.84rem;margin-bottom:.5rem}
.cc-slider label b{color:var(--gold);font-weight:800}
.cc-slider input[type=range]{width:100%;accent-color:var(--gold)}
.cc-out{text-align:center;min-width:150px}
.cc-out .cv{font-size:clamp(2rem,5vw,2.8rem);font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--gold)}
.cc-out .cl{font-size:.82rem;color:var(--muted);margin-top:.35rem}
.cr-note{font-size:.76rem;color:var(--muted);text-align:center;margin:1.2rem 0 0;opacity:.9}
.cr-feats{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-top:2.4rem}
@media(max-width:760px){.cr-feats{grid-template-columns:1fr}}
.cr-feat{background:var(--panel);border-radius:14px;padding:1.2rem}
.cr-feat .fi{width:40px;height:40px;border-radius:11px;display:grid;place-items:center;background:color-mix(in oklab,var(--green) 12%,transparent);color:var(--green);margin-bottom:.7rem}
.cr-feat h3{font-size:.96rem;margin:0 0 .25rem}
.cr-feat p{font-size:.83rem;color:var(--muted);margin:0;line-height:1.55}
.cr-band{margin-top:2.6rem;text-align:center;background:var(--panel);border-radius:20px;padding:2rem 1.6rem}
.cr-band h2{font-size:clamp(1.4rem,4vw,2.1rem);margin:0 0 .5rem}
.cr-band p{color:var(--muted);max-width:600px;margin:0 auto 1.3rem;line-height:1.6}

/* Motion is an enhancement here, never the thing that makes the menu usable. */
@media(prefers-reduced-motion:reduce){
  .lang-menu,.more-menu{transition:none;transform:none}
  .lang-menu.open,.more-menu.open{transform:none}
  .more-chev{transition:none}
}

/* ===== BORDERLESS PASS, marketing site (owner rule, 2026-08-23) =======================
   "Go across all Kurdify pages and remove anything that has a border like this, and make it
   better." The house rule has been borderless since 2026-08-19; index.html, autos.html and the
   SSR business page all carry the pass, and the 15 marketing pages never got it.

   Scoped by MEASUREMENT, not by grep. tools/border-audit.mjs was run over all 15 routes at
   1496px before any edit: 308 elements were flagged, but only 29 distinct components actually
   paint a border. The rest were the pass's OWN replacement device being counted, the 1px inset
   top highlight that stands in for a rim. So this block names the 29, not the 308.

   Three things are deliberately NOT removed, because each draws a picture rather than a box:
     - .bp-frame / .bp-bar / .bp-notch and .px-* are a browser chrome and a phone. Their lines
       are the device, and deleting them leaves a screenshot floating in space.
     - .tl-dot, .fx-lc-logo, .kfy-medal: rings that separate a mark from what it sits on.
     - every :focus indicator. Focus is a state, not a rim, and several of these borders were
       doubling as one, so they are re-issued as outlines wherever a border is taken away.

   Placed at the end of the file so it wins on source order at matching specificity. Anything a
   page defines in its own inline <style> beats this file whatever the order here, so page-local
   components are handled in the page, not from here. */

/* The first-year offer band on /pricing, the one in the owner's screenshot. It was a green
   rim around a green wash, so the hue was stated twice and the band read as an alert box. The
   rim goes; the fill comes up and gains a green bar on the start edge, which points at the
   number instead of fencing the whole row. */
.card-offer{border:0;
  background:linear-gradient(90deg,color-mix(in srgb,var(--green) 14%,var(--panel)),
    color-mix(in srgb,var(--green) 5%,var(--panel)));
  box-shadow:inset 3px 0 0 color-mix(in srgb,var(--green) 62%,transparent),
    0 10px 28px -22px rgba(0,0,0,.7)}
html[dir="rtl"] .card-offer{
  background:linear-gradient(270deg,color-mix(in srgb,var(--green) 14%,var(--panel)),
    color-mix(in srgb,var(--green) 5%,var(--panel)));
  box-shadow:inset -3px 0 0 color-mix(in srgb,var(--green) 62%,transparent),
    0 10px 28px -22px rgba(0,0,0,.7)}
html[data-theme="light"] .card-offer{box-shadow:inset 3px 0 0 color-mix(in srgb,var(--green) 62%,transparent),
  0 8px 20px -18px rgba(15,40,45,.28)}
html[data-theme="light"][dir="rtl"] .card-offer{box-shadow:inset -3px 0 0 color-mix(in srgb,var(--green) 62%,transparent),
  0 8px 20px -18px rgba(15,40,45,.28)}

/* Icon tiles and the verified pill: each was a tint with a stronger rim of the same hue drawn
   around it, which is the tint stated twice. One statement, at the strength the pair had. */
.mm-links .mm-ic{border:0;background:color-mix(in srgb,currentColor 17%,transparent);
  transition:background .15s ease}
.gv-rw-ic{border:0;background:color-mix(in oklab,var(--gold) 22%,transparent)}
.listing-card .verified{border:0;background:color-mix(in oklab,var(--green) 24%,transparent)}

/* .btn.ghost was `background:transparent` with a transparent border, so the secondary action
   on every marketing page was text with no object under it. It gets a real surface. */
.btn.ghost{background:color-mix(in srgb,var(--text) 7%,transparent)}
.btn.ghost:hover{background:color-mix(in srgb,var(--gold) 14%,transparent);color:var(--text)}
html[data-theme="light"] .btn.ghost{background:color-mix(in srgb,var(--text) 6%,transparent)}
