
:root {
  /* Warm neutrals — the approved hybrid direction: paper, not pure white or
     grey. No green anywhere in this file — that is a locked product decision,
     not a stylistic default, so do not "improve" it back toward teal.
     --bg is LOCKED to Direction 1's exact background token — do not drift it
     (it was previously #F7F2EA by a one-digit rounding error; restored here). */
  --bg:#F7F2E9; --surface:#FFFDF9; --surface-alt:#FBF5EA; --surface-2:#EFE5D2;
  --ink:#221D18; --ink-soft:#75695A; --ink-faint:#9C907E;
  --border:#E7DCC8; --border-strong:#D9CCB4;
  --paper:#FFFDF9; /* alias kept for the handful of rules below still named --paper */

  /* Fresh coral / orange-red accent (2026-08-18 correction) — the identity is
     NOT brown-dominant: --accent is a vivid coral-red for CTAs/active states/
     links (5.2:1 on white, 4.7:1 on --bg), --accent-2 a deeper emphasis tone
     for data that needs to stand out in running text (salary figures), and
     --accent-3 a lighter restrained orange reserved for large-surface/icon
     use only (it does not meet AA for small text and must never carry it). */
  --accent:#C63920; --accent-hover:#A82E19; --accent-2:#A82E19; --accent-3:#E0763A;
  --accent-soft:#F5DCD2;
  --accent-solid:#C63920; --accent-solid-hover:#A82E19;

  /* Trust — deliberately NOT green (locked decision). verified/known reuse the
     accent-2 emphasis tone as a *signal*, not a decoration; needs_review
     stays amber/ochre; risk/blocked stay a red distinct enough from the
     coral CTA color that a fraud warning can never read as a normal
     call-to-action. */
  --verified:#A82E19; --verified-bg:transparent;
  --known:#A82E19;    --known-bg:transparent;
  --good:#9C907E;     --good-bg:transparent;
  --review:#8A6212;   --review-bg:#FBF1DC;
  --risk:#A3341F;     --risk-bg:#FBE9E5;
  --blocked:#8A2418;  --blocked-bg:#FBE9E5;

  --ok:#A82E19; --warn:#8A6212; --danger:#A3341F;

  /* Six warm avatar tones spanning coral-red / orange / amber-gold / rose-coral
     rather than a single hue repeated at different darknesses — this is what
     reads as "fresh variety" instead of "brown-heavy" across a list of
     companies. Each clears 4.5:1 under its own white initials. */
  --avatar-1:#C63920; --avatar-2:#B85819; --avatar-3:#C13B4A;
  --avatar-4:#B9502F; --avatar-5:#A8671E; --avatar-6:#B85818;

  --radius-sm:8px; --radius:10px; --radius-lg:14px;
  --shadow-sm:0 1px 2px rgba(34,29,24,.05);
  --shadow:0 4px 14px rgba(34,29,24,.08);

  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px;
  --space-5:24px; --space-6:32px; --space-7:48px; --space-8:64px;

  /* Typography is LOCKED to the approved Direction-1 pairing: Markazi Text
     for a handful of display moments (see .display below), IBM Plex Sans
     Arabic for everything else. Do not substitute another family. */
  --font-display: "Markazi Text", "IBM Plex Sans Arabic", "Segoe UI", Tahoma, sans-serif;
  --font-ar: "IBM Plex Sans Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma,
             "Geeza Pro", "Arabic Typesetting", system-ui, sans-serif;
  --font-num: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  --maxw:1140px;
  --header-h:60px;
  --tabbar-h:64px;

  /* --------------------------------------------------------------------
     Compatibility scale. Most of this file (buttons, forms, tables, cards,
     pagination, footer…) is not being rewritten rule-by-rule in this pass —
     only the tokens and the job-row/chip/badge/hero rules are, per the
     approved direction. Re-pointing the OLD ink/accent scale names at the
     NEW warm palette keeps every untouched selector correct for free,
     instead of requiring a line-by-line rewrite of the whole stylesheet.
     Do not add new rules against this compatibility scale — use the
     semantic names above (--bg, --surface, --ink, --ink-soft, --border,
     --accent, --accent-2, --accent-3) instead.
     -------------------------------------------------------------------- */
  --ink-900:#221D18; --ink-800:#2E2721; --ink-700:#3D342A; --ink-600:#544736;
  --ink-500:#75695A; --ink-400:#8F836F; --ink-300:#B3A88F; --ink-200:#E3D8C2;
  --ink-100:#F1E9DA; --ink-50:#F7F2E9;
  --accent-700:#A82E19; --accent-600:#C63920; --accent-500:#C63920; --accent-100:#F5DCD2;
}

