:root{
  /* ---- palette: aliases into world.css ------------------------------------
     world.css is the single source of truth for colour values. base.css keeps
     its own variable names so ~2,500 lines of var(--old) references work as-is.
     Contrast is documented and verified in world.css. */
  --bg:var(--page); --bg2:var(--surface); --card:var(--surface); --card2:var(--page);
  --line:var(--rule); --txt:var(--ink); --mut:var(--ink-soft);
  --acc:var(--teal); --acc2:var(--coral); --acc-ink:#fff;
  --acc-rgb:var(--teal-rgb); --acc2-rgb:var(--coral-rgb);
  --glow:rgba(var(--teal-rgb),.18); --warn:var(--coral); --warn-rgb:var(--coral-rgb);
  --mono:"JetBrains Mono",monospace;
  --ease:cubic-bezier(.2,.7,.2,1);
  --ico-arrow:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7"/><path d="M8 7h9v9"/></svg>');
  --ico-chevron:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 6 6 6-6 6"/></svg>');

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:64px; --s9:96px;
  --r-xs:8px; --r-sm:12px; --r:16px; --r-lg:24px; --r-pill:999px;
  --sh-1:0 1px 2px rgba(var(--shadow-rgb),.12);
  --sh-2:0 8px 24px rgba(var(--shadow-rgb),.10);
  --sh-3:0 20px 60px rgba(var(--shadow-rgb),.14);
  --z-base:1; --z-raised:10; --z-nav:50; --z-fab:60; --z-modal:100;
}

/* Qomraa Arabic — the brand face, self-hosted so it never depends on a CDN */
@font-face{font-family:"Qomraa";src:url("../fonts/itfQomraArabic-Light.woff2") format("woff2");
  font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:"Qomraa";src:url("../fonts/itfQomraArabic-Regular.woff2") format("woff2");
  font-weight:400 500;font-style:normal;font-display:swap}
@font-face{font-family:"Qomraa";src:url("../fonts/itfQomraArabic-Bold.woff2") format("woff2");
  font-weight:600 800;font-style:normal;font-display:swap}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;overflow-x:clip}
body{background:var(--bg);color:var(--txt);font-family:'Instrument Sans',system-ui,sans-serif;line-height:1.7;overflow-x:clip}
:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:var(--r-xs);transition:none}
:focus:not(:focus-visible){outline:none}
.skip{position:fixed;inset-inline-start:16px;top:12px;z-index:var(--z-modal);background:var(--acc);color:var(--acc-ink);
  padding:10px 18px;border-radius:var(--r-sm);font-weight:700;font-size:14px;
  transform:translateY(-200%);transition:transform .2s var(--ease)}
.skip:focus{transform:none}
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
html[lang="ar"] body{font-family:Qomraa,Tajawal,'Instrument Sans',system-ui,sans-serif}
h1,h2{font-family:'Outfit','Instrument Sans',system-ui,sans-serif}
h3{font-family:'Instrument Sans',sans-serif}
html[lang="ar"] h1,html[lang="ar"] h2,html[lang="ar"] h3{font-family:Qomraa,Tajawal,sans-serif}
a{color:inherit;text-decoration:none}
.wrap{max-width:1180px;margin:0 auto;padding:0 24px}
.acc{color:var(--acc)}
.mono{font-family:var(--mono)}
section{position:relative}
h2{font-size:clamp(30px,4vw,46px);font-weight:800;line-height:1.2}
.sub{color:var(--mut);max-width:640px;margin-top:12px}


html,body{transition:background-color .4s,color .4s}


/* NAV */
nav{position:fixed;top:16px;left:50%;transform:translateX(-50%);z-index:50;width:min(1180px,94%);
  background:color-mix(in srgb, var(--page) 92%, transparent);backdrop-filter:saturate(1.4) blur(16px);border:1px solid var(--line);border-radius:var(--r);
  display:flex;align-items:center;justify-content:space-between;padding:12px 18px;transition:.3s}
nav.scrolled{border-color:rgba(var(--acc-rgb),.3);box-shadow:0 12px 40px rgba(var(--shadow-rgb),.5)}



@keyframes blink{50%{opacity:0}}
.brand{display:flex;align-items:center;gap:11px}
.brand-pic{width:38px;height:38px;border-radius:50%;overflow:hidden;border:2px solid var(--acc);flex:none;
  box-shadow:var(--sh-1);transition:.3s}
.brand:hover .brand-pic{transform:scale(1.08) rotate(-4deg)}
.brand-pic img{width:100%;height:100%;object-fit:cover}
.brand-name{font-family:'Instrument Sans',Qomraa,Tajawal;font-weight:600;font-size:16px;white-space:nowrap}
.brand-name b{color:var(--acc)}
/* floating pill nav — the active section gets its own filled sub-pill */
nav ul{display:flex;align-items:center;gap:2px;list-style:none;
  background:var(--card2);border:1px solid var(--line);border-radius:var(--r-pill);padding:4px}
/* "~/about" is a path token — force the whole link LTR so RTL can't flip "~/" into "/~" */
nav ul a{color:var(--mut);font-size:13.5px;font-family:var(--mono);transition:color .2s,background .25s;
  direction:ltr;unicode-bidi:isolate;display:inline-block;padding:7px 13px;border-radius:var(--r-pill)}
nav ul a::before{content:"~/";color:var(--acc);opacity:.7;transition:color .25s}
nav ul a:hover{color:var(--txt);background:rgba(150,150,160,.13)}
nav ul a[aria-current="true"]{background:var(--acc);color:var(--acc-ink)}
nav ul a[aria-current="true"]::before{color:var(--acc-ink);opacity:.7}
.menu-btn{display:none;width:38px;height:32px;border-radius:var(--r-sm);border:1px solid var(--line);
  background:var(--card2);color:var(--txt);cursor:pointer;align-items:center;justify-content:center;flex:none;transition:.25s}
.menu-btn svg{width:17px;height:17px}
.menu-btn:hover{border-color:var(--acc);color:var(--acc)}
.menu-btn .x{display:none}
.menu-btn[aria-expanded="true"] .x{display:block}
.menu-btn[aria-expanded="true"] .bars{display:none}
.btn{display:inline-flex;align-items:center;gap:8px;background:var(--acc);color:var(--acc-ink);font-weight:700;font-size:14px;
  padding:11px 20px;border-radius:var(--r-sm);border:0;cursor:pointer;transition:.25s;position:relative;overflow:hidden}
.btn::after{content:"";position:absolute;inset:0;background:linear-gradient(110deg,transparent 30%,rgba(255,255,255,.25) 50%,transparent 70%);transform:translateX(-100%);transition:.5s}
.btn:hover{background:var(--acc2);transform:translateY(-2px);box-shadow:0 12px 34px var(--glow)}
.btn:hover::after{transform:translateX(100%)}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--txt)}
.btn.ghost:hover{border-color:var(--acc);color:var(--acc);box-shadow:none}

/* switch (theme) + lang toggle */
.switch{position:relative;width:66px;height:32px;border-radius:var(--r-pill);cursor:pointer;flex:none;
  background:var(--card2);border:1px solid var(--line);transition:.35s;padding:0}
.switch .knob{position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;
  background:var(--acc);display:flex;align-items:center;justify-content:center;color:var(--acc-ink);
  transition:transform .4s var(--ease),background .35s;box-shadow:0 3px 10px var(--glow)}
.switch .knob svg{width:13px;height:13px}
.switch .tk{position:absolute;top:50%;transform:translateY(-50%);color:var(--mut);transition:opacity .35s}
.switch .tk svg{width:12px;height:12px;display:block}
.switch .tk.l{left:9px}.switch .tk.r{right:9px}
/* the knob parks over the ACTIVE icon; the uncovered one is what you'd switch to */
.switch .tk.l{opacity:0}
.switch.on .tk.l{opacity:1}
.switch.on .tk.r{opacity:0}
.switch.on .knob{transform:translateX(34px)}
.switch:hover{border-color:var(--acc)}
.lang-btn{height:32px;border-radius:var(--r-pill);border:1px solid var(--line);background:var(--card2);color:var(--mut);
  font-family:var(--mono);font-size:12.5px;font-weight:600;letter-spacing:.04em;padding:0 13px;cursor:pointer;
  transition:.25s;flex:none;direction:ltr}
.lang-btn:hover{color:var(--acc);border-color:var(--acc)}
/* below 1180px the pill is the first thing to give — never let the bar wrap */
@media(max-width:1180px){
  nav ul a{padding:7px 10px;font-size:12.5px}
  nav ul{gap:0}}

/* Coarse pointers get the full-size controls; 32px reads fine under a mouse and
   badly under a thumb. Visual size is unchanged — the box just grows. */
@media(pointer:coarse){
  .soc-pill a{width:44px;height:44px}
  .menu-btn,.lang-btn,.switch{height:40px}
  .menu-btn{width:44px}
  .switch .knob{top:8px}}

