/* Kurdify site header: the one source of truth for the bar on every surface.
   Nexus V22 / Kavalsia Inc. / Siavash Sadighi

   LOAD THIS LAST, immediately before </body>, never from <head>.
   Every page in this repo keeps its CSS in inline <style> blocks, so a <link> in
   the head would lose every equal-specificity contest to rules further down the
   document. Loaded at the end it occupies the same cascade position on all
   surfaces, which is the only reason one file can drive twelve pages.

   It reads the host page's own theme tokens (--gold, --text, --muted, --panel,
   --line2, --bg, --green); all twelve pages define them. The --h-* tokens below
   are declared ON .topbanner and .nav, never on :root, so the header's own
   palette cannot leak into the page underneath it.

   TYPE IS LATIN-ONLY, DELIBERATELY. Source Sans 3 has no Arabic-script coverage
   and Kurdify's default language is Sorani, so it is scoped to :lang(en) and
   :lang(kmr). ckb and ar keep the site's own face.

   Every horizontal offset is a LOGICAL property. The default language is RTL and
   a physical margin-left:auto silently breaks Sorani. */

/* ---------------------------------------------------------------- tokens ---- */
/* .mobile-menu IS IN THIS LIST, and leaving it out was a silent bug for two days.
   The sheet is a SIBLING of .nav, not a descendant of it (see the shell in REPO-MAP.md), so
   every var(--h-*) inside it resolved against nothing. A failed var() does NOT fall back to
   the previous declaration: the property becomes invalid at computed-value time and computes
   to its INITIAL value, so `background:color-mix(in srgb,var(--h-gold) 18%,transparent)` came
   out transparent rather than dropping through to the .06 chip underneath it. The four rules
   that carry the sheet's entire hierarchy were dead: the active link, the SELECTED language
   pill, the theme label and its icon. Net effect, the selected language was the only pill with
   no chip and no gold, so the one item that had to look chosen looked disabled. */
.topbanner,.nav,.mobile-menu{
  --h-ink:#1a171f;
  --h-ink-deep:#141118;
  --h-gold:#ffce85;
  --h-gold-soft:#f6dcb6;
  --h-line:rgba(255,255,255,.11);
  --h-text:#f7f2ec;
  --h-muted:rgba(246,240,232,.72);   /* 8.7:1 on the header floor */
  --h-muted-2:rgba(246,240,232,.56); /* 5.3:1 */
  --h-ease:cubic-bezier(.22,1,.36,1);
}
:is(.topbanner,.nav) :lang(en),:is(.topbanner,.nav) :lang(kmr){
  font-family:"Source Sans 3","Helvetica Neue",Helvetica,Arial,sans-serif;
}

/* ------------------------------------------------- announcement top bar ---- */
/* A plain full-width strip at the very top of the page. Deliberately NOT part of
   the floating stack: it is the one piece of chrome that stays a bar. */
.topbanner{
  position:relative;z-index:41;
  background:var(--h-ink-deep);color:var(--h-muted-2);
  font-weight:400;font-size:.78rem;letter-spacing:.01em;text-align:center;
  display:flex;align-items:center;justify-content:center;
  padding-block:8px;padding-inline:16px;min-height:38px;
  gap:clamp(10px,2vw,22px);flex-wrap:nowrap;border-bottom:0;
}
.topbanner > *{white-space:nowrap}
.topbanner svg{width:14px;height:14px;flex:none;color:var(--h-gold)}
.topbanner a{
  color:var(--h-muted);font-weight:500;text-decoration:none;
  border-bottom:0;transition:color 200ms,border-color 200ms;
}
.topbanner a:hover{color:var(--h-gold);border-bottom-width:0}
/* Background and colour move together or not at all. Setting only the colour here
   left the marketing pages under site/ pairing this cream text with their OWN light
   gold banner ground, which measured 1.13:1. The whole header stack is dark in both
   themes, so the strip is too. */
html[data-theme="light"] .topbanner{background:var(--h-ink-deep);color:var(--h-muted-2)}
/* two centred lines rather than a ragged wrap */
@media (max-width:619px){
  .topbanner{flex-direction:column;gap:3px;min-height:0;padding-block:7px;
             font-size:.76rem;line-height:1.35}
}

/* ------------------------------------------------------ the floating bar ---- */
/* The shell is transparent and carries only position. The glass is on .wrap, so
   whatever is behind the header (a hero photograph on the home page, the page
   ground everywhere else) shows around the pane rather than behind a slab. */
.nav{
  position:sticky;top:clamp(14px,2vw,24px);z-index:40;
  background:transparent;border-bottom:0;
  padding-inline:clamp(12px,3vw,28px);
  margin-top:clamp(14px,2vw,22px);
  transition:top 420ms var(--h-ease);
}
html[data-theme="light"] .nav{background:transparent}

/* ------------------------------------------ the old full-width bar, reset ---- */
/* THE DOUBLED `.nav.nav` IS A SPECIFICITY GUARD, NOT A TYPO, the same device site.css
   already uses on `.cam-slide.cam-slide` and for the same reason.

   Every surface that predates the floating pill still carries its own copy of the OLD
   full-width bar on `.nav`. The shell is now a transparent full-viewport carrier for an
   1180px pill, so each of those declarations paints about 283px past the pill on either
   side with no background and no edge to explain it:
     site.css:62, pro:36, user.html:79   background + border-bottom + backdrop-filter
     site.css:63                         .nav::after, a gold hairline at inset-inline:0,
                                         measured rendering right across the viewport
     media-kit.html:43                   .nav::before, inset-inline:-999px, its own blur,
                                         deliberately 999px wider each way
     data.html:167                       .nav.scrolled, blur(16px), TWO classes

   That last one is why the selector is doubled. A plain `.nav{}` reset is (0,1,0) and loses
   to `.nav.scrolled` (0,2,0) outright, so /data got its blur band back the moment the page
   scrolled, after the band had been fixed on every other surface. `.nav.nav` ties any
   single-modifier page rule and wins on order, because this file loads last on all of them.
   It also covers the next page to be written this way without another round of this.

   Pseudo-elements are neutralised, never `content:none`, so a surface may still hang its own
   decoration off the hooks; what goes is the ground, the blur and the rule, not the element. */