@font-face{font-family:"Markazi Text";font-weight:500;font-style:normal;font-display:swap;src:url("/assets/fonts/markazi-text-500.woff2") format("woff2")}
@font-face{font-family:"Markazi Text";font-weight:700;font-style:normal;font-display:swap;src:url("/assets/fonts/markazi-text-700.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Sans Arabic";font-weight:400;font-style:normal;font-display:swap;src:url("/assets/fonts/ibm-plex-sans-arabic-400.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Sans Arabic";font-weight:600;font-style:normal;font-display:swap;src:url("/assets/fonts/ibm-plex-sans-arabic-600.woff2") format("woff2")}

/*
 * Dark mode is scoped to body.is-admin ONLY (2026-08-18 correction, §17/§18).
 *
 * This used to be a bare ':root' rule inside this same media query, which
 * silently reskinned the ENTIRE site — public pages included — to a
 * near-black theme for any visitor whose OS/browser preferred dark. That is
 * the confirmed, reproduced root cause of "the iPhone still shows the old
 * rejected dark design while desktop shows the new one": it was never a
 * caching problem (verified: CSS/font routes are versioned + immutable, and
 * asset content matched on both). It was this rule, live, firing correctly
 * on every request from a device in Dark Mode — since most phones default to
 * or commonly use system Dark Mode and most desktop test browsers do not,
 * the two devices were simply hitting two different, both-correct-at-the-
 * time branches of the same stylesheet. Reproduced directly against the
 * deployed preview with 'prefers-color-scheme: dark' forced: --bg resolved
 * to #18130F instead of the approved #F7F2E9.
 *
 * The public job-seeker product must always render the approved warm/light
 * identity regardless of OS theme. Admin/operations pages may still opt in
 * to a dark variant — adminPage() in routes/admin.ts sets bodyClass:
 * 'is-admin' on the Layout for exactly this purpose — but nothing here can
 * reach a public page, because public routes never set that class.
 */
@media (prefers-color-scheme: dark) {
  body.is-admin {
    --bg:#18130F; --surface:#221C16; --surface-alt:#2A231C; --surface-2:#332A20;
    --ink:#F3EBDF; --ink-soft:#B6A995; --ink-faint:#8A7E6C;
    --border:#3A3125; --border-strong:#4A3F30;
    --paper:#221C16;

    --accent:#E08055; --accent-hover:#EE9269; --accent-2:#D89A6E; --accent-3:#D9AE66;
    --accent-soft:#3A2A20;
    --accent-solid:#C1502E; --accent-solid-hover:#A5431F;

    --verified:#D89A6E; --verified-bg:transparent;
    --known:#D89A6E;    --known-bg:transparent;
    --good:#8A7E6C;     --good-bg:transparent;
    --review:#DCB156;   --review-bg:#31280F;
    --risk:#E88A76;     --risk-bg:#331A15;
    --blocked:#F0A091;  --blocked-bg:#3A1A14;
    --shadow-sm:0 1px 2px rgba(0,0,0,.4);
    --shadow:0 4px 14px rgba(0,0,0,.35);

    /* Compatibility scale, dark mode — see the light-mode block for why this exists. */
    --ink-900:#F3EBDF; --ink-800:#E4D9C8; --ink-700:#CBBDA6; --ink-600:#AA9B82;
    --ink-500:#B6A995; --ink-400:#8A7E6C; --ink-300:#4A3F30; --ink-200:#3A3125;
    --ink-100:#2A231C; --ink-50:#18130F;
    --accent-700:#D89A6E; --accent-600:#E08055; --accent-500:#E08055; --accent-100:#3A2A20;
  }
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--ink-50); color:var(--ink-800);
  font-family:var(--font-ar); font-size:16px; line-height:1.7;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{margin:0 0 var(--space-3); line-height:1.35; color:var(--ink-900); font-weight:700}
h1{font-size:clamp(1.5rem,1.2rem + 1.4vw,2.1rem)}
h2{font-size:clamp(1.25rem,1.1rem + .8vw,1.6rem)}
h3{font-size:1.1rem}
p{margin:0 0 var(--space-3)}
a{color:var(--accent-600); text-decoration:none}
a:hover{text-decoration:underline}
ul,ol{margin:0 0 var(--space-3); padding-inline-start:1.35em}
img{max-width:100%; height:auto}
hr{border:0; border-top:1px solid var(--ink-200); margin:var(--space-5) 0}

/* Latin runs inside Arabic text must render LTR and in a Latin face. */
[dir="ltr"]{direction:ltr; unicode-bidi:isolate; text-align:start}
.ltr,.num,code,kbd,samp{direction:ltr; unicode-bidi:isolate; font-family:var(--font-num)}
.num{font-variant-numeric:tabular-nums}

:focus-visible{outline:3px solid var(--accent-500); outline-offset:2px; border-radius:4px}
:focus:not(:focus-visible){outline:none}

.skip-link{
  position:absolute; inset-inline-start:-9999px; top:0; z-index:100;
  background:var(--accent-solid); color:#fff; padding:var(--space-3) var(--space-4);
}
.skip-link:focus{inset-inline-start:0}

.wrap{max-width:var(--maxw); margin-inline:auto; padding-inline:var(--space-4)}
.stack>*+*{margin-block-start:var(--space-4)}
.row{display:flex; gap:var(--space-3); align-items:center; flex-wrap:wrap}
.spread{display:flex; justify-content:space-between; align-items:center; gap:var(--space-3); flex-wrap:wrap}
.muted{color:var(--ink-500); font-size:.9rem}
.tiny{font-size:.8rem}
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ---------- header ---------- */
.site-header{
  position:sticky; top:0; z-index:50; background:var(--paper);
  border-block-end:1px solid var(--ink-200);
}
.site-header .bar{display:flex; align-items:center; gap:var(--space-4); height:var(--header-h)}
/* Brand mark (2026-08-26): the approved Arabic wordmark SVG, inlined
   directly (views/brand-assets.ts) — never the old letter-badge + text
   pairing. The SVG ships with no width/height attribute (viewBox only), so
   it needs an explicit height here with width:auto to size correctly
   instead of falling back to the browser's 300x150 replaced-element
   default (confirmed while validating the asset: without this rule the
   wordmark silently renders at zero visible size in a flex context). */
.brand{display:flex; align-items:center}
.brand:hover{text-decoration:none}
.brand svg{height:28px; width:auto; display:block}
.footer-brand{display:inline-block; margin-block-end:var(--space-3)}
.footer-brand svg{height:22px; width:auto; display:block}
.site-nav{display:flex; gap:var(--space-4); margin-inline-start:auto; align-items:center; flex-wrap:wrap}
.site-nav a{color:var(--ink-600); font-size:.94rem; font-weight:600}
.site-nav a[aria-current="page"]{color:var(--accent-600)}
/* Below 768px (the exact breakpoint .tabbar appears at — see further down),
   the top nav is redundant with the bottom tabbar and, worse, actively
   dangerous: .bar has a fixed height (--header-h) but .site-nav can
   wrap onto a second line at narrow widths (five links + a button do not
   fit in 320-375px), and a fixed-height flex container does not clip
   overflow — the wrapped second line (confirmed: the "إنشاء حساب" button)
   visually spills out UNDER the sticky header and sits on top of whatever
   content starts right below it (confirmed: the homepage h1). Hiding the
   redundant nav here is both the fix and the correct mobile design — the
   header stays compact/calm per the approved direction, and every
   destination in it is already reachable from the tabbar (home/jobs/
   saved/account) or the footer (companies/trust). */
@media (max-width:767px){
  .site-nav{display:none}
}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--space-2);
  padding:10px 18px; border-radius:var(--radius); border:1px solid transparent;
  font:inherit; font-weight:600; font-size:.94rem; cursor:pointer;
  background:var(--ink-100); color:var(--ink-800); min-height:44px;
  transition:background .12s ease, border-color .12s ease;
}
.btn:hover{text-decoration:none; background:var(--ink-200)}
.btn-primary{background:var(--accent-solid); color:#fff}
.btn-primary:hover{background:var(--accent-solid-hover)}
.btn-outline{background:transparent; border-color:var(--ink-300); color:var(--ink-700)}
.btn-outline:hover{background:var(--ink-100)}
.btn-danger{background:var(--risk-bg); color:var(--risk); border-color:var(--risk)}
.btn-sm{padding:6px 12px; min-height:36px; font-size:.85rem}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.5; cursor:not-allowed}