/* HERO */
.hero{position:relative}
.hero-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:32px;align-items:center}
.hero-copy{position:relative;z-index:3}
.hero h1{font-size:clamp(44px,6.2vw,88px);font-weight:700;line-height:1.04;letter-spacing:-.02em}
html[lang="ar"] .hero h1{font-size:clamp(40px,5.6vw,72px);line-height:1.2;letter-spacing:0;font-weight:800}
.hero .tag{color:var(--mut);margin:20px 0 8px;max-width:560px;font-size:16.5px;line-height:1.75}
.meta{display:flex;flex-wrap:wrap;gap:16px;margin:18px 0 24px;color:var(--ink-soft);font-size:12.5px}
.meta span{display:inline}
.meta span + span::before{content:"·";margin-inline-end:16px;color:var(--rule)}
.hero-text-link{color:var(--ink-soft);font-size:15px;font-weight:600;text-decoration:underline;
  text-underline-offset:4px;text-decoration-color:var(--rule);transition:color .2s,text-decoration-color .2s}
.hero-text-link:hover{color:var(--teal);text-decoration-color:var(--teal)}
.dot{width:8px;height:8px;border-radius:50%;background:var(--acc);box-shadow:0 0 10px var(--acc);animation:pulse 2s infinite}
@keyframes pulse{50%{opacity:.4}}




.avatar-wrap{position:relative;display:flex;justify-content:center}
.mostaql-seal{position:absolute;bottom:8%;inset-inline-end:-6%;z-index:10;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  width:68px;height:68px;border-radius:50%;
  background:var(--amber);color:var(--ink);text-decoration:none;
  font-family:'Outfit','Instrument Sans',sans-serif;
  transform:rotate(12deg);box-shadow:0 4px 16px rgba(0,0,0,.12);
  transition:transform .25s var(--ease)}
.mostaql-seal:hover{transform:rotate(0deg) scale(1.08)}
.mostaql-seal b{font-size:18px;font-weight:700;line-height:1;direction:ltr}
.mostaql-seal span{font-size:9px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;line-height:1;margin-top:2px}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes float{50%{transform:translateY(-12px)}}
/* HERO PORTRAIT — cutout on a target halo, flanked by code brackets.
   Only renders once shots/hero-portrait.png loads; until then the code card stands in.
   Needs a TRANSPARENT PNG cutout — a photo with its own background defeats the halo. */
.portrait{position:relative;z-index:2;display:none}
html[data-portrait] .portrait{display:flex}
/* Full colour. The cutout has no box to put a border on, so stacked zero-offset
   drop-shadows trace the alpha silhouette — that IS the border — over a deep cast shadow. */
.portrait img{position:relative;z-index:3;transition:filter .45s var(--ease)}

@media(hover:hover) and (pointer:fine){
  .avatar-wrap:hover .portrait img{filter:
    drop-shadow(0 0 1.5px rgba(var(--acc-rgb),.85))
    drop-shadow(0 0 14px rgba(var(--acc-rgb),.22))
    drop-shadow(0 26px 42px rgba(var(--shadow-rgb),.62))}}
/* PHOTO MODE — a real photo that carries its own background: framed, not haloed.
   (Cutout mode above still wins if a transparent shots/hero-portrait.png is added later.) */
html[data-portrait="photo"] .portrait{align-items:center}
html[data-portrait="photo"] .portrait img{object-fit:cover;object-position:center 14%;
  border-radius:var(--r-lg);border:1px solid rgba(var(--acc-rgb),.3);
  box-shadow:0 30px 70px rgba(var(--shadow-rgb),.55),inset 0 0 0 1px rgba(255,255,255,.05);filter:none}
/* accent bloom behind the frame, standing in for the halo */
html[data-portrait="photo"] .portrait::before{content:"";position:absolute;z-index:0;inset:-10% -12%;
  background:radial-gradient(closest-side,var(--glow),transparent 74%);filter:blur(8px);pointer-events:none}
/* framed mode: the frame is opaque, so the brackets must clear it entirely */
html[data-portrait="photo"] .portrait{width:min(400px,78vw)}



/* STATS */


/* direction:ltr keeps "8+" / "5.0★" from flipping to "+8" / "★5.0" in RTL */


/* CARDS */
.grid3{display:grid;grid-template-columns:repeat(3,1fr);margin-top:44px}
.grid2{display:grid;grid-template-columns:repeat(2,1fr);margin-top:44px}
.card{position:relative;overflow:hidden}
.card::before{content:"";position:absolute;inset:0;opacity:0;transition:.35s;pointer-events:none}

/* accent hairline sweeps in along the card's top edge on hover */
.card::after{content:"";position:absolute;top:0;inset-inline-start:0;height:2px;width:100%;
  background:linear-gradient(90deg,var(--acc),var(--acc2),transparent);
  transform:scaleX(0);transform-origin:left;transition:transform .45s var(--ease);z-index:4}
html[dir="rtl"] .card::after{transform-origin:right}
.card:hover::after{transform:scaleX(1)}

.card .ico{width:48px;height:48px;border-radius:var(--r-sm);color:var(--acc);align-items:center;justify-content:center;margin-bottom:18px;transition:.3s}
.card:hover .ico{transform:scale(1.1) rotate(-6deg)}
.card .ico svg{width:24px;height:24px}


