/* ============================================================================
   IBIX base — the non-negotiables, pre-solved.
   Start every new client site with this file, then layer the site's own theme
   on top. Every rule here exists because its absence shipped a real bug on a
   real client site; the comment names which one. Don't delete a rule without
   reading its comment.

   Pair it with the guardrail check:   python "IBIX Studio/qa/qa.py" <url>
   ========================================================================= */

/* --- reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box }
* { margin: 0; padding: 0 }

/* `height:auto` is load-bearing. An <img> carrying width/height attributes
   (good practice for CLS) whose only CSS is max-width:100% renders VERTICALLY
   STRETCHED below its natural width — object-fit defaults to `fill`, so a
   1280x720 photo draws as 350x720 on a phone. Desktop looks perfect, which is
   why it hides for weeks. Ajyal fleet photo + East Hope, both owner-caught. */
img, video, svg { max-width: 100%; height: auto; display: block }

/* Scoped rules that set an explicit height (cover-fit heroes, logo tiles) are
   more specific and still win — that is intentional. */

input, button, textarea, select { font: inherit; color: inherit }
a { color: inherit; text-decoration: none }

/* --- layout safety -------------------------------------------------------- */

/* No horizontal scroll at ANY width. Wide things scroll inside their own box. */
html { overflow-x: hidden }
body { overflow-x: hidden; -webkit-font-smoothing: antialiased }
table, pre { max-width: 100% }
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch }

/* NEVER style bare landmarks — a page has more than one <nav>, <header>,
   <footer>, <section>. `nav{position:fixed}` on IBIX's own site also hit the
   FOOTER's <nav class="footer-links"> and pinned it to the top of the viewport.
   Scope to an id/class instead. This comment is the rule; there is deliberately
   no `nav{}` block here. */

/* A portable component must reset its own landmarks so it survives being
   dropped into a page whose CSS you haven't audited. */
#site-footer nav { max-width: none; margin: 0; padding: 0; display: block }

/* --- controls ------------------------------------------------------------- */

/* A header CTA that wraps to two lines grows taller than the fixed nav row, so
   it stops matching its neighbours and reads as "misaligned and a different
   size" — the owner's exact words on East Hope. The cause is the wrap, not the
   alignment. nowrap is the fix, and it belongs in the BASE rule. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  white-space: nowrap; line-height: 1.15; cursor: pointer;
  border: 1.5px solid transparent; transition: .18s;
}

/* Full-screen hero headline: size it by the SMALLER of viewport width AND height.
   A width-only headline (e.g. font-size:12vw) grows so tall on a wide-but-short
   laptop that it pushes the sub-head + CTA below the fold — the hero looks broken
   and the primary button disappears (Ajyal immersive demo; qa.py `hero-fit` catches
   it). The min(_vw,_vh) makes it stay dramatic on tall screens but fit short ones.
   Use .hero-display on the headline, or copy the min() pattern with your own values. */
.hero-display { font-size: clamp(2.5rem, min(11vw, 15vh), 8rem); line-height: .98 }
/* and trim a 100vh hero's vertical padding on short laptops so the CTA stays visible */
@media (max-height: 820px) {
  .hero-fit-pad { padding-top: clamp(80px, 12vh, 120px); padding-bottom: clamp(28px, 5vh, 60px) }
}

/* WCAG 2.2 AA (2.5.8) target size. Cheap to honour, awkward to retrofit. */
@media (hover: none) and (pointer: coarse) {
  a, button, [role="button"], input[type="submit"] { min-height: 24px }
  /* Only ever set `cursor` in a blanket a,button rule. Setting
     `pointer-events:auto` here re-enables links inside CLOSED overlays
     (opacity:0 + pointer-events:none), creating invisible tap targets that
     open random pages. IBIX shipped exactly that for weeks. */
  * { -webkit-tap-highlight-color: transparent }
}

/* Note the SPACES in the media query above: writing the combinator "and" with
   NO space before the next "(" makes the whole query DEAD in every browser —
   the parser reads it as a function token. IBIX's tablet layout silently never
   applied for months. (Described in words so this comment can never
   false-positive qa.py's dead-query scan when the file is inlined.) */