.qr-code{width:220px; max-width:100%; background:#fff; padding:var(--space-3); border-radius:var(--radius)}
.qr-code svg{width:100%; height:auto; display:block}

/* ---------- forms ---------- */
label{display:block; font-weight:600; font-size:.9rem; margin-block-end:var(--space-1); color:var(--ink-700)}
input[type=text],input[type=email],input[type=password],input[type=search],
input[type=number],input[type=url],input[type=tel],select,textarea{
  width:100%; padding:10px 12px; min-height:44px;
  border:1px solid var(--ink-300); border-radius:var(--radius);
  background:var(--paper); color:var(--ink-900); font:inherit;
}
textarea{min-height:120px; resize:vertical; line-height:1.7}
input:focus,select:focus,textarea:focus{border-color:var(--accent-500)}
input[aria-invalid="true"],select[aria-invalid="true"],textarea[aria-invalid="true"]{border-color:var(--danger)}
.field{margin-block-end:var(--space-4)}
.field .hint{font-size:.82rem; color:var(--ink-500); margin-block-start:var(--space-1)}
.field .err{font-size:.85rem; color:var(--danger); margin-block-start:var(--space-1); font-weight:600}
fieldset{border:1px solid var(--ink-200); border-radius:var(--radius); padding:var(--space-4); margin:0 0 var(--space-4)}
legend{font-weight:700; padding-inline:var(--space-2)}
.check{display:flex; align-items:center; gap:var(--space-2); font-weight:500; min-height:36px}
.check input{width:18px; height:18px; min-height:auto; flex:0 0 auto}

/* ---------- cards ---------- */
.card{
  background:var(--paper); border:1px solid var(--ink-200);
  border-radius:var(--radius-lg); padding:var(--space-5); box-shadow:var(--shadow-sm);
}
.card-tight{padding:var(--space-4)}

/* ---------- job row ----------
   Restrained by design: a hairline-divided list, not a stack of shadowed
   cards. Visual life comes from the company-identity avatar and content
   density, not from container chrome (approved hybrid direction §1/§6). */
.job-list{display:flex; flex-direction:column}
.job-card{
  position:relative; display:flex; gap:var(--space-3); align-items:flex-start;
  padding:var(--space-3) var(--space-2); border-block-end:1px solid var(--border);
  background:transparent; border-radius:0; box-shadow:none; border-inline:0; border-block-start:0;
  transition:background .12s ease;
}
.job-list>.job-card:nth-child(even){background:var(--surface-alt)}
.job-card:hover{background:var(--surface-alt)}
.job-card.is-expired{opacity:.7}
.job-card .avatar{
  flex:none; width:44px; height:44px; border-radius:var(--radius-sm);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-ar); font-weight:600; font-size:.85rem; color:#fff;
}
.job-card .body{flex:1; min-width:0}
.job-card h3{margin:0; font-size:.98rem; font-weight:600}
.job-card h3 a{color:var(--ink-900)}
/* The whole row is one tap target; the visible title link stays the only
   thing that looks interactive, but the invisible overlay makes the entire
   row respond, which is what a dense mobile feed needs (approved direction §6). */