.tagrow{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
/* scoped to .tagrow — unscoped, this pill rule also swallowed the hero's <p class="tag"> pitch */
.tagrow .tag{font-size:11px;padding:4px 10px;border-radius:var(--r-pill);font-family:var(--mono);direction:ltr}
.card .arrow{position:absolute;top:22px;inset-inline-end:22px;color:var(--mut);transition:.25s}
.card:hover .arrow{transform:translate(3px,-3px)}
/* all-projects drawer — live from the GitHub API, so it never goes stale */





.repo .meta{display:flex;gap:12px;margin-top:10px;font-size:11px;color:var(--mut);font-family:var(--mono);direction:ltr}


@media(max-width:900px){.repos{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.repos{grid-template-columns:1fr}}
.badge{position:absolute;top:12px;inset-inline-end:12px;background:rgba(var(--ink-rgb),.82);border:1px solid var(--line);font-size:11px;color:#fff;padding:4px 10px;border-radius:var(--r-pill);font-family:var(--mono)}

/* TESTIMONIALS */
/* A wall, not a ledger. Nine verified 5.0-star reviews read at the visitor's
   pace, and the circular portrait is what makes each one a person rather than
   a record -- which is the whole job of this section. The ruled-row treatment
   that suits services and the proof figures flattened that; this section keeps
   its cards. */
/* --- testimonials: centred, circular avatars, one raised --- */
.wall{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px;align-items:start}
.testi{width:auto;text-align:center;padding:clamp(24px,3vw,32px);
  border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);
  transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
.testi:nth-child(2){transform:translateY(-12px);box-shadow:var(--sh-2)}
.testi blockquote{font-size:15px;color:var(--txt);line-height:1.8;font-style:normal}
.testi .who{display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:18px}
.testi .who .pic{width:56px;height:56px;border-radius:50%;overflow:hidden;
  border:2px solid rgba(var(--acc-rgb),.4);flex:none}
.testi .who .pic img{width:100%;height:100%;object-fit:cover}
.testi .who small{display:block;color:var(--mut);font-size:12px;direction:ltr;text-align:center}
.stars{color:var(--acc);font-size:13px;margin-bottom:10px;justify-content:center}
.projtag{font-size:11px;color:var(--acc);font-family:var(--mono)}

/* CTA — teal field */
.cta{background:var(--teal);color:#fff;border:0;border-radius:var(--r-lg);padding:64px;
  display:grid;grid-template-columns:1.3fr .7fr;gap:36px;align-items:center;position:relative;overflow:hidden}
.cta::after{content:"";position:absolute;inset-inline-end:-120px;top:-120px;width:340px;height:340px;border-radius:50%;
  background:radial-gradient(circle,rgba(255,255,255,.08),transparent 65%)}
.cta h2{font-size:clamp(28px,3.6vw,42px);color:#fff}
.cta .sub{color:rgba(255,255,255,.75)}
.socials{display:flex;gap:10px;margin-top:22px;flex-wrap:wrap}
.socials a{width:42px;height:42px;border:1px solid rgba(255,255,255,.25);border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.7);transition:.25s}
.socials a svg{width:18px;height:18px}
.socials a:hover{color:#fff;border-color:rgba(255,255,255,.5);transform:translateY(-3px)}
/* 360px: controls needed 323px inside a 312px content box. Tighten the gap and the
   theme switch rather than dropping a control — nothing becomes unreachable. */
@media(max-width:400px){
  nav > div:last-child{gap:6px!important}
  .switch{width:54px}
  .switch.on .knob{transform:translateX(22px)}
  .switch .tk.l{left:7px}.switch .tk.r{right:7px}
  nav .btn{padding:9px 11px;font-size:12px}}
/* PROCESS — a spine that fills as you scroll, so the sequence reads as a journey
   rather than a list. The rail is one element; each node lights when it arrives. */
.steps{margin-top:52px;max-width:880px;position:relative}
.steps::before{content:"";position:absolute;inset-inline-start:23px;top:14px;bottom:34px;width:0;
  border-inline-start:2px dotted var(--rule)}
.steps::after{content:"";position:absolute;inset-inline-start:23px;top:14px;bottom:34px;width:0;
  border-inline-start:2px solid var(--teal);
  transform:scaleY(var(--fill,0));transform-origin:top;transition:transform .25s linear}
.step{display:grid;grid-template-columns:48px 1fr;gap:26px;padding:0 0 34px;position:relative}
.step:last-child{padding-bottom:0}
.step .no{width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-family:'Outfit','Instrument Sans',sans-serif;font-size:16px;font-weight:700;
  color:var(--ink-soft);background:var(--surface);
  border:2px solid var(--rule);position:relative;z-index:2;direction:ltr;
  transition:color .45s var(--ease),border-color .45s var(--ease),background .45s var(--ease),transform .45s var(--ease)}
.step.lit .no{color:#fff;border-color:transparent;
  box-shadow:0 0 0 6px rgba(var(--teal-rgb),.14);transform:scale(1.06)}
.step:nth-child(3n+1).lit .no{background:var(--teal)}
.step:nth-child(3n+2).lit .no{background:var(--amber);color:var(--ink)}
.step:nth-child(3n).lit .no{background:var(--coral)}
.step .body{padding-top:9px;opacity:.45;transform:translateY(10px);
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
.step.lit .body{opacity:1;transform:none}
.step h3{font-size:19px;margin-bottom:7px}
.step p{color:var(--mut);font-size:14.5px;line-height:1.75;max-width:60ch}
.step .tag-when{display:inline-flex;align-items:center;gap:6px;margin-top:12px;
  font-size:12px;font-weight:600;color:var(--acc);background:rgba(var(--teal-rgb),.08);border:1px solid rgba(var(--teal-rgb),.18);
  padding:5px 11px;border-radius:var(--r-pill)}
.step .tag-when::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--acc)}
@media(max-width:600px){
  .steps::before,.steps::after{inset-inline-start:18px}
  .step{grid-template-columns:38px 1fr;gap:16px;padding-bottom:26px}
  .step .no{width:38px;height:38px;font-size:13px}}
@media(prefers-reduced-motion:reduce){
  .steps::after{display:none}
  .step .body{opacity:1;transform:none}
  .step .no{transition:none}}

/* CONTACT FORM */
.cform{display:grid;gap:12px;margin-top:22px}
.cform .row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.cform input,.cform textarea{width:100%;background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.25);border-radius:var(--r-sm);
  padding:13px 15px;color:#fff;font-family:inherit;font-size:14.5px;transition:border-color .2s}
.cform input::placeholder,.cform textarea::placeholder{color:rgba(255,255,255,.55)}
.cform textarea{min-height:110px;resize:vertical}
.cform input:focus,.cform textarea:focus{outline:none;border-color:rgba(255,255,255,.6)}
.cform button.btn{background:#fff;color:var(--teal);justify-content:center;width:100%}
.cform button.btn:hover{background:var(--page);transform:none;box-shadow:none}
.cform .btn.ghost{background:transparent;border-color:rgba(255,255,255,.3);color:#fff}
.cform .btn.ghost:hover{border-color:rgba(255,255,255,.5);color:#fff;box-shadow:none}
.cform .note{font-size:12px;color:rgba(255,255,255,.6);text-align:center;line-height:1.6}
.cform .msg{font-size:13.5px;padding:11px 14px;border-radius:var(--r-sm);display:none}
.cform .msg.ok{display:block;background:rgba(var(--acc-rgb),.12);color:var(--acc);border:1px solid rgba(var(--acc-rgb),.3)}
/* the accent is now mint, so success and failure would have collapsed to the same
   colour. Errors keep the old red as --warn — the one job red still holds. */
.cform .msg.err{display:block;background:rgba(var(--warn-rgb),.12);color:var(--warn);border:1px solid rgba(var(--warn-rgb),.35)}
/* physical left:-9999px lands ON-screen in RTL. clip-path + zero box hides it
   in both directions without moving it anywhere. */
.hp{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;opacity:0;pointer-events:none}
@media(max-width:600px){.cform .row{grid-template-columns:1fr}}


/* ============ AI ASSISTANT ============ */
.ai-fab{color:var(--acc-ink);position:fixed;bottom:22px;inset-inline-end:22px;z-index:60;display:flex;align-items:center;gap:10px;
  background:var(--acc);color:var(--acc-ink);border:0;border-radius:var(--r-pill);padding:13px 20px;cursor:pointer;
  font-weight:700;font-size:14px;font-family:inherit;box-shadow:0 14px 40px var(--glow);transition:.25s}
.ai-fab:hover{background:var(--acc2);transform:translateY(-2px)}
.ai-fab svg{width:18px;height:18px}
.ai-fab .pip{width:8px;height:8px;border-radius:50%;background:#fff;opacity:.9;animation:pulse 2s infinite}
/* --- the bot: blinking eyes, wobbling antenna, hop on hover --- */
.botface{position:relative;width:30px;height:28px;flex:none}
.botface .head{position:absolute;inset:6px 0 0 0;background:currentColor;border-radius:var(--r-xs);opacity:.95}
.botface .ant{position:absolute;top:0;left:50%;width:2px;height:8px;background:currentColor;
  transform-origin:bottom center;transform:translateX(-50%);animation:antwob 2.6s ease-in-out infinite}
.botface .ant::after{content:"";position:absolute;top:-4px;left:50%;width:6px;height:6px;margin-left:-3px;
  border-radius:50%;background:var(--acc);box-shadow:0 0 8px var(--acc)}
.botface .eye{position:absolute;top:14px;width:6px;height:6px;border-radius:50%;background:var(--acc);
  animation:blinkeye 3.6s infinite}
.botface .eye.l{left:6px}.botface .eye.r{right:6px}
.botface .mouth{position:absolute;bottom:5px;left:50%;width:12px;height:3px;margin-left:-6px;border-radius:3px;
  background:var(--acc);opacity:.75}
@keyframes antwob{0%,100%{transform:translateX(-50%) rotate(-13deg)}50%{transform:translateX(-50%) rotate(13deg)}}
@keyframes blinkeye{0%,92%,100%{transform:scaleY(1)}95%{transform:scaleY(.12)}}
@keyframes bothop{0%,100%{transform:translateY(0) rotate(0)}30%{transform:translateY(-5px) rotate(-7deg)}60%{transform:translateY(0) rotate(5deg)}}
.ai-fab:hover .botface{animation:bothop .7s var(--ease)}
.ai-head .botface{color:var(--card)}
/* peeking wave when the panel first opens */
@keyframes botwave{0%{transform:rotate(0)}25%{transform:rotate(-18deg)}50%{transform:rotate(12deg)}75%{transform:rotate(-8deg)}100%{transform:rotate(0)}}
.ai-head .botface.wave{animation:botwave .9s var(--ease)}
.ai-panel{position:fixed;bottom:22px;inset-inline-end:22px;z-index:61;width:min(400px,calc(100vw - 32px));
  height:min(560px,calc(100vh - 44px));background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
  display:none;flex-direction:column;overflow:hidden;box-shadow:0 34px 80px rgba(var(--shadow-rgb),.6)}
.ai-panel.open{display:flex}
.ai-head{display:flex;align-items:center;gap:11px;padding:14px 16px;border-bottom:1px solid var(--line);
  background:var(--card2)}
.ai-head .pic{width:36px;height:36px;border-radius:50%;overflow:hidden;border:2px solid var(--acc);flex:none}
.ai-head .pic img{width:100%;height:100%;object-fit:cover}
.ai-head b{font-size:14px;display:block}
.ai-head small{color:var(--acc);font-size:11.5px;display:flex;align-items:center;gap:5px}
.ai-head .x{margin-inline-start:auto;background:none;border:0;color:var(--mut);cursor:pointer;padding:6px;border-radius:var(--r-xs)}
.ai-head .x:hover{color:var(--txt);background:rgba(150,150,160,.14)}
.ai-head .x svg{width:16px;height:16px}
/* min-height:0 is required — without it a scrollable flex child refuses to shrink and its
   content spills under the chips/composer instead of scrolling */
.ai-log{flex:1;min-height:0;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;scroll-behavior:smooth}
/* full-width row + bubble inside — a bare flex item with align-self shrinks to its
   longest word here, which collapsed every message to one word per line */
/* flex:none is load-bearing — as shrinkable items in a column flex container the rows
   get compressed once the log overflows, which squashed bubbles and spilled their text */
.ai-row{display:flex;width:100%;flex:0 0 auto}
.ai-row.me{justify-content:flex-end}
/* fit-content is load-bearing: without it the bubble computes a zero-width content box
   and the text overflows as one word per line (verified empirically, 30px vs 315px) */
.ai-msg{width:fit-content;max-width:86%;padding:11px 14px;border-radius:var(--r);font-size:14px;
  line-height:1.65;white-space:pre-wrap}
.ai-msg.bot{background:var(--card2);border:1px solid var(--line);border-start-start-radius:5px}
.ai-msg.me{background:var(--acc);color:var(--acc-ink);border-end-end-radius:5px}
.ai-typing{display:flex;gap:4px;align-self:flex-start;flex:0 0 auto;padding:13px 15px;background:var(--card2);
  border:1px solid var(--line);border-radius:var(--r);border-start-start-radius:5px}
.ai-typing i{width:6px;height:6px;border-radius:50%;background:var(--mut);animation:blip 1.1s infinite}
.ai-typing i:nth-child(2){animation-delay:.15s}.ai-typing i:nth-child(3){animation-delay:.3s}
@keyframes blip{0%,60%,100%{opacity:.3;transform:translateY(0)}30%{opacity:1;transform:translateY(-4px)}}
.ai-chips{display:flex;flex-wrap:wrap;gap:7px;padding:10px 16px 12px;flex:0 0 auto;
  background:var(--card);border-top:1px solid var(--line)}
.ai-chips:empty{display:none}
.ai-chips button{background:var(--card2);border:1px solid var(--line);color:var(--mut);border-radius:var(--r-pill);
  padding:7px 13px;font-size:12.5px;cursor:pointer;font-family:inherit;transition:.2s}
.ai-chips button:hover{border-color:var(--acc);color:var(--acc)}
.ai-form{display:flex;gap:8px;padding:12px 14px;border-top:1px solid var(--line);background:var(--card2)}
.ai-form input{flex:1;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-sm);padding:11px 13px;
  color:var(--txt);font-family:inherit;font-size:14px;min-width:0}
.ai-form input:focus{outline:none;border-color:var(--acc)}
.ai-form button{background:var(--acc);border:0;color:var(--acc-ink);border-radius:var(--r-sm);padding:0 15px;cursor:pointer;flex:none}
.ai-form button svg{width:17px;height:17px}
.ai-note{font-size:11px;color:var(--mut);text-align:center;padding:0 16px 10px;line-height:1.5}
@media(max-width:600px){
  .ai-fab{bottom:16px;inset-inline-end:16px;padding:12px 16px;font-size:13px}
  .ai-panel{bottom:12px;inset-inline-end:12px;inset-inline-start:12px;width:auto;height:min(72vh,540px)}}
/* Arabic in mono-styled chrome: JetBrains Mono has no Arabic glyphs, so these were
   silently falling back to a system face and breaking the type system. Latin-only
   elements (kickers, tech tags, slugs, terminal lines) stay mono on purpose. */
html[lang="ar"] nav ul a,
html[lang="ar"] .badge,
html[lang="ar"] .proj .links a,
html[lang="ar"] .step .tag-when,
html[lang="ar"] .ai-chips button{font-family:Qomraa,Tajawal,sans-serif}
html[lang="ar"] nav ul a::before{font-family:var(--mono)}

svg{flex:none}
.tro{color:var(--acc);display:inline-block;vertical-align:-3px}.tro svg{width:16px;height:16px}
/* 3D */

.grid3,.grid2{perspective:1200px}
.card{transform-style:preserve-3d}
.card .ico,.card h3,.card p,.card .tagrow,.card .body,.card .who{transform:translateZ(24px)}
/* Hiding is gated on `html.js`: without scripting the observer never runs, so an
   unscoped `opacity:0` would blank most of the page. No JS, no hiding. */
.js .reveal{opacity:0;transform:translateY(24px);transition:opacity .55s var(--ease),transform .55s var(--ease)}
.reveal.in{opacity:1;transform:none}
.reveal.in>*:nth-child(7){transition-delay:.36s}
.reveal.in>*:nth-child(8){transition-delay:.42s}
.reveal.in>*:nth-child(9){transition-delay:.48s}
.reveal.in>*:nth-child(2){transition-delay:.06s}
.reveal.in>*:nth-child(3){transition-delay:.12s}
.reveal.in>*:nth-child(4){transition-delay:.18s}
.reveal.in>*:nth-child(5){transition-delay:.24s}
.reveal.in>*:nth-child(6){transition-delay:.3s}
@media(max-width:900px){
  .hero-grid,.cta{grid-template-columns:1fr}
  .grid3{grid-template-columns:1fr 1fr}
  .wall{grid-template-columns:repeat(2,1fr)}
  .avatar-wrap{margin-top:24px}
  nav{flex-wrap:wrap;padding:10px 12px;gap:8px}
  .menu-btn{display:inline-flex}
  nav .btn{padding:9px 14px;font-size:13px;white-space:nowrap}
  .brand-name{font-size:14.5px}
  nav ul{display:none;order:9;flex-basis:100%;flex-direction:column;gap:0;
    background:none;border:0;border-radius:0;
    padding-top:8px;margin-top:8px;border-top:1px solid var(--line)}
  nav ul.open{display:flex}
  nav ul a{display:block;padding:11px 4px;font-size:15px}
  section{padding:76px 0}
  .cta{padding:40px 28px}}
@media(max-width:600px){
  .grid3,.grid2,.wall{grid-template-columns:1fr}
  .hero{padding:130px 0 56px}
  section{padding:60px 0}
  .wrap{padding:0 18px}
  .cta{padding:32px 22px;border-radius:var(--r-lg)}}
@media(max-width:430px){
  .brand-name{display:none}}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;transition-delay:0!important;scroll-behavior:auto!important}
  .reveal,.reveal>*{opacity:1!important;transform:none!important}
  .card::after{display:none}
  .botface .ant,.botface .eye{animation:none!important}
  .ai-fab:hover .botface,.ai-head .botface.wave{animation:none!important}
  .caret,.cursor,.dot{animation:none!important}}

/* ---- polish: selection + scrollbar ---- */
::selection{background:rgba(var(--acc-rgb),.35);color:var(--txt)}
*{scrollbar-width:thin;scrollbar-color:rgba(var(--teal-rgb),.35) rgba(var(--rule-rgb),.3)}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:rgba(var(--rule-rgb),.2)}
::-webkit-scrollbar-thumb{background:rgba(var(--teal-rgb),.35);border-radius:var(--r-pill);border:2px solid var(--bg)}
::-webkit-scrollbar-thumb:hover{background:rgba(var(--teal-rgb),.5)}
section[id]{scroll-margin-top:96px}

/* ---- back to top ---- */
.totop{position:fixed;bottom:22px;inset-inline-start:22px;z-index:55;width:44px;height:44px;border-radius:var(--r);display:grid;place-items:center;background:var(--card2);border:1px solid var(--line);color:var(--txt);cursor:pointer;opacity:0;pointer-events:none;transform:translateY(10px);transition:opacity .3s var(--ease),transform .3s var(--ease),background .3s,border-color .3s,color .3s}
.totop.show{opacity:1;pointer-events:auto;transform:none}
.totop:hover{background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
@media(max-width:600px){.totop{bottom:18px;inset-inline-start:18px}}

/* ---- card v2: lift + ring + ambient glow + light sheen ---- */


.card::before{background:radial-gradient(400px 200px at var(--mx,50%) var(--my,0%),rgba(var(--acc-rgb),.08),transparent 60%),linear-gradient(115deg,transparent 32%,rgba(255,255,255,.07) 46%,transparent 60%);background-size:100% 100%,220% 100%;background-position:0 0,130% 0}
.card:hover::before{opacity:1;background-position:0 0,-30% 0;transition:opacity .35s,background-position .7s var(--ease)}
.card .ico{background:linear-gradient(135deg,rgba(var(--acc-rgb),.16),rgba(var(--acc2-rgb),.06));border:1px solid rgba(var(--acc-rgb),.18)}

/* ---- stats: gradient ring + gradient number ---- */

/* the figures carry their emphasis in weight and the solid accent */

/* ==========================================================================
   LUIQUE LAYER — the reference's four visual devices, as reusable primitives.
   Nothing below is section-specific; every new section composes these.
   ========================================================================== */

/* 1. Ghost watermark ------------------------------------------------------
   A large low-opacity word behind each section. A real <span aria-hidden>,
   not a ::before with attr(), so it is reliably out of the a11y tree and can
   carry a separate Arabic string — a long Latin word behind RTL copy reads
   as noise, so I18N sets its own per language. */
.sec{position:relative;isolation:isolate}

/* 2. Centred section header ----------------------------------------------- */
.sec-head{position:relative;z-index:1;margin-bottom:var(--s6);max-width:64ch}
.sec-head h2{font-size:clamp(30px,4.4vw,50px);letter-spacing:-.02em;line-height:1.14}
html[lang="ar"] .sec-head h2{letter-spacing:0;line-height:1.3}
.sec-head .eyebrow{display:block;margin-bottom:var(--s3);color:var(--acc);
  font-family:var(--mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase}
html[lang="ar"] .sec-head .eyebrow{letter-spacing:.06em}
.sec-head .sub{margin-top:var(--s4);max-width:62ch}

/* 4. Section rhythm -------------------------------------------------------
   Was bg -> bg2 -> bg -> bg2 -> bg2 -> bg: testimonials and process were
   adjacent on the same tone, so they read as one undifferentiated slab.
   Alternation is now structural, and padding scales with density instead of
   every section getting the same 100px regardless of content. */
.sec{padding-block:var(--s9)}

.sec--alt{background:var(--bg2)}
@media(max-width:900px){.sec{padding-block:var(--s8)}.sec--tight{padding-block:var(--s7)}}
@media(max-width:600px){.sec{padding-block:var(--s7)}.sec--tight{padding-block:var(--s6)}}

/* ==========================================================================
   CARD v3 — the reference's card, replacing the icon-tile card.
   Reference anatomy: small uppercase mint category label, bold title, muted
   body, a "see more ->" link on the baseline, and a dotted-grid block in the
   trailing bottom corner. No 48px icon tile, no heavy glow, no 3D tilt: the
   old card shouted, this one reads.
   ========================================================================== */

.card .eyebrow{display:block;font-family:var(--mono);text-transform:uppercase;color:var(--acc);direction:ltr;unicode-bidi:isolate}
html[lang="ar"] .card .eyebrow{font-family:Qomraa,Tajawal,sans-serif;letter-spacing:.04em;direction:inherit}
.card h3{line-height:1.35}

.card .more{display:inline-flex;align-items:center;gap:7px;color:var(--acc);transition:gap .25s var(--ease)}
.card .more::after{content:"";width:.85em;height:.85em;flex:none;background:currentColor;
  -webkit-mask:var(--ico-chevron) center/contain no-repeat;mask:var(--ico-chevron) center/contain no-repeat;
  transition:transform .25s var(--ease)}
html[dir="rtl"] .card .more::after{transform:scaleX(-1)}
.card:hover .more{gap:11px}

/* quieter hover: a lift and an accent edge, not a glow + sheen + tilt stack */


.card::before{display:none}                 /* spotlight + sheen layer retired */
.card .ico{display:none}                    /* icon tile replaced by the eyebrow */
.card:hover .arrow{color:var(--acc)}
/* the reference keeps tags, but as quiet outlines rather than filled pills */
.tagrow .tag{background:transparent;border:1px solid var(--line);color:var(--mut)}
.card:hover .tagrow .tag{border-color:rgba(var(--acc-rgb),.3)}

/* ==========================================================================
   CARD v4 — professional restraint, matching the reference more literally.
   v3 still carried too much: 24px corners, generous padding, and a row of tag
   pills under every service. The reference card holds four things only —
   label, title, one short paragraph, one link — on near-square corners.
   ========================================================================== */
.card{padding:var(--s5) var(--s5) var(--s6);border:1px solid var(--line);box-shadow:none}
.card h3{font-size:18px;margin-bottom:var(--s2);letter-spacing:-.01em}
.card p{font-size:13.5px;color:var(--mut);line-height:1.7}
.card .eyebrow{font-size:11px;letter-spacing:.14em;margin-bottom:var(--s2)}
.card .more{font-size:12.5px;font-weight:600}
.card:hover{transform:none;background:var(--card2)}
.card .arrow{display:none}
.grid3{gap:var(--s3)}
.grid2{gap:var(--s3)}
.testi{border-radius:6px}
/* the cutout sat on a bloom, so it carried an accent rim to define its edge.
   On a solid disc that rim reads as a halo artefact — drop it, keep the cast. */

@media(hover:hover) and (pointer:fine){
  .avatar-wrap:hover .portrait img{filter:drop-shadow(0 22px 36px rgba(var(--shadow-rgb),.5))}}


/* form validation feedback - there was no aria-invalid and no visual cue */
.cform [aria-invalid="true"]{border-color:var(--warn)}
.cform [aria-invalid="true"]:focus{border-color:var(--warn);outline-color:var(--warn)}

/* ---- tap targets: WCAG 2.5.8 wants 24x24 CSS px minimum ----------------
   Footer column links measured 20px tall and the project Live/Case-study
   links 22px. Padding rather than font-size, so nothing reflows: the extra
   height is absorbed by the existing column gap. */
.foot-col a{display:inline-flex;align-items:center;justify-content:flex-start;min-height:24px;min-width:24px;padding-block:2px}
.foot-col ul{gap:6px}
.soc-pill a,.socials a{min-width:24px;min-height:24px}

/* ==========================================================================
   CARD v5 — the alignment the reference actually has.
   v4 got the anatomy right but let each card size to its own copy, so the
   "see details" links landed at three different heights across a row. In the
   reference every link sits on one baseline and the dot matrix pins to the
   same corner regardless of body length.
   ========================================================================== */
.grid3,.grid2{align-items:stretch}
.card{display:flex;flex-direction:column;height:100%}
/* the link is the floor of the card: everything above it can grow */
.card .more{margin-top:auto;padding-top:var(--s6)}
.card .tagrow{margin-top:var(--s4)}

/* ============================================================================
   EDITORIAL PROOF — hero note, case studies, engineering depth, architecture,
   judgment. Reuses the existing tokens; adds no new palette.
   ========================================================================== */
.hero-note{margin-top:18px;padding-inline-start:16px;border-inline-start:1px solid var(--acc);
  color:var(--txt);font-size:clamp(15px,1.5vw,17px);line-height:1.7;max-width:56ch}
.hero-cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px}

/* ---- case studies ---- */
.casewall{display:grid}
.case{display:grid;grid-template-columns:minmax(0,340px) minmax(0,1fr);border:1px solid var(--line)}
.case.feat{grid-template-columns:minmax(0,420px) minmax(0,1fr)}
.case-shot{display:block;background:var(--card2);overflow:hidden;align-self:stretch;border-start-start-radius:var(--r-sm);border-end-start-radius:var(--r-sm)}
.case-frame{display:block;position:relative;block-size:100%;overflow:hidden}
.case-shot img{display:block;width:100%;block-size:100%;min-block-size:100%;object-fit:cover;object-position:top}
.case-shot.missing .case-frame{min-height:200px;background:var(--card2)}
.case-shot .badge{position:absolute;inset-block-start:14px;inset-inline-start:14px;inset-inline-end:auto;width:fit-content;
  padding:5px 11px;border-radius:999px;font-size:12px;font-weight:600;
  background:rgba(var(--acc-rgb),.14);color:var(--acc);border:1px solid rgba(var(--acc-rgb),.3);
  backdrop-filter:blur(6px)}
.case-body{padding:28px 30px 26px;min-width:0}
.case-body h3{font-size:clamp(19px,2vw,24px);line-height:1.35;margin:8px 0 18px}
.case-body h3 a{color:inherit;text-decoration:none}
.case-body h3 a:hover{color:var(--acc)}
.case-fields{display:grid;gap:14px;margin:0}
.case-field{display:grid;grid-template-columns:minmax(120px,26%) minmax(0,1fr);gap:14px;
  padding-block-end:14px;border-block-end:1px solid var(--line)}
.case-field:last-child{border-block-end:0;padding-block-end:0}
.case-field dt{font-family:var(--mono);text-transform:uppercase;color:var(--acc2);padding-block-start:2px}
.case-field dd{margin:0;color:var(--mut);font-size:14.5px;line-height:1.75}
.case .links{display:flex;gap:18px;flex-wrap:wrap;margin-top:22px}
.case .links a{display:inline-flex;align-items:center;gap:7px;color:var(--acc);
  font-size:14px;font-weight:600;text-decoration:none;min-height:44px}
.case .links a:hover{text-decoration:underline}
.case .links svg{width:15px;height:15px;flex:none}
.case-disclosure{margin-top:26px;color:var(--mut);font-size:13.5px;line-height:1.8;max-width:80ch}
.case-disclosure a{color:var(--acc)}
.case-more{margin-top:22px}

/* ---- engineering depth ---- */
.domains{display:grid}


.domain p{color:var(--mut);line-height:1.8}
.depth{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 0;padding:0}
.depth li{font-family:var(--mono);font-size:12px;padding:5px 10px;border-radius:6px;
  border:1px solid var(--line);color:var(--acc2);background:var(--card2)}

/* ---- architecture proof ---- */
.arch{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:34px;align-items:start}
.arch-fig{margin:0;border:1px solid var(--line);padding:22px;overflow-x:auto;direction:ltr}
html[dir="rtl"] .arch-fig figcaption{direction:rtl;text-align:right}
.arch-svg{width:100%;min-width:520px;height:auto;display:block;direction:ltr}
.arch-svg rect{fill:var(--card2);stroke:var(--line);stroke-width:1.5}
.arch-svg .arch-shell{fill:none;stroke:var(--line);stroke-dasharray:5 5}
.arch-svg .arch-core{fill:rgba(var(--acc-rgb),.1);stroke:rgba(var(--acc-rgb),.45)}
.arch-svg text{fill:var(--txt);font-size:13px;font-weight:600;text-anchor:middle;
  font-family:inherit}
.arch-svg text.sm{fill:var(--mut);font-size:11px;font-weight:400}
.arch-svg .arch-shell-label{fill:var(--mut);font-family:var(--mono);font-size:11px;font-weight:400;text-anchor:end}
.arch-svg .arch-edges path{fill:none;stroke:var(--acc2);stroke-width:1.5;opacity:.65}
.arch-fig figcaption{margin-top:16px;color:var(--mut);font-size:13px;line-height:1.7}

.arch-q h3{margin:0 0 10px}
.arch-q p{color:var(--mut);font-size:14.5px;line-height:1.8;margin:0}

/* ---- human judgment x AI ---- */
.judg-quote{margin:26px 0 0}
.judg-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}

.judg-col h3{margin:0 0 16px}
.judg-col ul{list-style:none;margin:0;padding:0;display:grid;gap:12px}
.judg-col li{position:relative;padding-inline-start:20px;color:var(--mut);font-size:14.5px;line-height:1.75}
.judg-col li::before{content:"";position:absolute;inset-inline-start:0;inset-block-start:.62em;
  width:7px;height:7px;border-radius:2px;background:var(--acc)}

/* the diagram has a hard minimum width; give it the full row before it clips */
@media (max-width:1100px){
  .arch{grid-template-columns:1fr}}
@media (max-width:900px){
  .case,.case.feat{grid-template-columns:1fr}
  .case-shot{border-end-start-radius:0;border-start-end-radius:var(--r-sm)}
  .case-frame{block-size:auto}
  .case-shot img{block-size:auto;min-block-size:0;aspect-ratio:16/10}
  .case-shot{min-height:0}
  /* stacked: the shot sits above the evidence, so pinning it would cover the text */
  .case-frame{position:static}
  .domains,.judg-grid{grid-template-columns:1fr}}
@media (max-width:560px){
  .case-body{padding:22px 20px}
  .case-field{grid-template-columns:1fr;gap:5px}
  .domain,.judg-col{padding:22px 20px}
  .hero-cta .btn{width:100%;justify-content:center}}

.nav-cta-short{display:none}
@media (max-width:820px){
  .nav-cta-full{display:none}
  .nav-cta-short{display:inline}}

/* ============================================================================
   EDITORIAL LAYER
   Replaces the card-and-glow template surface with typographic structure:
   hairline rules instead of boxes, one accent used sparingly, and enough air
   that the hierarchy is legible before anything is read.
   ========================================================================== */

/* --- rhythm ---------------------------------------------------------------
   Sections were a uniform 100px regardless of what was in them. Density now
   decides: an eight-field case study needs more room around it than a
   two-card writing block. */
section{padding:clamp(72px,9vw,132px) 0}
.hero{padding:clamp(40px,5vw,72px) 0 clamp(48px,6vw,80px)}

/* --- the portrait ---------------------------------------------------------
   Was a dashed spinning ring, six orbiting tool icons, a glowing disc and two
   chevrons. None of it said anything. A photograph with a quiet ground does. */
.portrait,html[data-portrait] .portrait{display:flex}
.avatar-wrap{perspective:none;position:relative}
.portrait{width:100%;max-width:440px;margin-inline:auto;aspect-ratio:4/5;
  background:none;border-radius:0;overflow:visible;
  align-items:flex-end;justify-content:center;position:relative;z-index:2}
.portrait img{width:100%;height:100%;object-fit:cover;object-position:top center;
  filter:drop-shadow(0 18px 36px rgba(var(--shadow-rgb),.18))}
html[data-portrait="cut"] .portrait img{object-fit:contain;object-position:bottom center;
  /* A cut-out with no shadow floats. Offset and soft blur, tinted from the
     ink rather than black, because a neutral shadow on a warm ground reads
     grey. */
  filter:drop-shadow(0 18px 30px rgba(var(--ink-rgb),.26))}
.avatar-wrap:hover .portrait img{filter:drop-shadow(0 22px 40px rgba(var(--shadow-rgb),.24))}
.brush-stroke{position:absolute;inset:-8% -12%;z-index:1;pointer-events:none;
  clip-path:inset(100% 0 0 0);animation:brush-reveal .7s cubic-bezier(.16,1,.3,1) .2s forwards}
.brush-stroke img{width:100%;height:100%;display:block}
@keyframes brush-reveal{to{clip-path:inset(0 0 0 0)}}
@media(prefers-reduced-motion:reduce){
  .brush-stroke{clip-path:none;animation:none}}


/* --- engineering depth ----------------------------------------------------
   Four equal boxes in a 2x2 is the single most template-looking arrangement on
   the page. Ruled rows keep the grouping and drop the pretence. */
/* --- skills: 2×2 grid with visible rules --- */
.skills-grid{display:grid;grid-template-columns:1fr 1fr;margin-top:clamp(40px,5vw,64px);
  border-block-start:1px solid var(--line);border-inline-start:1px solid var(--line)}
.skill-cell{padding:clamp(24px,3vw,36px);border-block-end:1px solid var(--line);
  border-inline-end:1px solid var(--line)}
.skill-cell h3{margin:0 0 8px;font-size:clamp(18px,1.9vw,22px);line-height:1.3}
.skill-cell p{margin:0;font-size:14.5px;color:var(--mut);line-height:1.75;max-width:calc(40ch * var(--measure))}

/* --- career timeline -------------------------------------------------------
   Vertical dotted rail with coloured nodes. RTL mirrors automatically via
   logical properties: the rail sits on inline-start (left in LTR, right in RTL). */
.timeline{list-style:none;margin:clamp(40px,5vw,64px) 0 0;padding:0;
  position:relative;border-inline-start:2px dotted var(--line)}
.tl-item{position:relative;padding:0 0 clamp(36px,4vw,52px) clamp(28px,3vw,40px)}
.tl-item:last-child{padding-block-end:0}
.tl-node{position:absolute;inset-inline-start:-7px;top:4px;width:12px;height:12px;
  border-radius:50%;background:var(--acc);border:2px solid var(--bg);box-shadow:0 0 0 2px var(--acc)}
.tl-when{display:inline-block;font-family:var(--mono);font-size:12.5px;font-weight:700;
  color:var(--acc);letter-spacing:.06em;direction:ltr;margin-bottom:6px}
html[lang="ar"] .tl-when{letter-spacing:.02em;font-size:13.5px}
.tl-role{margin:0 0 2px;font-size:clamp(17px,1.8vw,21px);font-weight:700;line-height:1.3}
.tl-org{display:inline-block;font-size:13.5px;color:var(--mut);margin-bottom:8px;direction:ltr}
.tl-desc{margin:0;font-size:14.5px;color:var(--mut);line-height:1.75;max-width:calc(56ch * var(--measure))}

/* --- judgment -------------------------------------------------------------
   Two columns, one rule between them. */
.judg-quote{border-inline-start:0;padding-inline-start:0;margin-block:clamp(32px,4vw,48px) 0;
  font-size:clamp(24px,3.6vw,38px);font-weight:700;line-height:1.25;letter-spacing:-.015em;
  max-width:22ch;color:var(--txt)}
html[lang="ar"] .judg-quote{letter-spacing:0;line-height:1.45}
.judg-grid{gap:0;margin-top:clamp(40px,5vw,64px);border-block-start:1px solid var(--line)}
.judg-col{background:none;border:0;border-radius:0;padding:clamp(28px,3vw,40px)}
.judg-col + .judg-col{background:rgba(var(--teal-rgb),.05);border-radius:var(--r-sm);
  border-inline-start:0}
.judg-col h3{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--acc);margin-bottom:var(--s4)}
html[lang="ar"] .judg-col h3{font-family:Qomraa,Tajawal,sans-serif;letter-spacing:.04em;
  font-size:13px;text-transform:none}

/* --- architecture ---------------------------------------------------------
   The figure keeps its frame: it is a diagram, and a diagram needs a ground. */
.arch{margin-top:clamp(40px,5vw,64px)}
.arch-fig{background:rgba(var(--teal-rgb),.04);border-radius:var(--r-sm)}
.arch-q h3{font-family:inherit;font-size:17px;letter-spacing:0;text-transform:none;color:var(--txt)}
.arch-q{padding-block-start:var(--s5);border-block-start:1px solid var(--line)}
.arch-q + .arch-q{margin-top:var(--s5)}

/* --- case studies ---------------------------------------------------------
   These keep a frame -- each one is a self-contained argument and the shot
   needs an edge -- but lose the gradient fill and the rounded-pill look. */
.case{border-radius:var(--r-sm);background:var(--card);gap:0}
.casewall{gap:clamp(20px,2.4vw,32px);margin-top:clamp(40px,5vw,64px)}
.case-field dt{font-size:11px;letter-spacing:.12em}
html[lang="ar"] .case-field dt{letter-spacing:.02em;font-size:12.5px}

/* --- remaining cards ------------------------------------------------------
   Services and writing still use .card. Flat fill, no lift, no shadow: they
   are navigation, not features. */
.card{background:var(--card);border-radius:var(--r-sm);
  transition:border-color .25s,background-color .25s;transform:none!important}
.card:hover{border-color:rgba(var(--acc-rgb),.4);box-shadow:none}

/* --- type -----------------------------------------------------------------*/
h2{letter-spacing:-.022em}
html[lang="ar"] h2{letter-spacing:0}
.hero h1{letter-spacing:-.03em}
html[lang="ar"] .hero h1{letter-spacing:0}



@media(max-width:900px){
  .skills-grid{grid-template-columns:1fr;border-inline-start:0}
  .skill-cell{border-inline-end:0}
  .judg-col + .judg-col{padding-inline-start:0;border-inline-start:0;
    border-block-start:1px solid var(--line);margin-top:var(--s5)}
}


/* --- ARABIC LABELS --------------------------------------------------------
   The small labels are set in a Latin monospace with uppercase and .14em
   tracking. Arabic has no case, and tracking breaks the joins between letters,
   so the same rule that reads as "label" in English reads as damage in Arabic.
   Same role, different mechanics. */
html[lang="ar"] .sec-head .eyebrow,
html[lang="ar"] .domain .eyebrow,
html[lang="ar"] .case-body .eyebrow,
html[lang="ar"] .judg-col h3,
html[lang="ar"] .case-field dt{
  font-family:Qomraa,Tajawal,sans-serif;letter-spacing:0;text-transform:none;
  font-size:13px;font-weight:600}


/* --- about ---- */
.about-intro{max-width:calc(62ch * var(--measure));color:var(--mut);font-size:16.5px;line-height:1.75;
  display:flex;flex-direction:column;gap:12px;margin-bottom:32px}
.about-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.about-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:clamp(24px,3vw,36px)}
.about-card h3{font-size:18px;margin:0 0 8px;line-height:1.35}
.about-card p{font-size:14.5px;color:var(--mut);line-height:1.75;margin:0}

/* the hero already ends on the figures rule; it does not need a second gap */
.hero{padding-block-end:0}

/* ==========================================================================
   MOBILE HERO — portrait as a compact headshot above the copy.
   On a phone the full-height portrait consumed half the viewport and pushed
   the proof figures below the fold. Moving it first and shrinking it to a
   100px circle puts a face on the page immediately, gives the headline full
   width, and lets the evidence arrive within one scroll.
   Desktop is untouched: the two-column grid with the large portrait stays.
   ========================================================================== */
@media(max-width:900px){
  .hero-grid .avatar-wrap{order:-1;margin-top:0;margin-bottom:8px}
  .hero-grid .brush-stroke{display:none}
  .hero-grid .portrait{width:100px;max-width:100px;aspect-ratio:1;border-radius:50%;
    border:2px solid var(--teal);box-shadow:var(--sh-1);margin:0;overflow:hidden}
  html[data-portrait="photo"] .hero-grid .portrait{width:100px;max-width:100px}
  .hero-grid .portrait::before{display:none}
  .hero-grid .portrait img{object-position:center 14%}
  html[data-portrait="cut"] .hero-grid .portrait img{object-fit:cover;object-position:center 14%}
  .mostaql-seal{width:52px;height:52px;bottom:auto;top:-4px;inset-inline-end:-4px}
  .mostaql-seal b{font-size:14px}
  .mostaql-seal span{font-size:7.5px}
}

@media(max-width:600px){
  .about-grid{grid-template-columns:1fr}
}


/* the depth chips are labels too: same Arabic treatment as the rest */
html[lang="ar"] .depth li{font-family:Qomraa,Tajawal,sans-serif;letter-spacing:0;font-size:13px}

/* ---- link affordance ---- */
/* Only <a class="btn"> gets it: a submit button navigates nowhere, so an
   external-link arrow on it would be a lie. */
a.btn::before{content:"";order:1;width:.85em;height:.85em;flex:none;background:currentColor;
  -webkit-mask:var(--ico-arrow) center/contain no-repeat;mask:var(--ico-arrow) center/contain no-repeat}
html[dir="rtl"] a.btn::before{transform:scaleX(-1)}
/* the rating widget draws its stars now, so it lays them out as icons */
.stars{display:flex;gap:3px;letter-spacing:normal}
.stars svg{width:14px;height:14px;display:block}

/* ============================================================================
   LATIN TYPE — Instrument Serif for display, Instrument Sans for everything
   else. Space Grotesk and Inter are the two faces that show up on every
   generated site; a serif display reads as writing, which is what the page is
   actually selling.

   Instrument Serif ships one weight, so the display sizes carry their emphasis
   through size and leading instead of weight. Asking the browser for 800 here
   would only get a synthesised bold, which smears a serif's contrast.

   Arabic is unaffected: Qomraa leads every html[lang="ar"] chain and does have
   real weights, so it keeps the heavier setting it was designed around.
   ========================================================================== */
h2{font-weight:600}
.sec-head h2{font-size:clamp(30px,3.4vw,46px);font-weight:600;line-height:1.08;letter-spacing:-.012em}
.cred b{font-weight:600}

.judg-quote{font-family:'Outfit',Qomraa,Tajawal,sans-serif;font-style:normal;font-weight:600;
  font-size:clamp(21px,2.7vw,30px);line-height:1.4;letter-spacing:-.01em}

html[lang="ar"] h2,html[lang="ar"] .sec-head h2{font-weight:800}
html[lang="ar"] .sec-head h2{font-size:clamp(28px,3.2vw,42px);line-height:1.3}
html[lang="ar"] .judg-quote{font-style:normal;font-weight:600;font-size:clamp(19px,2.4vw,26px);line-height:1.45}
html[lang="ar"] .cred b{font-weight:700}


/* --- services -------------------------------------------------------------
   The last uniform card grid on the page. Six equal boxes of label + title +
   text + link is the arrangement that made the rest of the page look generated;
   the depth section and the about list already read as ruled rows, so this one
   joins them. The category stays — unlike the about and domain labels it says
   something the title does not. */
/* --- services chip-row stack --- */
.svc-stack{margin-top:clamp(32px,4vw,48px)}
.svc-row{display:flex;align-items:center;gap:clamp(16px,2.5vw,24px);
  padding:clamp(20px,2.6vw,28px) 0;border-block-start:1px solid var(--line);
  color:inherit;text-decoration:none;transition:background .2s}
.svc-row:last-child{border-block-end:1px solid var(--line)}
.svc-row:hover{background:rgba(var(--teal-rgb),.03)}
.svc-chip{width:48px;height:48px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;
  color:var(--surface)}
.svc-chip svg{width:22px;height:22px}
.svc-chip{background:var(--teal-bright)}
.svc-row:nth-child(2n) .svc-chip{background:var(--amber);color:var(--ink)}
.svc-row:nth-child(3n) .svc-chip{background:var(--coral)}
.svc-content{flex:1;min-width:0}
.svc-content h3{font-size:clamp(17px,1.8vw,21px);margin:0 0 4px;line-height:1.35;transition:color .2s}
.svc-content p{font-size:14.5px;color:var(--mut);line-height:1.75;margin:0;max-width:calc(62ch * var(--measure))}
.svc-row .more{flex:none;display:inline-flex;align-items:center;gap:7px;
  font-size:12.5px;font-weight:600;color:var(--acc);white-space:nowrap;transition:gap .25s var(--ease)}
.svc-row .more::after{content:"";width:.85em;height:.85em;flex:none;background:currentColor;
  -webkit-mask:var(--ico-chevron) center/contain no-repeat;mask:var(--ico-chevron) center/contain no-repeat}
html[dir="rtl"] .svc-row .more::after{transform:scaleX(-1)}
.svc-row:hover .more{gap:11px}
.svc-row:hover .svc-content h3{color:var(--acc)}
@media(max-width:600px){
  .svc-row{flex-wrap:wrap}
  .svc-content{flex-basis:calc(100% - 64px)}
  .svc-row .more{width:100%;padding-inline-start:64px}}

/* ==========================================================================
   MEASURE PARITY — every `ch` cap on this page was tuned against the Latin
   face. Qomraa resolves 1ch at 7.54px where Instrument Sans resolves 10.32px
   at the same 15.5px, so in Arabic each cap came out 27% short of the measure
   it was written for: the service and domain paragraphs stopped 314px inside
   a 782px track, and the stats label wrapped "Google Play" onto three lines
   inside a cell more than twice its width. RTL collects that slack on the
   left, which is what made the ruled rows read as a three-column layout with
   an empty third column.

   A unitless multiplier is the fix rather than a second set of numbers: `ch`
   still resolves per element, so each cap keeps tracking its own font-size,
   and only the family difference is corrected. 10.32 / 7.54 = 1.37.
   ========================================================================== */
:root{--measure:1}
html[lang="ar"]{--measure:1.37}

.sec-head{max-width:calc(64ch * var(--measure))}
.sec-head .sub{max-width:calc(62ch * var(--measure))}
.hero-note{max-width:calc(56ch * var(--measure))}
.step p{max-width:calc(60ch * var(--measure))}
.case-disclosure{max-width:calc(80ch * var(--measure))}
.domain p{max-width:calc(62ch * var(--measure))}
.svc-content p{max-width:calc(62ch * var(--measure))}

/* --- services row: the link ----------------------------------------------
   `.more` sat at grid-row 4 of a two-row grid, so the row grew a pair of
   implicit tracks to reach it, and it still carried the flex-card floor rule
   (`margin-top:auto; padding-top:var(--s6)`) even though this row is a grid.
   That stacked 32px of padding on 18px of margin -- 50px of dead space above
   the link, more than the row's own vertical padding. It also stretched to
   the full 782px track, so the hover target covered the empty half of the row.

   Split by breakpoint because the single-column rule below 760px has to keep
   winning: these declarations are later in the file and would otherwise pull
   the link back into a second column the mobile row does not have.
   ------------------------------------------------------------------------ */

/* --- writing rows ---------------------------------------------------------
   Two blog teaser cards side by side is the last .grid2 .card pair on the
   page. Same ruled-row treatment as services: category label on the leading
   edge, title + blurb + link beside it. */
.writing-rows{margin-top:clamp(32px,4vw,48px)}
.writing-row{display:grid;grid-template-columns:minmax(150px,22%) minmax(0,1fr);
  column-gap:clamp(20px,3.6vw,48px);row-gap:0;align-items:start;
  padding:clamp(22px,2.8vw,32px) 0;border-block-start:1px solid var(--line);
  color:inherit;text-decoration:none}
.writing-row:last-child{border-block-end:1px solid var(--line)}
.writing-row h3{grid-column:1;grid-row:1;margin:0;
  font-size:clamp(18px,2vw,24px);line-height:1.4;transition:color .2s}
.writing-row p{grid-column:2;grid-row:1;margin:0;font-size:15px;
  color:var(--mut);line-height:1.8;max-width:calc(62ch * var(--measure))}
.writing-row .more{grid-column:2;grid-row:2;display:inline-flex;align-items:center;
  gap:7px;margin-top:var(--s4);font-size:12.5px;font-weight:600;color:var(--acc);
  justify-self:start;transition:gap .25s var(--ease)}
.writing-row .more::after{content:"";width:.85em;height:.85em;flex:none;
  background:currentColor;
  -webkit-mask:var(--ico-chevron) center/contain no-repeat;
  mask:var(--ico-chevron) center/contain no-repeat}
html[dir="rtl"] .writing-row .more::after{transform:scaleX(-1)}
.writing-row:hover h3{color:var(--acc)}
.writing-row:hover .more{gap:11px}
.writing-row:focus-visible{outline:2px solid var(--focus);outline-offset:4px;border-radius:2px}
@media(max-width:760px){
  .writing-row{grid-template-columns:1fr}
  .writing-row h3,.writing-row p,
  .writing-row .more{grid-column:1;grid-row:auto}
  .writing-row p{margin-top:10px}}

/* ==========================================================================
   PROOF LEDGER — the three figures under the hero.

   Replaces `.stats`/`.stat`, which had accumulated six layers of overrides
   (card grid -> dark badge pills -> ruled cells) still arguing with each
   other: a box-shadow cast by a background-less element, an underline that
   marked two of three labels, a 4-column template a 3-column one had to undo.
   All of it is retired -- these are the only rules the band has now.

   The arrangement is a ledger rather than a row of figures because two of the
   three facts can be checked and one cannot. Naming the destination on the
   trailing edge makes that difference visible instead of hiding it in an
   underline: "8+ years" has no source, so its row carries no tag and is not a
   link. The tag names where the reader lands, not where the claim came from --
   an arrow that promises mostaql.com has to arrive at mostaql.com.
   ========================================================================== */
/* LEDGER BAND — mustard field, oversized numerals, icon chips */
.ledger-band{background:var(--amber);margin-top:clamp(48px,6vw,80px);
  padding:clamp(36px,5vw,64px) 0;position:relative;z-index:3;
  opacity:0;transform:translateY(16px);transition:opacity .5s var(--ease),transform .5s var(--ease)}
.ledger-band.in{opacity:1;transform:none}
.ledger{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(24px,3vw,48px)}
.ledger-row{display:flex;flex-direction:column;gap:4px;
  color:var(--ink);text-decoration:none;border-radius:8px;transition:background .2s}
.ledger-row + .ledger-row{border-inline-start:1px solid rgba(var(--ink-rgb),.15);
  padding-inline-start:clamp(24px,3vw,48px)}

.ledger-icon{display:grid;place-items:center;width:40px;height:40px;
  border-radius:50%;background:rgba(var(--ink-rgb),.1);color:var(--ink);margin-bottom:8px}
.ledger-icon svg{width:22px;height:22px}

.ledger .fig{
  font-family:'Outfit','Instrument Sans',system-ui,sans-serif;font-weight:700;
  font-size:clamp(44px,5.5vw,72px);line-height:1;letter-spacing:-.02em;
  color:var(--ink);direction:ltr;unicode-bidi:isolate;
  align-self:start;margin-bottom:2px;
  font-variant-numeric:tabular-nums}
html[lang="ar"] .ledger .fig{font-family:Qomraa,Tajawal,sans-serif;font-weight:800;
  font-size:clamp(40px,5vw,64px)}

.ledger-claim{color:var(--ink);opacity:.78;font-size:14px;line-height:1.55}

.ledger-src{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  font-family:var(--mono);font-size:11.5px;color:var(--ink);opacity:.5;
  unicode-bidi:isolate;transition:opacity .2s var(--ease);margin-top:2px;
  text-decoration:underline;text-decoration-color:transparent;
  text-underline-offset:3px;transition:opacity .2s,text-decoration-color .2s}
html[lang="ar"] .ledger-src{font-family:Qomraa,Tajawal,sans-serif;letter-spacing:.04em}
.ledger-src::after{content:"";width:.7em;height:.7em;flex:none;background:currentColor;
  -webkit-mask:var(--ico-arrow) center/contain no-repeat;
  mask:var(--ico-arrow) center/contain no-repeat}
html[dir="rtl"] .ledger-src::after{transform:scaleX(-1)}

a.ledger-row:hover .ledger-src{opacity:.85;text-decoration-color:currentColor}
a.ledger-row:hover .ledger-claim{opacity:1}
a.ledger-row:focus-visible{outline:2px solid var(--ink);outline-offset:6px;border-radius:8px}
a.ledger-row:focus-visible .ledger-src{opacity:.85}

@media(max-width:700px){
  .ledger{grid-template-columns:1fr}
  .ledger-row + .ledger-row{border-inline-start:0;padding-inline-start:0;
    border-block-start:1px solid rgba(var(--ink-rgb),.15);padding-block-start:clamp(18px,4vw,24px)}}
@media(prefers-reduced-motion:reduce){
  .ledger-band{opacity:1;transform:none;transition:none}}

/* --- case study: the engineering half, on request -------------------------
   Every case carries the eight fields PRODUCT.md's contract requires, but a
   founder scanning three of them met 24 blocks of dense text before reaching
   the contact form. The three a buyer actually reads stay open — the problem,
   the weakness that was found, the supported result. The five that answer
   "how" fold into this disclosure.

   Nothing is removed and nothing is hidden from a crawler: <details> keeps its
   content in the DOM, and it is keyboard-reachable and announced without any
   script. The marker is drawn from the existing chevron token so it mirrors in
   RTL like every other affordance on the page. */
.case-deep{margin-block-start:14px}
.case-deep > summary{display:flex;align-items:center;gap:10px;cursor:pointer;
  list-style:none;padding:10px 14px;border-radius:var(--r-sm);
  background:rgba(var(--teal-rgb),.06);border:1px solid rgba(var(--teal-rgb),.15);
  transition:background .2s,border-color .2s;min-height:44px}
.case-deep > summary:hover{background:rgba(var(--teal-rgb),.10);border-color:rgba(var(--teal-rgb),.25)}
.case-deep > summary::-webkit-details-marker{display:none}
.case-deep-label{font-size:13.5px;font-weight:600;color:var(--acc)}
html[lang="ar"] .case-deep-label{font-family:Qomraa,Tajawal,sans-serif}
.case-deep-chevron{width:18px;height:18px;flex:none;margin-inline-start:auto;
  background:var(--acc);transition:transform .25s var(--ease);
  -webkit-mask:var(--ico-chevron) center/contain no-repeat;
  mask:var(--ico-chevron) center/contain no-repeat;transform:rotate(90deg)}
.case-deep[open] .case-deep-chevron{transform:rotate(-90deg)}
.case-deep > summary:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
/* the fields inside keep the grid they have in the open part of the card */
.case-deep .case-field{margin-block-start:14px}
.case-deep .case-field:first-of-type{margin-block-start:8px}

/* --- other work -----------------------------------------------------------
   Seven projects that do not get the full inline treatment. A real grid, not
   the single stacked column .casewall is: at this size the cards are meant to
   be scanned against each other, not read one after another. */
.more-work{margin-top:clamp(44px,5vw,72px)}
.more-head{max-width:70ch}
.more-head h3{font-size:clamp(17px,1.7vw,20px);margin:0 0 8px}
.more-head p{margin:0;color:var(--mut);font-size:14.5px;line-height:1.8}
.casewall-more{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
  gap:clamp(16px,1.8vw,24px);margin-top:clamp(22px,2.6vw,32px)}
.case-sm{display:flex;flex-direction:column;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--card);overflow:hidden}
.case-sm-shot{display:block;background:var(--card2)}
.case-sm-shot img{display:block;width:100%;height:auto;aspect-ratio:16/10;
  object-fit:cover;object-position:top}