.nav.nav{
  background:transparent;border-bottom:0;
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
.nav.nav::before,.nav.nav::after{
  background:none;border:0;box-shadow:none;
  backdrop-filter:none;-webkit-backdrop-filter:none;
}

.nav .wrap{
  position:relative;
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  width:min(1180px,100%);margin-inline:auto;
  height:auto;min-height:68px;
  padding-block:12px;padding-inline:clamp(16px,2.4vw,26px);
  border-radius:18px;
  /* Real glass: a top-lit sheen over a translucent ground, a 1px rim picked out in
     white rather than a drawn border, drop shadow doing the lifting. A flat rgba
     fill under a blur reads as a grey box, not as glass. */
  background:
    linear-gradient(178deg,rgba(255,255,255,.075),rgba(255,255,255,.018) 42%,rgba(255,255,255,0) 78%),
    rgba(23,19,28,.34);
  backdrop-filter:blur(26px) saturate(1.7);
  -webkit-backdrop-filter:blur(26px) saturate(1.7);
  /* Inset highlights only, no outward drop-shadow (2026-08-14): .wrap has no
     overflow:hidden ancestor to clip one, and this pill sits directly on top of
     page content (a hero photo on the home page), so an outward blur bled past
     the rounded corners onto whatever was underneath as a stray glow smear.
     The same fix already applied to the nav-actions button cluster. */
  /* Border pass, 2026-08-31: the two inset layers here were a rim, split across three
     physical lines, which is why the automated dering.py pass could not see them (it reads
     one line at a time and this property's value started on the next line down). Found by
     hand-checking the AFTER border-audit, which still listed .wrap. The gradient + backdrop
     blur above already carries the glass surface without an edge. */
  box-shadow:none;
  transition:background 420ms var(--h-ease),box-shadow 420ms var(--h-ease);
}
/* Once the bar has pinned it tightens and darkens, so it reads as chrome over the
   content rather than as part of the hero. header.js adds .stuck. */
.nav.stuck .wrap{
  background:
    linear-gradient(178deg,rgba(255,255,255,.055),rgba(255,255,255,.012) 42%,rgba(255,255,255,0) 78%),
    rgba(19,16,23,.56);
  min-height:62px;
  box-shadow:none; /* border pass, 2026-08-31: same multi-line rim as .nav .wrap above */
}
/* THE BAR IS DARK IN BOTH THEMES (owner's call, 2026-08-13). It was dark-only by
   accident before: a translucent dark ground with no light branch composited to a
   flat #a8a9ac slab over a light page, and the cream text on it measured 1.74:1.
   Going opaque in light mode is what turns that accident into the decision. */
html[data-theme="light"] .nav .wrap{
  background:
    linear-gradient(178deg,rgba(255,255,255,.075),rgba(255,255,255,.018) 42%,rgba(255,255,255,0) 78%),
    rgba(23,19,28,.90);
}
html[data-theme="light"] .nav.stuck .wrap{
  background:
    linear-gradient(178deg,rgba(255,255,255,.055),rgba(255,255,255,.012) 42%,rgba(255,255,255,0) 78%),
    rgba(19,16,23,.94);
}
/* Without backdrop-filter the sheen would sit over nothing, so those browsers get
   an opaque ground instead of a see-through bar. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nav .wrap{background:rgba(23,19,28,.95)}
  .nav.stuck .wrap{background:rgba(19,16,23,.97)}
}
@media (prefers-reduced-motion:reduce){.nav,.nav .wrap{transition:none}}

/* ------------------------------------------------------------- wordmark ---- */
/* min-height, not height: the brand is a link and therefore a tap target, and its own
   content (22px sun + one line of wordmark) only ever reached 22-30px depending on the
   surface. The floor is the contract's 44px; a page carrying the .wm subtitle is taller
   than the floor already and is unaffected. Queue 387. */
.nav .brand{
  display:flex;align-items:center;gap:10px;flex:none;min-height:44px;
  font-weight:800;font-size:1.15rem;letter-spacing:-.02em;
  color:var(--h-text);text-decoration:none;cursor:pointer;
}
.nav .brand b{color:var(--h-gold);font-weight:800}
.nav .brand .sun{width:22px;height:22px;flex:none;color:var(--h-gold)}
/* Some pages carry a per-page subtitle under the wordmark. It is part of the
   component, not a special case, so it has a size here rather than per page. */
.nav .brand .wm{display:flex;flex-direction:column;line-height:1.15}
.nav .brand .wm small{
  font-size:.62rem;font-weight:500;letter-spacing:.02em;
  color:var(--h-muted-2);text-transform:none;
}
.nav .brand .wm small:empty{display:none}

/* ---------------------------------------------------------------- links ---- */
.nav .nav-links{display:flex;align-items:center;gap:17px;min-width:0}
.nav .nav-links a{
  position:relative;color:var(--h-muted);font-size:.9rem;font-weight:500;
  white-space:nowrap;padding-block:6px;text-decoration:none;
}
.nav .nav-links a::after{
  content:"";position:absolute;inset-inline-start:50%;inset-inline-end:50%;bottom:0;
  height:1px;border-radius:2px;background:var(--h-gold);
  transition:inset-inline-start .22s var(--h-ease),inset-inline-end .22s var(--h-ease);
}
.nav .nav-links a:hover{color:#fff}
.nav .nav-links a:hover::after,
.nav .nav-links a.nav-on::after{inset-inline-start:0;inset-inline-end:0}
.nav .nav-links a.nav-on{color:var(--h-gold)}
@media (prefers-reduced-motion:reduce){.nav .nav-links a::after{transition:none}}

/* the one gold call to action that lives in the bar.
   BORDERLESS GLASS, not a ringed chip (owner's call 2026-08-22). index.html has said
   `border:none` on this pill for as long as it has existed and it never once applied:
   that rule is `.nav-links a.nav-ask` at (0,2,0), this one is (0,3,0), and specificity is
   settled before file order is consulted, so the gold hairline below was the one on screen
   at every width. Same family as the `#main .rowcard` note in REPO-MAP: a borderless sweep
   that does not match the winning selector is decoration.
   The shape now comes from the ground, the blur and one soft shadow instead of a rim. There is
   no top light: `inset 0 1px 0` is a lit edge and the borderless law bans it by name. The
   gradient ground is what keeps the pill from reading as a flat slab, and it composites rather
   than replacing, which a background-image sheen would not (see the .btn/.coupon note in
   REPO-MAP TRAPS).
   #822: the shadow read `box-shadow:none 0 8px 20px -12px rgba(0,0,0,.7)` until 2026-09-04, so
   the parser dropped the declaration and the pill shipped with no shadow on every page this
   sheet reaches (computed `none`, measured on :4660). This sheet is also site/assets/header.css
   by symlink, so one file covers the app and all 12 marketing pages.
   The @supports branch matters because without backdrop-filter the ground alone is a
   washed-out patch, so those browsers get an opaque one instead. */
.nav .nav-links a.nav-ask{
  display:inline-flex;align-items:center;gap:6px;
  color:var(--h-gold);font-weight:800;
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--h-gold) 22%,transparent),
    color-mix(in srgb,var(--h-gold) 11%,transparent));
  border:none;
  backdrop-filter:blur(16px) saturate(140%);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  box-shadow:0 8px 20px -12px rgba(0,0,0,.7);
  border-radius:100px;padding:.4rem .9rem;margin-inline-end:10px;
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nav .nav-links a.nav-ask{background:color-mix(in srgb,var(--h-gold) 20%,#131a1e)}
}
.nav .nav-links a.nav-ask svg{width:16px;height:16px;flex:none}
.nav .nav-links a.nav-ask::after{display:none}
.nav .nav-links a.nav-ask:hover{
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--h-gold) 32%,transparent),
    color-mix(in srgb,var(--h-gold) 18%,transparent));
  color:var(--h-gold);
}
.nav .nav-links a.nav-ask .nav-ask-dot{
  display:inline-block;width:6px;height:6px;border-radius:50%;
  background:var(--green);flex:none;
}