.job-card h3 a::after{content:""; position:absolute; inset:0}
.job-card .meta{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px;
  color:var(--ink-500); font-size:.83rem; margin-block-start:4px;
}
.job-card .meta .sep{color:var(--ink-300)}
.job-card .meta svg{flex:none; opacity:.7; position:relative; z-index:1}
.job-card .salary{color:var(--accent-2); font-weight:600}
/* Kept visible and functional (unlike the row's tap-to-open affordance,
   Apply is a distinct action — hiding it would remove the only way to apply
   straight from a dense list without opening the detail page first). Sized
   down and pushed to the row's own rhythm rather than a separate bordered
   footer, so it does not read as a second card stacked under the first. */
.job-card .foot{
  display:flex; align-items:center; gap:8px; margin-block-start:8px; position:relative; z-index:1;
}

/* ---------- trust signal ----------
   Icon + text inline in the metadata line, never a filled pill on every row —
   trust stays subtle evidence, not marketing decoration (approved direction §12). */
.trust-signal{display:inline-flex; align-items:center; gap:4px; font-weight:600; position:relative; z-index:1}
.trust-signal svg{flex:none}
.trust-signal.is-verified{color:var(--verified)}
.trust-signal.is-review{color:var(--review)}
.trust-signal.is-risk{color:var(--risk)}
.trust-signal.is-neutral{color:var(--ink-400)}
.trust-signal a{color:inherit}