.case-sm-body{display:flex;flex-direction:column;gap:10px;flex:1;padding:20px 22px 22px}
/* No screenshot: an accent rule stands in for the image edge, so a type-only
   card still reads as a card rather than as a truncated one. */
.case-sm--type .case-sm-body{border-block-start:2px solid rgba(var(--acc-rgb),.4)}
.case-sm h4{font-size:16.5px;line-height:1.45;margin:0}
.case-sm h4 a{color:inherit;text-decoration:none}
.case-sm h4 a:hover{color:var(--acc)}
.case-sm h4 a:focus-visible{outline:2px solid var(--acc);outline-offset:3px;border-radius:2px}
.case-sm p{margin:0;color:var(--mut);font-size:14px;line-height:1.75}
.case-sm-tags{display:flex;flex-wrap:wrap;gap:6px;margin:auto 0 0;padding:6px 0 0;list-style:none}
.case-sm-tags li{font-family:var(--mono);font-size:11px;color:var(--acc2);
  border:1px solid var(--line);border-radius:999px;padding:3px 9px;white-space:nowrap}
/* Says the quiet part on the card: this one cannot be checked from outside. */
.case-sm-tags li.case-sm-unsourced{color:var(--mut);border-style:dashed;font-family:inherit;font-size:12.5px}
@media(max-width:600px){.casewall-more{grid-template-columns:1fr}}