/* dropdowns inside the bar */
.nav .csel{position:relative}
.nav .nav-more .csel-btn{
  background:none;border:0;color:var(--h-muted);
  font-size:.9rem;font-weight:500;font-family:inherit;
  display:inline-flex;align-items:center;gap:5px;cursor:pointer;padding-block:6px;
}
.nav .nav-more .csel-btn:hover{color:#fff}
.nav .nav-more .cs-chev{width:12px;height:12px;transition:transform .18s ease}
.nav .csel.open .cs-chev{transform:rotate(180deg)}
/* THE SAME GLASS AS kurdify.app (owner request 2026-08-25: "make this dropdown in
   app.kurdify.app like kurdify.app"). The marketing pages got this treatment on 2026-08-14
   in site.css (`.nav .lang-menu,.nav .more-menu`), but site.css is not loaded on this host, so
   the app surfaces kept the original flat `--panel` slab with a hard 1px `--line2` outline:
   opening a menu dropped an opaque card out of a translucent bar. The values below are copied
   from that block on purpose, not re-invented, so the two hosts cannot drift again.
   Rims are rgba white, never `--line2`: on app.kurdify.app that token is neutered transparent
   by the borderless pass, so a --line2 rim vanishes here and draws hard on the site pages.
   The ground (.94) is more opaque than the bar's: 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 GROUND IS OPAQUE AND THE MENU HAS NO backdrop-filter OF ITS OWN, and both halves are
   deliberate. Reported twice as "the dropdown is still not fixed" and chased twice to the wrong
   cause (a stale ?v=7 cache, correctly retracted in queue #678) because the computed style was
   always right: getComputedStyle reported rgba(19,16,23,.94) and blur(22px) on the live host
   while the hero headline read straight through the panel. The style was applying; the PAINT
   was wrong.

   Cause, established by controlled experiment on the deployed page rather than by reading:
   the menu's ancestor `.nav .wrap` carries its own backdrop-filter (blur(26px) saturate(1.7)),
   which makes it a backdrop root, and the menu hangs 287px BELOW that ancestor's box (menu
   bottom 379, .wrap bottom 92). A translucent background on a descendant that escapes a
   backdrop-filtered ancestor does not composite at its declared alpha: at .94 and at .97 the
   headline behind was plainly legible, far more than 6% or 3% of it. Removing the ancestor's
   filter fixed it, and so did an alpha of exactly 1; removing only the MENU's own filter did
   not, and neither did raising the alpha to .97. So neither the alpha nor this element's blur
   was ever the lever.

   The blur is dropped rather than kept because inside that backdrop root it had nothing left to
   sample: it was paying compositor cost to filter an empty backdrop. The white sheen gradient
   stays, and it is what still reads as glass -- the look the 2026-08-25 owner request asked for
   ("make this dropdown in app.kurdify.app like kurdify.app") survives, only the transparency it
   was riding on is gone.

   DO NOT reintroduce an alpha below 1 here, and do not add an @supports fallback that sets one:
   the previous fallback branch set rgba(19,16,23,.97) and would have re-broken this on any
   browser without backdrop-filter, which is why it is gone rather than merely 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 .csel-menu{
  position:absolute;top:calc(100% + 12px);inset-inline-end:0;min-width:200px;
  border:0;border-radius:15px;padding:7px;z-index:90;display:none;
  background:
    linear-gradient(178deg,rgba(255,255,255,.07),rgba(255,255,255,.015) 45%,rgba(255,255,255,0) 80%),
    #131017;
  /* Border pass, 2026-08-31: kept the elevation layer, dropped the two rim layers
     (same multi-line blind spot as .nav .wrap above). */
  box-shadow:0 20px 44px -16px rgba(0,0,0,.72);
}
.nav .csel.open .csel-menu{display:block}
/* 44px is the touch minimum and stays that on a coarse pointer. A mouse does not need it, and
   a column of 44px rows makes a seven-item menu read as a list of sections rather than a menu,
   so the fine-pointer row tightens to 40px. Same split as the site pages. */