/* ---------- company avatar ----------
   Deterministic initials fallback (approved direction §5) — the only
   identity signal today, since the companies table has no logo_url column.
   Six explicit color classes, not an inline style attribute: the CSP's
   style-src has a nonce but no unsafe-inline, so inline styles would
   silently fail to paint. */
.avatar{background:var(--accent-2)}
.avatar-1{background:var(--avatar-1)}
.avatar-2{background:var(--avatar-2)}
.avatar-3{background:var(--avatar-3)}
.avatar-4{background:var(--avatar-4)}
.avatar-5{background:var(--avatar-5)}
.avatar-6{background:var(--avatar-6)}

/* ---------- badges (admin use only now — see note) ----------
   The public site no longer renders this component: jobCard()/trustBadge()
   emit .trust-signal instead (subtle, per §12). This filled-capsule style
   stays exactly as structured before, only recolored away from green/teal,
   because admin's ops tables depend on its density and this pass does not
   redesign admin (per the approved boundaries) — a safe compatibility
   retint, not a structural change. */
.badge{
  display:inline-flex; align-items:center; gap:5px; padding:3px 10px;
  border-radius:999px; font-size:.78rem; font-weight:700; white-space:nowrap;
  border:1px solid transparent;
}
.badge-verified{background:var(--accent-soft); color:var(--verified); border-color:var(--verified)}
.badge-known{background:var(--accent-soft); color:var(--known); border-color:var(--known)}
.badge-good{background:var(--surface-2); color:var(--good); border-color:var(--ink-300)}
.badge-review{background:var(--review-bg); color:var(--review); border-color:var(--review)}
.badge-risk{background:var(--risk-bg); color:var(--risk); border-color:var(--risk)}
.badge-blocked{background:var(--risk-bg); color:var(--blocked); border-color:var(--blocked)}
.badge-neutral{background:var(--ink-100); color:var(--ink-600)}

/* ---------- notices ---------- */
.notice{
  border-radius:var(--radius); padding:var(--space-3) var(--space-4);
  border:1px solid var(--ink-200); background:var(--ink-100); font-size:.92rem;
}
.notice-warn{background:var(--review-bg); border-color:var(--review); color:var(--review)}
.notice-danger{background:var(--risk-bg); border-color:var(--risk); color:var(--risk)}
.notice-ok{background:var(--accent-soft); border-color:var(--verified); color:var(--verified)}
.notice strong{font-weight:800}

/* ---------- layout ---------- */
.split{display:grid; grid-template-columns:1fr; gap:var(--space-5)}
@media (min-width:920px){ .split{grid-template-columns:280px 1fr} }
/* Above-the-fold height is a deliberate budget (2026-08-19 correction §1):
   the job feed must start early on a real phone. Tightened block padding
   and inter-element gaps here and on .searchbar/.chips below — never by
   shrinking type size or touch targets. */
.hero{
  background:var(--bg); border-block-end:0;
  padding-block:var(--space-5) var(--space-4);
}
.hero h1{max-width:20ch; margin-block-end:var(--space-1)}
.hero p.lead{font-size:1rem; color:var(--ink-soft); max-width:56ch; margin-block-end:0}