/* --- degradation: never ship a blank page --------------------------------- */

/* Reveal-on-scroll hides content until JS runs. Gate it on html.js (set by a
   pre-paint inline script) so that if JS is off, blocked, or main.js 404s, the
   content is simply visible instead of the whole page being blank.
   Put this in <head> of every page, BEFORE the stylesheet:
       <script>document.documentElement.classList.add('js');</script> */
html.js .reveal { opacity: 0; transform: translateY(18px); transition: .6s ease }
html.js .reveal.in { opacity: 1; transform: none }

/* Reduced-motion users must SEE the content, not a blank page. Both selectors
   are listed because `html.js .reveal` (0,2,0) outranks a bare `.reveal`
   (0,1,0) — gating the hide silently disabled this override on East Hope. */
@media (prefers-reduced-motion: reduce) {
  html.js .reveal, .reveal { opacity: 1; transform: none; transition: none }
  html { scroll-behavior: auto }
  *, *::before, *::after { animation-duration: .001ms !important;
    animation-iteration-count: 1 !important; transition-duration: .001ms !important }
}

/* Belt and braces for the no-JS case: in every page's <head>, wrap the rule
   .reveal{opacity:1!important;transform:none!important} in noscript+style tags.
   (Spelled out in WORDS on purpose — a literal closing style tag inside this
   comment TERMINATES the <style> element whenever this file is inlined into a
   single-file build, spilling the rest of the stylesheet onto the page as
   visible text. Found live on the ACME demo build 2026-07-26.) */

/* --- mobile menu scroll lock ---------------------------------------------- */

/* `body{overflow:hidden}` is a NO-OP on any site with `html{overflow-x:hidden}`
   — per CSS overflow propagation the viewport takes its scrolling from the root,
   and body's overflow is only propagated when html computes to `visible`. The
   class applies, and nothing happens. This position-fixed lock is the only one
   that works here AND on iOS Safari. Drive it from JS: store scrollY, set
   body.style.top = -y, restore with scrollTo(0, y) on release. Use an
   owner-keyed lock (lock('menu') / lock('about')) — one overlay opening from
   another otherwise strands the lock forever. */
body.scroll-locked { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden }

/* --- cross-browser -------------------------------------------------------- */

/* Safari needs the -webkit- twin or the effect silently does nothing. */
.glass {
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
          backdrop-filter: blur(14px) saturate(1.2);
}
/* Blur is expensive: a grid of many blurred panels janks mid-range Android,
   which is what Gulf clients actually browse on. Drop it at phone widths. */
@media (max-width: 720px) {
  .glass { -webkit-backdrop-filter: none; backdrop-filter: none }
}
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .glass { background-color: rgba(20, 52, 79, .82) }
}

/* Firefox ignores ::-webkit-scrollbar entirely — ship both. On a light design a
   default scrollbar reads as a "dark strip" bug to clients, so style it. */
html { scrollbar-width: thin; scrollbar-color: #CBC4B8 transparent }
::-webkit-scrollbar { width: 11px; height: 8px }
::-webkit-scrollbar-thumb { background: #CBC4B8; border-radius: 9px }

/* Decorative fixed canvases NEVER take pointer events — a fixed canvas never
   scrolls away, so it floats over every section and swallows taps in dead
   zones, sending users to random pages. */
canvas[data-decorative] { pointer-events: none }

/* --- RTL / bilingual ------------------------------------------------------ */

/* letter-spacing breaks Arabic letter joining outright. */
[dir="rtl"] * { letter-spacing: normal !important }
/* Latin display faces (Bebas, Archivo, Saira) have NO Arabic glyphs, so Arabic
   headings silently fall back to an ugly default. Same trap for Cyrillic. */
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3 { font-family: var(--body) }
/* Carousel tracks need LTR geometry with RTL content inside. */
[dir="rtl"] .carousel-track { direction: ltr }

/* --- print ---------------------------------------------------------------- */
@media print {
  .no-print, .wa-float, .cookie-banner { display: none !important }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em }
}