/* THREE classes deep on purpose. The options in the two nav menus are <a> inside .nav-links, so
   `.nav .nav-links a` (0,2,1) outranks a `.nav .csel-opt` (0,2,0) written here and the rows kept
   the LINK ROW's .9rem/500 instead of the menu type this rule sets. Measured before the fix:
   font-size 12.96px, font-weight 500. .nav .csel-menu .csel-opt is 0,3,0 and wins, and it also
   scopes the row to a menu rather than to anything that happens to carry the class. */
.nav .csel-menu .csel-opt{
  display:flex;align-items:center;gap:8px;
  min-height:40px;padding:.5rem .75rem;border-radius:11px;cursor:pointer;
  font-size:.88rem;font-weight:600;color:var(--h-text);text-decoration:none;white-space:nowrap;
}
@media (pointer:coarse){.nav .csel-menu .csel-opt{min-height:44px}}
/* Hover picks up the brand the way the header's own controls do, instead of a flat panel swap. */
.nav .csel-menu .csel-opt:hover{
  background:color-mix(in srgb,var(--h-gold) 11%,rgba(255,255,255,.05));
  color:var(--h-text);
}
.nav .csel-menu .csel-opt.sel,.nav .csel-menu .csel-opt.nav-on{color:var(--h-gold)}
@media (prefers-reduced-motion:reduce){.nav .nav-more .cs-chev{transition:none}}

/* ------------------------------------------------------- control cluster ---- */
/* Glass on each button, contained this time (2026-08-14). The first pass here went
   flat (var(--panel) + inset 1px var(--line2)) to kill an outward box-shadow glow
   that bled past the header's edge with no overflow:hidden to clip it. That threw
   out the glass look along with the bug: on app.kurdify.app --line2 is neutered
   transparent by the borderless pass so the rim vanished entirely (flat, no edge),
   and on kurdify.app's site/*.html pages --line2 is a real color so the same rule
   drew a hard, un-glass-like outline instead. Restored the original soft sheen
   gradient + translucent ground + rgba-based inset highlights (contained inside
   the button, they cannot bleed), and kept ONLY the fix: no outward box-shadow
   layer, so nothing escapes past the button's own edge. */
/* THE CLUSTER IS A ROW, NOT A CONTAINER (owner request 2026-08-14: "remove the background
   behind the buttons and the border, just buttons"). site.css:97 wraps these in a second pill
   of its own: padding + radius + panel background + 1px border + an inset highlight, so the
   three glass buttons sat inside a fourth box that repeated the header's own frame one level
   down. Reset here rather than edited there, because site.css owns only the marketing pages
   while this file is the cluster on all twelve surfaces. Each button keeps its own glass; the
   thing around them is gone. */
.nav.nav .nav-actions{
  display:inline-flex;align-items:center;gap:4px;flex:none;
  background:none;border:0;box-shadow:none;padding:0;border-radius:0;
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
/* The notifications bell joins the cluster here rather than styling itself in
   dashboard/notify.css. That file gives .kn-btn a 38px box, an 11px radius and a 1px
   --line2 border so it can stand alone on a page with no cluster, and next to these
   four that read as a smaller, teal-rimmed control from another surface. This file is
   the one source of truth for the bar on all twelve surfaces, so the bell is listed
   with its siblings and inherits the identical glass. Its own rules still apply where
   there is no .nav-actions around it. */
.nav .nav-actions .theme-btn,
.nav .nav-actions .csel-btn,
.nav .nav-actions .icon-btn,
.nav .nav-actions .lang-btn,
.nav .nav-actions .kn-btn{
  min-width:44px;min-height:44px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:12px;border:0;cursor:pointer;
  font-family:inherit;font-size:.85rem;font-weight:700;white-space:nowrap;
  color:var(--h-text);
  background:
    linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.04) 42%,transparent 78%),
    rgba(255,255,255,.05);
  box-shadow:none; /* border pass, 2026-08-31: same multi-line rim as .nav .wrap above */
  transition:transform .18s ease,box-shadow .18s ease;
}
.nav .nav-actions .csel-btn,
.nav .nav-actions .lang-btn{padding-inline:14px;gap:8px}
.nav .nav-actions .theme-btn svg,
.nav .nav-actions .csel-btn svg,
.nav .nav-actions .icon-btn svg,
.nav .nav-actions .lang-btn svg,
.nav .nav-actions .kn-btn svg{width:18px;height:18px;flex:none}
.nav .nav-actions .cs-chev{width:13px;height:13px;color:var(--h-muted);flex:none;transition:transform .2s}
.nav .nav-actions .theme-btn:hover,
.nav .nav-actions .csel-btn:hover,
.nav .nav-actions .icon-btn:hover,
.nav .nav-actions .lang-btn:hover,
.nav .nav-actions .kn-btn:hover{
  box-shadow:none; /* border pass, 2026-08-31: same multi-line rim as .nav .wrap above */
}
/* notify.css turns the glyph gold on hover and gold-tints the ground when the panel is
   open. Both are correct standing alone and wrong in a row where every sibling goes to
   white, so the cluster's own behaviour wins and the open state is carried by the rim. */
.nav .nav-actions .kn-btn:hover{color:#fff;border-width:0}
.nav .nav-actions .kn-btn[aria-expanded="true"]{
  color:var(--h-gold);border-width:0;
  background:
    linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.04) 42%,transparent 78%),
    rgba(255,255,255,.05);
  box-shadow:none; /* border pass, 2026-08-31: same multi-line rim as .nav .wrap above */
}
.nav .nav-actions .theme-btn:active,
.nav .nav-actions .csel-btn:active,
.nav .nav-actions .icon-btn:active,
.nav .nav-actions .lang-btn:active,
.nav .nav-actions .kn-btn:active{transform:translateY(1px)}
.nav .nav-actions .theme-btn:focus-visible,
.nav .nav-actions .csel-btn:focus-visible,
.nav .nav-actions .icon-btn:focus-visible,
.nav .nav-actions .lang-btn:focus-visible,
.nav .nav-actions .kn-btn:focus-visible{outline:2px solid var(--h-gold);outline-offset:2px}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nav .nav-actions .theme-btn,
  .nav .nav-actions .csel-btn,
  .nav .nav-actions .icon-btn,
  .nav .nav-actions .lang-btn,
  .nav .nav-actions .kn-btn{background:var(--panel);box-shadow:none}
}
@media (prefers-reduced-motion:reduce){
  .nav .nav-actions .theme-btn,
  .nav .nav-actions .csel-btn,
  .nav .nav-actions .icon-btn,
  .nav .nav-actions .lang-btn,
  .nav .nav-actions .kn-btn{transition:none}
  .nav .nav-actions .theme-btn:active,
  .nav .nav-actions .csel-btn:active{transform:none}
}