/* .display — the ONLY place Markazi Text appears: homepage headline, homepage
   section headings, and the /trust intro. Everything else stays IBM Plex Sans
   Arabic (approved direction §3 — typography is locked, use selectively). */
.display{font-family:var(--font-display); font-weight:700; line-height:1.28}

.searchbar{display:flex; gap:var(--space-2); flex-wrap:wrap; margin-block-start:var(--space-4)}
.searchbar .btn{flex:0 0 auto}
.searchbar-field{
  flex:1 1 260px; display:flex; align-items:center; gap:8px;
  border:1px solid var(--border); border-radius:var(--radius); background:var(--surface);
  padding-inline:12px;
}
.searchbar-field svg{flex:none; color:var(--ink-faint)}
.searchbar-field input{border:0; padding-inline-start:0; background:transparent}
.searchbar-field input:focus{outline:none}
.searchbar select{flex:0 1 180px}

/* ---------- discovery chips ----------
   Text-forward, small radius — a light touch control, not a capsule feature
   in its own right (approved direction §10: "help reach jobs faster, not
   become a visual feature by itself"). */
.chips{display:flex; gap:var(--space-2); flex-wrap:wrap}
.chip{
  display:inline-flex; align-items:center; gap:6px; padding:6px 12px;
  border-radius:var(--radius-sm); border:1px solid var(--border); background:var(--surface);
  color:var(--ink-soft); font-size:.85rem; font-weight:600; min-height:36px;
}
.chip:hover{text-decoration:none; border-color:var(--accent); color:var(--accent)}
.chip[aria-pressed="true"]{background:var(--accent-soft); border-color:var(--accent); color:var(--accent-2)}

/* ---------- tables (admin) ---------- */
.table-wrap{overflow-x:auto; border:1px solid var(--ink-200); border-radius:var(--radius); background:var(--paper)}
table{width:100%; border-collapse:collapse; font-size:.9rem; min-width:640px}
th,td{padding:10px 12px; text-align:start; border-block-end:1px solid var(--ink-100); vertical-align:top}
th{background:var(--ink-50); font-weight:700; color:var(--ink-700); white-space:nowrap}
tbody tr:hover{background:var(--ink-50)}

.kpi-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:var(--space-3)}
.kpi{background:var(--paper); border:1px solid var(--ink-200); border-radius:var(--radius); padding:var(--space-4)}
.kpi .v{font-size:1.7rem; font-weight:800; color:var(--ink-900); font-variant-numeric:tabular-nums}
.kpi .k{font-size:.82rem; color:var(--ink-500); font-weight:600}