/* coloured plates for type-only cards — rotate through accent fills */
.case-sm-plate{display:flex;align-items:center;justify-content:center;
  aspect-ratio:16/10;padding:18px 22px}
.case-sm-plate span{font-family:var(--mono);font-size:clamp(12px,1.15vw,14px);
  line-height:2;text-align:center;opacity:.9}
.case-sm--type .case-sm-body{border-block-start:0}
.case-sm--type:nth-child(3n+1) .case-sm-plate{background:var(--teal);color:#fff}
.case-sm--type:nth-child(3n+1) .case-sm-plate span{color:#fff}
.case-sm--type:nth-child(3n+2) .case-sm-plate{background:var(--amber);color:var(--ink)}
.case-sm--type:nth-child(3n+2) .case-sm-plate span{color:var(--ink)}
.case-sm--type:nth-child(3n) .case-sm-plate{background:var(--coral);color:#fff}
.case-sm--type:nth-child(3n) .case-sm-plate span{color:#fff}

/* Hidden over the hero: fixed at the bottom of a phone viewport it lands on
   the hero's secondary CTA. Revealed with the back-to-top button instead. */
.ai-fab{opacity:0;pointer-events:none;transform:translateY(10px);
  transition:opacity .3s var(--ease),transform .3s var(--ease)}
.ai-fab.show{opacity:1;pointer-events:auto;transform:none}
@media(prefers-reduced-motion:reduce){.ai-fab{transition:none}}