/* ONE ORDER FOR THE CLUSTER ON BOTH HOSTS: language, then account. The marketing pages
   write it that way in their markup and index.html writes it the other way round, so the
   same two controls swapped places depending on which host you were on. Fixed with `order`
   for the same reason the phone bar's own order is: the component decides the bar, the
   page decides only what is in it. Not scoped to a breakpoint, because the two hosts
   disagreed at every width. */
.nav .nav-actions #acctBtn{order:1}

/* Server-rendered surfaces (the creator media kit) switch language with ?lang= links
   rather than the dropdown, because they are rendered per language and have no
   setLang to call. Same cluster, same glass, links instead of a menu. */
.nav .nav-actions .langs{display:flex;align-items:center;gap:2px}
.nav .nav-actions .langs .lg{
  display:inline-flex;align-items:center;justify-content:center;
  /* 38px was 6px under the contract floor on every surface linking this file. The newer
     .lang-btn/.csel-btn cluster at line 291 has been 44px for a while; this is the older
     ?lang= link cluster the server-rendered surfaces use, brought into step. Queue 387. */
  min-height:44px;padding-inline:11px;border-radius:11px;
  font-size:.82rem;font-weight:700;color:var(--h-muted);text-decoration:none;
}
.nav .nav-actions .langs .lg:hover{color:#fff;background:rgba(255,255,255,.07)}
.nav .nav-actions .langs .lg.on{
  color:var(--h-gold);
  background:color-mix(in srgb,var(--h-gold) 16%,transparent);
}

/* Two historical class names for the same two controls: the app surfaces call them
   .theme-btn and .csel-btn, the marketing pages under site/ call them .icon-btn and
   .lang-btn. Both are listed above rather than given a duplicate block, so the cluster
   cannot drift between the two hosts. */
/* ---------------------------------------------------------------- burger ---- */
.nav .burger{
  display:none;background:none;border:0;color:var(--h-text);
  cursor:pointer;padding:6px;border-radius:9px;
  min-width:44px;min-height:44px;align-items:center;justify-content:center;
}
.nav .burger svg{width:24px;height:24px;flex:none}
.nav .burger:hover{background:rgba(255,255,255,.07)}
.nav .burger:focus-visible{outline:2px solid var(--h-gold);outline-offset:2px}

/* ----------------------------------------------------------- responsive ---- */
/* Below 1080 the link row is dropped and the burger takes over. The bar keeps its
   controls to 1079 rather than collapsing at 768, where a 1500px-wide bar used to
   sit empty next to a burger. Written as `not all and (min-width:1080px)` on
   purpose: max-width:1079 plus min-width:1080 is not a clean hand-off, it leaves
   the fractional widths between them matching neither rule. */
@media not all and (min-width:1080px){
  .nav .nav-links{display:none}
  .nav .burger{display:inline-flex}

  /* THE PHONE BAR IS BURGER / WORDMARK / CONTROLS (owner's call 2026-08-16).
     Before this the two hosts disagreed, because each page's own DOM order decided
     the layout and the two orders are opposite: site/*.html writes .nav-actions
     BEFORE .burger, index.html writes .burger before .nav-actions. Measured at 375
     the same day: on kurdify.app the cluster sat at x=166 with the burger at 295,
     on app.kurdify.app the burger sat at 219 with the cluster at 277, and on both
     the wordmark was jammed against the leading edge, 106-116px off centre.
     `order` decides it here instead, so one component gives twelve surfaces the
     same bar whatever order their markup happens to be in. */
  .nav .burger{order:-1;margin-inline-start:0}
  .nav .nav-actions{order:1}

  /* CENTRED BETWEEN ITS NEIGHBOURS, NOT IN THE BAR (changed 2026-08-21).
     It was absolute: `inset:0; margin:auto; max-width:calc(100% - 200px)`, centred on
     the bar itself. That reserves width SYMMETRICALLY, and the thing it has to clear is
     on ONE side, so the reservation cannot express the constraint. It held only while
     every consumer's cluster stayed near the 92px this rule was written against.
     dashboard/user.html's cluster is 140px (notification + theme + language + log out),
     and there the wordmark ran UNDER the cluster at every phone width measured:
     56px of overlap at 320, 30 at 375, 22 at 390, still 3 at 430, and worse in Sorani
     (36 at 375) because the wordmark is wider. index.html overlapped by 6-10px at 320.
     Measured on ten app surfaces in en and ckb, 2026-08-21.
     No symmetric max-width fixes that: clearing a 140px cluster on both sides at 320px
     leaves 20px for the wordmark. So the brand goes back in flow, where the layout
     cannot place it on top of a sibling at all. margin-inline:auto splits the free space
     either side of it, which IS the bar centre whenever the burger and the cluster are
     the same width (every marketing surface: 44 and 44) and drifts only as far as they
     actually differ. Off centre by the amount the two sides genuinely disagree beats
     covering a control, which is what the old rule did.
     min-width:0 is load-bearing: a flex item's default min-width:auto refuses to shrink
     below its content, so without it the wordmark pushes the cluster off the bar instead
     of truncating.
     STILL GUARDED ON THE BURGER: a surface without one (creator-page.mjs, seo-pages.mjs,
     dashboard/media-kit.html) has only .brand + .nav-actions, and space-between already
     puts those at opposite ends. They keep the two-item bar untouched. */
  .nav .wrap:has(.burger) .brand{
    margin-inline:auto;
    /* flex-shrink, not just min-width. .brand carries `flex:none` in the base rule, which is
       flex:0 0 auto: it refuses to shrink whatever min-width says, so at 320px on the widest
       cluster the bar's own content overflowed by 30px. Both are needed. */
    flex-shrink:1;
    min-width:0;
    overflow:hidden;
  }
  .nav .wrap:has(.burger) .brand > span{
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
}
@media not all and (min-width:620px){
  .nav .wrap{padding-inline:16px}

  /* THE LANGUAGE CONTROL IS A GLOBE ON A PHONE (owner's call 2026-08-16), because a
     centred wordmark only has a middle to sit in if the sides stay square. Four full
     names run 44px to 102px wide and the widest of them is the one a Sorani-first
     product shows by default.
     The name is not lost: the burger sheet writes the full language row, which is
     where a deliberate switch belongs, and the dropdown behind this button still
     lists all four. header.js puts the globe into the buttons that have no icon of
     their own (the app writes .csel-btn as text + chevron), so hiding the label here
     can never leave an empty square. */
  .nav .nav-actions .lang-btn > span,
  .nav .nav-actions .csel-btn > span,
  .nav .nav-actions .csel-btn > .cs-chev{display:none}
  .nav .nav-actions .csel-btn,
  .nav .nav-actions .lang-btn{padding-inline:0;gap:0;width:44px}
}
/* THE CLUSTER USED TO BE HIDDEN OUTRIGHT BELOW 620, AND THAT RULE NEVER RAN.
   `.nav .nav-actions{display:none}` is (0,2,0) and the cluster's own layout rule
   `.nav.nav .nav-actions{display:inline-flex}` up in the cluster section is (0,3,0),
   which wins in every media query there is: specificity is resolved before the
   at-rule ever matters. So every phone has been showing the cluster since the
   .nav.nav specificity guard was added, and the hide was dead CSS that read as live.
   Deleted rather than repaired, because the owner asked for exactly what was already
   on screen: language and account beside the burger. Recorded here so the next
   reader does not "restore" it. */

/* ----------------------------------------------------------- mobile menu ---- */
.mobile-menu{
  display:none;flex-direction:column;gap:2px;
  width:min(1180px,calc(100% - 2*clamp(12px,3vw,28px)));
  margin-inline:auto;margin-top:8px;padding:10px;
  border-radius:18px;position:sticky;top:calc(clamp(14px,2vw,24px) + 76px);z-index:39;
  background:rgba(23,19,28,.94);
  backdrop-filter:blur(26px) saturate(1.7);
  -webkit-backdrop-filter:blur(26px) saturate(1.7);
  /* Inset only, no outward drop-shadow: same fix as .nav .wrap above, same reason
     (2026-08-14) -- no clipping ancestor, floats over page content on open. */
  box-shadow:none; /* border pass, 2026-08-31: same multi-line rim as .nav .wrap above */
}
.mobile-menu.open{display:flex}
.mobile-menu a,.mobile-menu button{
  display:flex;align-items:center;gap:10px;
  min-height:44px;padding:.55rem .8rem;border-radius:11px;
  background:none;border:0;cursor:pointer;text-align:start;
  font-family:inherit;font-size:.95rem;font-weight:600;
  color:var(--h-muted);text-decoration:none;
}
.mobile-menu a:hover,.mobile-menu button:hover{background:rgba(255,255,255,.07);color:#fff}
.mobile-menu a.nav-on{color:var(--h-gold)}
.mobile-menu svg{width:18px;height:18px;flex:none}
.mobile-menu .mm-row{display:flex;flex-wrap:wrap;gap:6px;padding:.4rem .3rem}
.mobile-menu .mm-lang{
  /* 44px, matching the .mobile-menu a/button rule above rather than sitting 4px under it in
     the same panel. This one shipped unmeasured for a long time because the pills only exist
     inside .mobile-menu.open: design-proof lists .mm-lang in its tappable selector but never
     clicks the burger, so it could name the element and never reach the state. Measured with
     the menu actually open at 375px: 4 pills at 40px in all four theme/language combinations,
     against 4 sibling controls in the same panel at 44px. Queue 399. */
  min-height:44px;padding:.4rem .8rem;border-radius:99px;
  background:rgba(255,255,255,.06);color:var(--h-muted);
  font-size:.85rem;font-weight:600;border:0;cursor:pointer;
}
.mobile-menu .mm-lang.sel{background:color-mix(in srgb,var(--h-gold) 18%,transparent);color:var(--h-gold)}
/* #mmLangs is the flex ITEM inside .mm-row, so without a display of its own its four buttons
   laid out as blocks and the pills stacked down the sheet in a ragged column instead of
   sitting in a row. A chip row never wraps to a ragged stack. */
/* #mmLangs, not just .mm-langs: index.html sets `#mmLangs{display:contents}` and an ID beats
   any class selector however deeply qualified. Matching its specificity and winning on order
   (this file loads last on every surface) is the same device .nav.nav uses above, and it is
   what makes the component's layout the one that decides rather than the page's. */
.mobile-menu .mm-langs,.mobile-menu #mmLangs{
  display:flex;flex-wrap:nowrap;gap:6px;min-width:0;
  /* Four full language names measure ~410px and the sheet is ~400px at 420px wide, so they
     wrapped and left one pill alone on a second line. A chip row scrolls, it does not wrap.
     Full names stay here on purpose: the bar is the place that had to get shorter, and a
     sheet you opened deliberately is where the language should say what it is. */
  overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.mobile-menu .mm-langs::-webkit-scrollbar,.mobile-menu #mmLangs::-webkit-scrollbar{display:none}
.mobile-menu .mm-lang{flex:none}
.mobile-menu .mm-row{overflow:hidden}
.mobile-menu .mm-theme{color:var(--h-muted)}
.mobile-menu .mm-theme svg{color:var(--h-gold)}

/* --------------------------------------------------- theme, moved out of the bar ---- */
/* Hidden ONLY when header.js has actually placed the footer control (it adds the class),
   so a surface with no <footer> keeps its bar button rather than losing every way to
   switch theme. The button stays in the DOM either way: pages wire their own toggleTheme
   to #themeBtn and removing it would break that binding. */
/* TARGET THE CONTROL, NOT THE CLASS. `.theme-btn` is a SHAPE on the app surfaces, not
   a role: index.html dresses its ACCOUNT button in it (`class="theme-btn" id="acctBtn"`,
   index.html:4940) because it wanted the same 44px glass square. So hiding `.theme-btn`
   took the account icon off the app's bar along with the theme toggle, on every width,
   from the day the toggle moved to the footer. Measured 2026-08-16 at 375/430/768/1024/1280:
   .nav-actions was 70px wide on app.kurdify.app, exactly the language control and nothing
   else, while kurdify.app's own bar kept its account link.
   Every real theme control on all twelve surfaces answers to one of these two: the app
   pages write `id="themeBtn"`, the marketing pages write `data-theme-icon` (and also that
   id). Neither is worn by anything that is not the theme. */
html.hdr-theme-moved .nav .nav-actions #themeBtn,
html.hdr-theme-moved .nav .nav-actions [data-theme-icon]{display:none}

/* ------------------------------------------------ theme control hidden site-wide ----
   ROUND 2026-08-20, ITEM 16. Owner's call: no dark/light switch anywhere, on any surface.

   HIDDEN, NOT REMOVED. Every host page wires its own toggleTheme() to #themeBtn and
   header.js hangs hdrToggleTheme() off the footer and burger copies. Deleting the nodes
   would break those bindings and the stored preference in localStorage
   ('kurdify_theme' on the app surfaces, 'kx_theme' on site/**), which keeps working:
   whatever theme a visitor already chose still applies, there is just no control for it.

   THE CONTROL IS NAMED, NEVER THE SHAPE. `.theme-btn` is a 44px glass square that
   index.html:4940 also puts on its ACCOUNT button; hiding that class swept the account
   icon off the app's bar for weeks. Every real theme control on all twelve surfaces
   answers to one of the four selectors below and nothing else wears them:
     #themeBtn / [data-theme-icon]  the bar button, both hosts
     .hdr-foot-theme-row           the footer row header.js appends
     .mobile-menu .mm-theme        the row inside the burger menu
   The footer ROW is hidden rather than the button, so the flex line it occupies goes
   with it and the footer does not keep an empty 44px band. */
#themeBtn,
[data-theme-icon],
.hdr-foot-theme-row,
.mobile-menu .mm-theme{display:none !important}
.hdr-foot-theme-row{
  display:flex;justify-content:center;width:100%;flex-basis:100%;margin-top:14px;
}
.hdr-foot-theme{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:44px;padding:.5rem 1rem;
  border:0;border-radius:12px;cursor:pointer;
  font-family:inherit;font-size:.85rem;font-weight:700;
  color:var(--muted,#8fb0ad);
  background:
    linear-gradient(180deg,rgba(255,255,255,.09),rgba(255,255,255,.03) 42%,transparent 78%),
    rgba(255,255,255,.04);
  box-shadow:none;
  transition:color .15s,box-shadow .15s;
}
.hdr-foot-theme svg{width:16px;height:16px;flex:none;color:var(--gold,#e0b64a)}
.hdr-foot-theme:hover{color:var(--text,#eaf4f2);box-shadow:none}
.hdr-foot-theme:focus-visible{outline:2px solid var(--gold,#e0b64a);outline-offset:2px}
/* The footer is the PAGE's, not this component's, so it may be light. An ink rim is the
   only edge that shows on a light ground. */
html[data-theme="light"] .hdr-foot-theme{
  background:linear-gradient(180deg,rgba(255,255,255,.9),rgba(255,255,255,.5) 42%,transparent 78%),rgba(255,255,255,.7);
  box-shadow:none;
}
@media (prefers-reduced-motion:reduce){.hdr-foot-theme{transition:none}}

/* ------------------------------------------------- header over the hero ---- */
/* --headover HAS A CSS DEFAULT, and that is the whole point (owner report 2026-08-14: "page
   loads with old style then changes to the new one"). header.js MEASURES this value and writes
   it to documentElement, but it is a deferred script at the end of the body, so for the whole
   of the first paint the variable does not exist and every `var(--headover,0px)` below resolved
   to 0: the hero rendered unraised, the flat slab was visible behind the bar, and the entire
   banner then jumped up ~90px the moment the script ran. A fallback of 0 was chosen when this
   was home-only and read as "degrade to the old layout"; once the lift shipped to all twelve
   marketing heroes it became a full-width flash on every one of them.

   The default is derived, not guessed. --headover is the distance from the bottom of the top
   bar to the bottom of the bar, which is the shell's own margin-top plus the pill's height:
     margin-top   clamp(14px,2vw,22px)   the .nav rule above
     pill height  68px                   .wrap min-height, also above
   Measured against the live page at 1745px: 2vw resolves to 22px, 22 + 68 = 90px, and header.js
   independently measured 90px. They agree, so the first paint is already correct and the script
   has nothing to move. Where a pill wraps to two lines it is taller than its min-height and the
   script still corrects the remainder, which is a settle of a few px rather than a jump.
   Keep these three numbers in step: change the margin or the min-height and change this too. */
:root{--headover:calc(clamp(14px,2vw,22px) + 68px)}
/* Home only: the hero photograph rises behind the bar and the info strip instead
   of them standing on a slab of page ground. --headover is MEASURED by header.js,
   never assumed. The hero rises by exactly that and pads its content down by
   exactly that, so the two cancel and document height does not move. */
.info-strip{position:relative;top:auto;z-index:31;background:transparent;border-bottom:0}
html[data-theme="light"] .info-strip{background:transparent}
.hero.page[data-page="home"]{
  margin-top:calc(-1 * var(--headover,0px));
  padding-top:calc(var(--headover,0px) + clamp(1.5rem,4vw,3rem));
}

/* The same lift for the MARKETING heroes (owner request 2026-08-14: "remove the background,
   put it on hero banner"). site/index.html carried this rule inline, so it was the home page
   alone: everywhere else the hero started at the nav's bottom edge and the strip between the
   top bar and the pill was painted by nothing but `body`, a flat slab the header sat on
   instead of floating over the banner. Measured on /for-users before the change: top bar ends
   at y=38, nav runs 60 to 128, hero began at exactly 128 with margin-top:0, and hit-testing
   beside the pill returned NAV, BODY, HTML with no hero in the stack.

   Base padding is `clamp(2.6rem,7vw,5.5rem)` from site.css:175 and is restated rather than
   guessed, so the rise and the pad-back cancel exactly: the banner grows upward behind the
   bar while the copy inside it and the document height both stay put. Every hero already has
   position:relative and overflow:hidden from that same rule, so a full-bleed .hero-bg child
   fills the taller box and clips to it.

   Home is deliberately untouched: `.hero:has(.cam-hero)` is (0,2,0) and still wins the
   padding-top it was given earlier today, when the ask was the opposite one. */
header.hero{
  margin-top:calc(-1 * var(--headover,0px));
  padding-top:calc(clamp(2.6rem,7vw,5.5rem) + var(--headover,0px));
}

/* -------------------------------------------------------- touch targets ---- */
@media (pointer:coarse){
  .nav .nav-actions .theme-btn,
  .nav .nav-actions .csel-btn,
  .nav .nav-actions .icon-btn,
  .nav .nav-actions .lang-btn,
  .nav .burger{min-width:44px;min-height:44px}
  .topbanner a{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
}

/* ---------------------------------------------------- in-development tag ----
   Appended by markWip() in js/header.js to the six vertical links that are still being built.
   It has to sit on two very different hosts: the desktop dropdown option (.csel-opt, a tight
   text row) and the phone sheet link (a 44px flex row with an icon). It is therefore sized in
   em so it tracks whichever font it lands in, and pushed to the end edge with an auto margin
   that works in both flex and block contexts.

   Deliberately quiet. This marks something as unfinished; it is not a badge to be proud of, and
   at nav scale a saturated plate beside six of the links would read as an error state. */
.hdr-wip{
  margin-inline-start:auto;
  flex:none;
  padding:.1em .42em;
  border-radius:5px;
  font-size:.56rem;
  font-weight:800;
  letter-spacing:.05em;
  line-height:1.6;
  text-transform:uppercase;
  white-space:nowrap;
  color:var(--h-gold,#e0b64a);
  /* BORDERLESS (queue #706, 2026-08-28). This carried `inset 0 0 0 1px` alongside the fill,
     which the house rule names explicitly as a border by another name: it framed a container
     rather than drawing a picture, which is the case the rule is aimed at. Removed, and the
     weight moved off the rim and into the fill exactly as the rule prescribes, 15% -> 26% gold,
     the same substitution and the same step autos.html already uses on .badge.term.
     NOT COVERED BY #507, which was asked and answered on 2026-08-23 and KEPT the 1px ring on
     .nav .wrap, .lang-btn and .icon-btn. That decision turns on the ring being a glass EDGE
     that makes the floating pill read as floating. A chip rim is not that argument, and
     .hdr-wip was never named in it. Asked separately and answered separately. */
  background:color-mix(in srgb,var(--h-gold,#e0b64a) 26%,transparent);
}
/* The dropdown option is not a flex container, so the auto margin has nothing to push against
   and the tag would sit hard against the label. */
.nav .csel-opt{display:flex;align-items:center;gap:10px}
/* RTL: the tag follows the start/end logic above on its own, but an uppercase Latin-free label
   still needs its own direction or the bracketed Arabic renders reversed inside a mixed row. */
[dir="rtl"] .hdr-wip{direction:rtl}

/* ---------------------------------------------- marketing nav: the More control ----
   The bar is committed DARK in both themes (html[data-theme="light"] .nav .wrap is
   rgba(23,19,28,.90) above), so anything inside it must take its colour from this
   component's own tokens and not from the page's. The twelve marketing pages write this
   control as .more-btn, which header.css never claimed, so it kept site.css's
   `color:var(--muted)` and in light theme that resolves to #556f6a: a dark grey label on a
   near-black bar, measured at 2.49-2.60:1 on every marketing page (queue 380, finding 1).

   --h-muted is cream and documented at 8.7:1 on the header floor, which is the same value
   the app's own .csel-btn already uses. Claiming the second class name here is the same
   move the cluster already makes for .icon-btn / .lang-btn: one component, two vocabularies,
   never a duplicated block that can drift. */
.nav .more-btn{color:var(--h-muted)}
.nav .more-btn:hover,
.nav .more-btn[aria-expanded="true"]{color:#fff}

/* ===== language control, brought into the cluster's own rhythm (owner, 2026-08-23) ======
   "Make the language switcher more matching the rest of the header element design."

   Measured before changing anything, on both hosts: the language control and its icon-tile
   siblings already share the same glass, the same 12px radius, the same 44px height and the
   same rim. The mismatch is not the surface, it is everything sitting ON the surface. The
   siblings are 44px squares carrying one saturated glyph; the language control is an 89-96px
   pill carrying three things at three different weights (a full-strength globe, a label set
   one step off the nav's own type, and a chevron), so it reads as a different KIND of control
   parked beside two buttons rather than as the third member of the set.

   Three changes, all toward "same set", none of them touching the glass:
     - the leading glyph drops to the header's muted ink, so the only saturated mark in the
       cluster stays the one that is meant to be an identity mark;
     - the label takes the nav's own size and tracking instead of its own;
     - the pill tightens toward the 44px module, which is what makes a row of controls read as
       a row rather than as one wide thing and two small things.
   Shared file: this is the one source of truth for the bar on all twelve surfaces, so both
   spellings of the control (.lang-btn on the marketing pages, .csel-btn in the app) are named
   together rather than fixed on whichever host was screenshotted. */
.nav .nav-actions .lang-btn,
.nav .nav-actions .csel-btn{
  padding-inline:12px;gap:7px;font-size:.8rem;letter-spacing:.01em;font-weight:700;
}
/* The globe is context, not the subject. It sits at the same ink as the chevron already does,
   which is what stops the control competing with the theme mark next to it. */
.nav .nav-actions .lang-btn > svg,
.nav .nav-actions .csel-btn > svg:not(.cs-chev){
  width:16px;height:16px;flex:none;color:var(--h-muted);
}
.nav .nav-actions .lang-btn:hover > svg,
.nav .nav-actions .csel-btn:hover > svg:not(.cs-chev){color:var(--h-text)}
.nav .nav-actions .cs-chev{width:12px;height:12px}
/* The label is the payload, so it keeps full ink while the two glyphs around it recede. */
.nav .nav-actions .lang-btn #langLabel,
.nav .nav-actions .csel-btn > span{color:var(--h-text)}