.pill-nav{display:flex; gap:var(--space-2); flex-wrap:wrap; margin-block-end:var(--space-4)}
.pill-nav a{
  padding:7px 14px; border-radius:var(--radius-sm); background:var(--surface);
  border:1px solid var(--border); color:var(--ink-soft); font-size:.88rem; font-weight:600;
}
.pill-nav a[aria-current="page"]{background:var(--accent-solid); border-color:var(--accent-solid); color:#fff}
.pill-nav a:hover{text-decoration:none}

/* ---------- pagination ---------- */
.pagination{display:flex; gap:var(--space-2); align-items:center; justify-content:center; margin-block-start:var(--space-6)}
.pagination a,.pagination span{
  padding:8px 14px; border-radius:var(--radius); border:1px solid var(--ink-200);
  background:var(--paper); color:var(--ink-700); font-size:.9rem; min-height:40px;
  display:inline-flex; align-items:center;
}
.pagination [aria-current="page"]{background:var(--accent-solid); color:#fff; border-color:var(--accent-solid)}
/* Chevrons must mirror in RTL. */
.pagination .prev::before{content:"›"; margin-inline-end:6px}
.pagination .next::after{content:"‹"; margin-inline-start:6px}

/* ---------- empty state ---------- */
/* Compact inline state — the giant dashed empty-card hero is a rejected
   pattern (2026-08-19 correction). This is one line of text, RTL start-
   aligned like any other paragraph, no card/border/oversized padding — it
   must never compete visually with a real job feed. */
.empty{
  text-align:start; color:var(--ink-soft); font-size:.92rem;
  padding-block:var(--space-2); margin:0; max-width:60ch;
}
.empty strong{color:var(--ink-900)}
.empty a{margin-inline-start:4px; font-weight:600}

/* ---------- homepage trust footnote ----------
   Was a full .card with a heading, four bullets and a button, sitting
   directly under the job feed as a second visual hero (2026-08-19
   correction §4). Trust stays present but quiet: one line, a hairline
   divider, no card — the dedicated /trust page carries the full
   explanation instead. */
.trust-footnote{
  color:var(--ink-soft); font-size:.86rem; margin:0;
  padding-block-start:var(--space-3); border-block-start:1px solid var(--border);
}
.trust-footnote strong{color:var(--ink-900); font-weight:600}
.trust-footnote a{margin-inline-start:4px; font-weight:600}

/* ---------- trust explanation ---------- */
.trust-panel{border-inline-start:4px solid var(--ink-300); padding-inline-start:var(--space-4)}
.trust-panel.band-verified_official,.trust-panel.band-known_source{border-color:var(--verified)}
.trust-panel.band-good{border-color:var(--good)}
.trust-panel.band-needs_review{border-color:var(--review)}
.trust-panel.band-high_risk,.trust-panel.band-blocked{border-color:var(--risk)}
.trust-reasons{list-style:none; padding:0; margin:var(--space-2) 0 0}
.trust-reasons li{
  padding:var(--space-2) 0; border-block-end:1px solid var(--ink-100);
  font-size:.9rem; color:var(--ink-600);
}
.trust-reasons li:last-child{border:0}

/* ---------- footer ---------- */
.site-footer{
  margin-block-start:var(--space-7); padding-block:var(--space-5);
  background:var(--paper); border-block-start:1px solid var(--ink-200); color:var(--ink-500);
  font-size:.88rem;
}
.site-footer .brand-blurb{margin:0 0 var(--space-4); max-width:60ch}
.site-footer ul{list-style:none; padding:0; margin:0}
.site-footer li{margin-block-end:6px}
.site-footer a{color:var(--ink-600)}

/* Footer link groups (2026-08-19 fix — Safari regression): rendered TWICE by
   layout.tsx (footerGroupsMobile/footerGroupsDesktop) from one shared data
   list, not once with CSS trying to force a single details tree open on
   desktop. That single-tree approach used the ::details-content pseudo to
   override the closed state at >=768px — real iOS Safari showed every
   group expanded at once instead, because that pseudo-element's cross-
   engine behaviour cannot be relied on. Two plain, unconditional render
   paths remove the risk entirely: .footer-cols-mobile uses <details> with
   nothing but its native default (closed unless the user taps — no CSS
   involved in that state at all), .footer-cols-desktop is never a
   <details> in the first place. Only one of the two is ever visible, by
   ordinary display:none — no experimental CSS, no forced-open trick. */
.footer-cols-desktop{display:none}

.footer-group summary{
  cursor:pointer; display:flex; align-items:center; justify-content:space-between; gap:var(--space-2);
  font-size:.9rem; font-weight:700; color:var(--ink-700); padding-block:12px; min-height:24px;
}
/* Marker suppression is layered because no single rule covers every engine:
   Chromium honours ::-webkit-details-marker, Safari/Firefox use ::marker on
   the (UA display:list-item) summary, and list-style alone catches
   whatever still renders as a list bullet after both pseudo-elements are
   nulled. Without all three, a native disclosure triangle or bullet can
   still render alongside the custom chevron below. */
.footer-group summary{list-style:none}
.footer-group summary::-webkit-details-marker{display:none}
.footer-group summary::marker{content:""}
/* Custom chevron: a plain two-border-side square rotated 45°, not text
   glyphs (a literal "+"/"−" character read as a stray dash in Safari's
   default summary font metrics) and not an emoji. Physical (not logical)
   border sides on purpose: "points down = more content below" is a
   direction-neutral convention, identical in meaning whether the text
   beside it is RTL or LTR, so this deliberately does not mirror with
   inline-end/start — down-then-up reads correctly in both. */
.footer-group summary::after{
  content:""; flex:none; width:7px; height:7px;
  border-right:1.6px solid var(--ink-400); border-bottom:1.6px solid var(--ink-400);
  transform:rotate(45deg); transition:transform .15s ease;
}
.footer-group[open] summary::after{transform:rotate(225deg)}
.footer-group ul{padding-block-end:var(--space-2)}

@media (max-width:767px){
  .footer-cols-mobile{display:block}
  .footer-group{border-block-end:1px solid var(--ink-100)}
  .footer-group:first-child{border-block-start:1px solid var(--ink-100)}
}

@media (min-width:768px){
  .footer-cols-mobile{display:none}
  .footer-cols-desktop{display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:var(--space-5)}
  .footer-cols-desktop h4{font-size:.9rem; color:var(--ink-700); margin:0 0 var(--space-2)}
}

/* ---------- utilities ----------
   These exist so no markup needs an inline style attribute. A CSP that carries
   a nonce on style-src does NOT cover inline style attributes, so allowing them
   would require unsafe-inline, weakening the policy for the sake of a few
   margins. Utility classes keep the policy strict instead. */
.mt-1{margin-block-start:var(--space-1)}
.mt-2{margin-block-start:var(--space-2)}
.mt-3{margin-block-start:var(--space-3)}
.mt-4{margin-block-start:var(--space-4)}
.mt-5{margin-block-start:var(--space-5)}
.mt-6{margin-block-start:var(--space-6)}
.mt-7{margin-block-start:var(--space-7)}
.mt-pull{margin-block-start:-8px}
.mb-1{margin-block-end:var(--space-1)}
.mb-3{margin-block-end:var(--space-3)}
.mb-4{margin-block-end:var(--space-4)}
.mb-6{margin-block-end:var(--space-6)}
.mb-7{margin-block-end:var(--space-7)}
.m-0{margin:0}
.py-5{padding-block:var(--space-5)}
.py-6{padding-block:var(--space-6)}
.py-7{padding-block:var(--space-7)}
.py-8{padding-block:var(--space-8)}
.w-full{width:100%}
.flex-1{flex:1}
.flex-grow-sm{flex:1 1 160px}
.flex-grow-md{flex:1 1 200px}
.flex-grow-lg{flex:1 1 220px}
.flex-fixed-md{flex:0 0 200px}
.text-center{text-align:center}
.mis-auto{margin-inline-start:auto}
.d-block{display:block}
.d-inline{display:inline}
.order-1{order:1}
.order-2{order:2}
.fw-600{font-weight:600}
.fs-lead{font-size:1.05rem}
.break-all{word-break:break-all}
.pre-wrap{white-space:pre-wrap}
.narrow-sm{max-width:460px}
.narrow{max-width:720px}
.narrow-md{max-width:800px}
.w-110{width:110px}
.w-130{width:130px}
.w-170{width:170px}
.w-200{width:200px}
.detail-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--space-3); margin-block:var(--space-4);
}
.detail-grid-lg{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--space-3); margin-block:var(--space-5);
}
.code-block{
  white-space:pre-wrap; background:var(--ink-50); padding:var(--space-3);
  border-radius:var(--radius-sm); overflow:auto;
}
.code-block-tall{max-height:320px}
.list-row{border-block-end:1px solid var(--ink-100); padding-block:var(--space-3)}
.list-row-sm{border-block-end:1px solid var(--ink-100); padding-block:10px}

/* ---------- mobile bottom nav ----------
   Approved direction §11: mature and restrained, simple icons, one active
   state, no colorful filled circles. Supports the four repeated actions
   only — nothing else lives here. */
.tabbar{
  display:none; position:fixed; inset-inline:0; bottom:0; z-index:50;
  background:var(--surface); border-block-start:1px solid var(--border);
  padding-block:8px calc(8px + env(safe-area-inset-bottom));
}
@media (max-width:767px){
  .tabbar{display:flex; justify-content:space-around}
  body{padding-block-end:var(--tabbar-h)}
}
.tabbar .tab{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  color:var(--ink-soft); font-size:.68rem; font-weight:600; min-width:56px; min-height:44px;
  padding-block:2px;
}
.tabbar .tab:hover{text-decoration:none}
.tabbar .tab[aria-current="page"]{color:var(--accent)}

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

@media print{
  .site-header,.site-footer,.btn,.pagination,.tabbar{display:none}
  body{background:#fff; padding-block-end:0}
}
