/* ==========================================================================
   Nutricare — stylesheet
   --------------------------------------------------------------------------
   Contents
     1.  Design tokens
     2.  Base & resets
     3.  Layout helpers
     4.  Buttons & links
     5.  Header & navigation
     6.  Hero
     7.  Cards (range + channels)
     8.  How to order (steps, ops rows)
     9.  Bands (brand owners, shoppers)
     10. Contact, trade info & form
     11. Footer
     12. Floating WhatsApp button
     13. Motion
     14. Responsive
   ========================================================================== */


/* ==========================================================================
   1. Design tokens
   --------------------------------------------------------------------------
   COLOUR RULE:  Ink = structure.  Green = action.
                 If something is green, it should be clickable.
                 Blue and yellow are accents only — they classify, they
                 never invite a click, or the rule stops meaning anything.

   Every value below was sampled from the logo's own pixels and then checked
   for contrast. Two results drove the palette:

     • The brand green #04C903 carries WHITE text at only 2.24:1 — far below
       the 4.5:1 minimum. Rather than muddying the green to a dull #038A02
       so white would pass, buttons use INK on the true brand green, which
       measures 8.13:1. The logo colour survives and the contrast is better.

     • The wordmark's own text is #151517, so --ink is the logo's black, not
       an invented one.
   ========================================================================== */
:root {
  /* Brand — measured from assets/images/source/ */
  --green:       #04C903;   /* the logo green — accents, rules, tints               */
  --green-btn:   #038A02;   /* PRIMARY BUTTON FILL — white on it is 4.53:1, passes AA */
  --green-deep:  #026E01;   /* primary button hover — white on it is 6.50:1          */
  --green-ink:   #037A02;   /* green TEXT on light backgrounds      5.4:1  vs white */
  --green-light: #6EE86C;   /* green text on dark backgrounds                       */
  --green-tint:  #E9FBE7;   /* soft green ground                                    */

  --blue:        #00A8FB;   /* accent only — classifies food categories */
  --blue-ink:    #006FA8;
  --blue-tint:   #E4F5FE;

  --yellow:      #FCD400;   /* accent only — classifies non-food categories */
  --yellow-ink:  #7A6600;
  --yellow-tint: #FFF6D6;

  --wa:          #25D366;   /* WhatsApp brand green — ink on it is 9.19:1 */
  --wa-fab:      #159B47;   /* floating button fill — WHITE on it is 3.61:1  */

  /* Neutrals */
  --ink:         #151517;   /* headings and structure — the wordmark's own black */
  --ink-soft:    #2B2E31;
  --white:       #FFFFFF;
  --off-white:   #F5F8F5;
  --gray:        #5A6069;   /* body copy                            6.34:1 vs white */
  --gray-strong: #454B53;
  --border:      #E3E7E3;
  --foot-text:   #A8AEB4;   /* on --ink                             8.14:1          */

  /* Type scale */
  --t-hero:  clamp(1.95rem,  4.3vw, 2.8rem);
  --t-h2:    clamp(1.55rem, 3.4vw, 2.25rem);
  --t-h3:    clamp(1.05rem, 1.7vw, 1.22rem);
  --t-lead:  clamp(1rem,    1.5vw, 1.1rem);

  --radius:    16px;
  --radius-sm: 11px;
  --shadow:    0 6px 26px rgba(21, 21, 23, 0.07);
  --shadow-lg: 0 16px 48px rgba(21, 21, 23, 0.13);
  --maxw:      1160px;
  --pad:       clamp(20px, 5vw, 64px);
  --header-h:  76px;
}


/* ==========================================================================
   2. Base & resets
   ========================================================================== */
* { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 12px);
}

/* Inter carries no Arabic glyphs. Listing IBM Plex Sans Arabic AFTER it means
   the browser takes each character from the first family that has it: Latin
   and digits from Inter, Arabic from Plex. One stack, no [dir] switch, and a
   mixed line — "Nutricare موزّع" — keeps both scripts in their proper face.

   main.js only fetches the Plex stylesheet when Arabic is selected, so an
   English visitor never pays for a font this stack never reaches. The named
   fallbacks after it are what an Arabic reader sees for the moment before it
   arrives; Segoe UI and Arial both carry Arabic, and Tahoma is the last
   resort that every Windows machine has. */
body {
  font-family: 'Inter', 'IBM Plex Sans Arabic', 'Segoe UI', Roboto, Tahoma, Arial, sans-serif;
  color: var(--gray);
  background: var(--white);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a  { text-decoration: none; color: inherit; }
ul { list-style: none; }

h1, h2, h3, h4 { color: var(--ink); line-height: 1.22; }

/* height:auto matters: the width/height attributes on an <img> act as a CSS
   height unless this overrides them, which stretches any image whose CSS
   width is set. The attributes stay in the HTML because the browser uses
   them to reserve the right space before the file loads. */
img { max-width: 100%; height: auto; display: block; }

/* ---------------------------------------------------------------------------
   THIS RULE HOLDS THE WHOLE hide-when-empty ARCHITECTURE UP. DO NOT REMOVE.

   The browser's own [hidden] rule is `display: none` at the lowest priority,
   so ANY author rule that sets a display value beats it. .btn is inline-flex
   and .contact-item is flex, which means <a class="btn" hidden> stays fully
   visible — an empty WhatsApp button rendering as a live control when
   site.json has no number in it.

   Measured before this rule existed: .btn rendered 157x52 and .contact-item
   870x53, both carrying the hidden attribute.
   tests/audit.js fails the build if this regresses.
   --------------------------------------------------------------------------- */
[hidden] { display: none !important; }

/* Numbers stay left-to-right so they can be copied into a dialer. */
.ltr { direction: ltr; unicode-bidi: isolate; }

/* ---------------------------------------------------------------------------
   ARABIC / RTL

   Almost nothing is needed here, and that is on purpose: the whole stylesheet
   is written in LOGICAL properties — margin-inline-start, inset-inline-end,
   padding-inline — which flip themselves when <html dir> changes. If you add
   a rule, write it the same way. `margin-left` is the bug; `margin-inline-start`
   is the fix, and it costs nothing in English.

   What is left below is the handful of things a logical property cannot
   describe: a glyph that points somewhere, and Arabic's heavier line.
   --------------------------------------------------------------------------- */

/* Arabic sits taller in the em box than Latin and its descenders run deeper,
   so at Inter's line-height the lines nearly touch. Headings feel it most. */
[dir="rtl"] body            { line-height: 1.85; }
[dir="rtl"] h1,
[dir="rtl"] h2,
[dir="rtl"] h3,
[dir="rtl"] h4              { line-height: 1.45; }
/* Plex Arabic has no 800, and Arabic at 800 would synthesise a smeared bold
   even where a face has it. 700 is the top weight on the Arabic page. */
[dir="rtl"] h1, [dir="rtl"] .h2, [dir="rtl"] .h3 { font-weight: 700; }

/* An arrow means "onward", and onward is leftward in Arabic. Mirroring the
   glyph is right where translating it would be nonsense — these are the only
   directional glyphs on the site. The chevrons (the scroll cue, the select)
   point DOWN and must not be touched. */
[dir="rtl"] .card-go svg,
[dir="rtl"] .text-link svg  { transform: scaleX(-1); }
/* …which means the hover nudge travels the other way too. The card moves the
   whole .card-go, so it just needs a negative offset; .text-link moves the
   glyph itself, so its rule has to carry the flip along or the arrow snaps
   back to pointing right the moment the pointer lands on it. */
[dir="rtl"] .card:hover .card-go  { transform: translateX(-3px); }
[dir="rtl"] .text-link:hover svg  { transform: scaleX(-1) translateX(3px); }

/* The phone field is a printed +974 followed by an 8-digit box, and a phone
   number reads left-to-right in Arabic as much as in English. Left alone, RTL
   puts the country code on the right of the digits it belongs in front of. */
[dir="rtl"] .input-prefix { direction: ltr; }

:focus-visible {
  outline: 3px solid var(--green-ink);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: fixed;
  /* Logical, so on the Arabic page it parks off the RIGHT edge and slides in
     from the right — off-screen at `left` in RTL is the wrong side twice
     over: it travels the length of the viewport to arrive. */
  inset-inline-start: -9999px;
  top: 0;
  z-index: 200;
  background: var(--ink);
  color: var(--white);
  padding: 12px 20px;
  border-radius: 0 0 var(--radius-sm) 0;
  font-weight: 600;
}
.skip-link:focus { inset-inline-start: 0; }

.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;
}


/* ==========================================================================
   3. Layout helpers
   ========================================================================== */
.wrap    { max-width: var(--maxw); margin-inline: auto; }
.section { padding: clamp(52px, 6.4vw, 84px) var(--pad); position: relative; }
.tinted  { background: var(--off-white); }

.eyebrow {
  display: inline-block;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--green-ink);
  background: var(--green-tint);
  padding: 6px 15px;
  border-radius: 30px;
  margin-bottom: 16px;
}

.h2   { font-size: var(--t-h2); font-weight: 800; letter-spacing: -.02em; }
.h3   { font-size: var(--t-h3); font-weight: 700; }
.lead { font-size: var(--t-lead); max-width: 66ch; margin-top: 14px; }

.section-head { text-align: center; margin-bottom: clamp(28px, 3.4vw, 42px); }
.section-head .lead { margin-inline: auto; max-width: 52ch; }

.section-cta { text-align: center; margin-top: clamp(32px, 4vw, 48px); }


/* ==========================================================================
   4. Buttons & links
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 14px 28px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: .95rem;
  font-weight: 700;
  line-height: 1.4;
  cursor: pointer;
  white-space: nowrap;
  /* ONE size. There was a .btn-lg variant on the hero, the brand band and the
     form submit, so the same call to action was three different heights down
     one page. There are exactly two button styles on this site — filled
     primary and outlined secondary — at one size, and no third. Do not add a
     size modifier back.

     No coloured drop shadow and no hover lift. A glow under a solid fill
     reads as a 2015 button; the state change is carried by colour alone. */
  transition: background-color .18s ease, box-shadow .18s ease, color .18s ease;
}
.btn svg { width: 19px; height: 19px; flex: none; }
.btn:active { transform: translateY(1px); }

/* White label, so the fill has to be the darkened green: white on the logo's
   own #04C903 measures 2.24:1, which is unreadable and fails AA outright.
   #038A02 is the lightest green that carries white at 4.5:1, and hover goes
   darker still rather than lighter. The logo green itself is untouched —
   it stays on the accents, tints and rules everywhere else on the page. */
.btn-primary {
  background: var(--green-btn);
  color: var(--white);
}
.btn-primary:hover { background: var(--green-deep); }

/* Secondary by design. Two solid green buttons side by side in the hero
   carried equal weight, so neither led — and once the primary took a white
   label the two fills clashed as well. WhatsApp green cannot carry white
   (1.98:1), so this is an outlined button with the brand green on the icon
   only: the channel is still recognisable, the hierarchy is not. */
.btn-wa {
  background: var(--white);
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--border);
}
.btn-wa svg { color: var(--wa); }
.btn-wa:hover {
  background: var(--off-white);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}

.btn[disabled] { opacity: .6; pointer-events: none; }

/* Green text link — the only non-button green, and still clickable. */
.text-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--green-ink);
  font-weight: 700;
  font-size: .95rem;
  padding: 8px 0;
}
.text-link svg { width: 17px; height: 17px; transition: transform .18s ease; }
.text-link:hover svg { transform: translateX(3px); }


/* ==========================================================================
   5. Header & navigation
   ========================================================================== */
/* FIXED, not sticky. A sticky header holds its own row in the flow, so the
   strip behind it is the body background — plain white — and the hero's
   colour could only ever start below it. Fixed lifts it out of the flow and
   the hero runs the full height of the window underneath, which is what lets
   the gradient read behind the nav.

   The hero pays for the space it no longer occupies with its own padding-top;
   see section 6. */
header {
  position: fixed;
  top: 0;
  inset-inline: 0;
  z-index: 100;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .25s ease, border-color .25s ease,
              box-shadow .25s ease, backdrop-filter .25s ease;
}

/* main.js adds .scrolled past 8px. Only then does the bar get a surface —
   before that it is a row of controls floating on the hero. */
header.scrolled {
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--border);
  box-shadow: 0 2px 14px rgba(21, 21, 23, .05);
}

/* The open mobile menu needs a surface behind the burger even at scroll 0,
   or the bar reads as detached from the panel hanging off it. */
header:has(#navLinks.open) {
  background: var(--white);
  border-bottom-color: var(--border);
}

/* Every section is a full-bleed box with `padding: … var(--pad)` and a
   `max-width: var(--maxw)` child, so its CONTENT measures --maxw. The nav put
   --maxw on the padded box itself, making its content --maxw minus two pads —
   up to 128px narrower than everything below it, with the logo visibly inset
   from the section edges. Adding the padding back to the cap lines them up. */
.nav {
  max-width: calc(var(--maxw) + 2 * var(--pad));
  margin-inline: auto;
  min-height: var(--header-h);
  padding-inline: var(--pad);
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 24px);
}

.brand { flex: none; padding-block: 6px; display: flex; }
/* The wordmark asset is trimmed to its ink, so this height is the height the
   logo actually appears at — no transparent padding inflating the box, which
   is why 36px here is genuinely 36px of logo. */
.brand img { height: 36px; width: auto; }

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.2vw, 28px);
  margin-inline-start: auto;
}

/* Desktop keeps its CTA in .nav-actions; this one only exists for the open
   mobile menu, where the bar itself has no room for a full-width button. */
.nav-menu-cta { display: none; }
/* :not(.btn) throughout — the menu panel contains a real button as well as
   links, and `.nav-links a` is specific enough to override .btn-primary's own
   colour and padding if it is allowed to match it. */
.nav-links a:not(.btn) {
  font-size: .92rem;
  font-weight: 600;
  color: var(--ink-soft);
  position: relative;
  padding-block: 6px;
}
.nav-links a:not(.btn)::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  bottom: 0;
  height: 2px;
  width: 0;
  background: var(--green);
  transition: width .22s ease;
}
.nav-links a:not(.btn):hover { color: var(--ink); }
.nav-links a:not(.btn):hover::after { width: 100%; }

.nav-actions { display: flex; align-items: center; gap: 12px; flex: none; }

/* LANGUAGE SWITCH.

   Deliberately NOT a .btn. There are exactly two button styles on this site,
   filled primary and outlined secondary, and both mean "act now" — a third
   pill in the header would compete with the one call to action standing
   beside it. This is a quiet control that changes how the page is read, so
   it is weighted like a nav link and given an outline only to say it is
   pressable rather than another word in the menu.

   No flag icon, ever. A flag is a country, not a language: Arabic is not
   Saudi Arabia's, and English is neither Britain's nor America's. The
   language's own name in its own script is the only label that cannot be
   misread — which is also why the button carries a `lang` attribute, so the
   Arabic word on the English page is spoken and set in Arabic.

   min-height 40px with the 44px tap target coming from the padded row it
   sits in; on a phone the bar itself gives it the full height. */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 6px 14px;
  border: 0;
  box-shadow: inset 0 0 0 1.5px var(--border);
  border-radius: 999px;
  background: transparent;
  /* --ink-soft on white is 13.4:1; it stays over the hero gradient too,
     which is held under ~5% saturation for exactly this reason. */
  color: var(--ink-soft);
  font: inherit;
  font-size: .86rem;
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .18s ease, box-shadow .18s ease, color .18s ease;
}
.lang-toggle:hover {
  color: var(--ink);
  background: var(--white);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}
.lang-toggle:active { transform: translateY(1px); }
/* Arabic at .86rem is noticeably smaller on the page than Latin at the same
   size — the script carries its weight lower and needs the extra fraction to
   read as an equal peer of the nav links rather than as fine print. */
.lang-toggle[lang="ar"] { font-size: .95rem; }

/* No filled chip behind it. The bar is transparent over the hero gradient,
   so a grey rounded square read as a button pasted onto the page rather than
   part of the nav. Bars only; the 44px box is kept for the tap target. */
.burger {
  display: none;
  width: 44px; height: 44px;
  border: 0;
  border-radius: 11px;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  padding: 13px 8px;
  flex-direction: column;
  justify-content: space-between;
  transition: background-color .18s ease;
}
.burger:hover { background: rgba(21, 21, 23, .05); }
.burger span {
  display: block; height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .24s ease, opacity .18s ease;
}
.burger.open span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.burger.open span:nth-child(2) { opacity: 0; }
.burger.open span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }


/* ==========================================================================
   6. Hero
   --------------------------------------------------------------------------
   HEIGHT MODEL — read this before changing it.

     min-height: min(calc(100svh - var(--header-h)), 860px)

   It fills the viewport on a laptop, and stops asking for more than 860px on
   a tall desktop monitor where a truly full-height hero just pushes the
   product grid off the screen.

   It is a MIN-height with min() inside, never a max-height. A max-height on a
   box containing text is a clipping bug waiting for the first visitor with a
   larger font size or a longer translation: the box stops growing and the
   copy is cut off. This construct can only ever grow.

   `svh` is the *small* viewport height — the height with the mobile browser's
   toolbars showing. Using `vh` here means the hero is taller than the visible
   area on a phone until the user scrolls, so the CTA starts below the fold.
   The `vh` line above it is the fallback for browsers without `svh`.
   ========================================================================== */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: grid;
  grid-template-rows: 1fr auto;
  min-height: 100vh;
  min-height: min(100svh, 900px);   /* same rule at every width, phones included */
  /* The header is fixed, so the hero starts at y=0 and reserves the bar's
     height itself. Without this the headline sits under the nav. */
  padding: calc(var(--header-h) + clamp(24px, 4vw, 48px)) var(--pad) clamp(20px, 3vw, 32px);
  background: var(--white);
}

/* --- Background ----------------------------------------------------------
   Four layers, painted bottom to top:
     1. a barely-there diagonal tint, so the ground is not flat white
     2. green, sitting where the logo mark sits — it lights the mark from
        behind instead of the hard white disc that used to be drawn there
     3. blue, low and left, weighting the opposite corner
     4. yellow, top right, the logo's third colour, faintest of the three

   Each field drifts on a different period (22s / 26s / 30s) so the
   composition never returns to the same arrangement twice.

   The tints are deliberately kept under about 5% saturation. `.hero` itself
   stays a solid `var(--white)`, which is what lets the contrast audit resolve
   a real background colour for every text node in the hero rather than
   reporting it as an unmeasurable gradient.
   ------------------------------------------------------------------------ */
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    linear-gradient(158deg,
      rgba(233, 251, 231, .55) 0%,
      rgba(255, 255, 255, 0)   38%,
      rgba(255, 255, 255, 0)   62%,
      rgba(228, 245, 254, .55) 100%);
}
.hero-bg span {
  position: absolute;
  display: block;
  border-radius: 50%;
  will-change: transform;
}

/* Centred on the mark. This is the glow the disc was faking.
   The three fields are placed with LOGICAL offsets so they mirror with the
   page: in Arabic the hero grid reverses and the mark moves to the left, and
   a green glow left behind on the right would be an unexplained blob sitting
   over the headline. */
.hb-green {
  top: 6%; inset-inline-end: 8%;
  width: 46%; aspect-ratio: 1;
  background: radial-gradient(circle,
    rgba(4, 201, 3, .28) 0%, rgba(4, 201, 3, .11) 45%, rgba(4, 201, 3, 0) 72%);
  animation: heroDriftA 22s ease-in-out infinite alternate;
}
.hb-blue {
  bottom: -12%; inset-inline-start: -10%;
  width: 48%; aspect-ratio: 1;
  background: radial-gradient(circle,
    rgba(0, 168, 251, .20) 0%, rgba(0, 168, 251, 0) 70%);
  animation: heroDriftB 26s ease-in-out infinite alternate;
}
.hb-warm {
  top: -20%; inset-inline-end: 2%;
  width: 32%; aspect-ratio: 1;
  background: radial-gradient(circle,
    rgba(252, 212, 0, .13) 0%, rgba(252, 212, 0, 0) 70%);
  animation: heroDriftC 30s ease-in-out infinite alternate;
}

/* Masked to fade OUT under the middle of the hero, so the grid textures the
   edges and never sits behind the headline. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(21, 21, 23, .06) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 62% 58% at 46% 46%, transparent 30%, #000 100%);
          mask-image: radial-gradient(ellipse 62% 58% at 46% 46%, transparent 30%, #000 100%);
}

/* Dissolves the colour into the white of the section below. Without it the
   hero's overflow:hidden ends the gradient on a dead straight line and the
   join reads as two pages stacked rather than one page. */
.hero::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: clamp(90px, 16vh, 180px);
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, var(--white) 100%);
}

/* --- Layout -------------------------------------------------------------- */
.hero-inner {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  align-self: center;
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(28px, 5vw, 64px);
  align-items: center;
}

.hero h1 {
  font-size: var(--t-hero);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.08;
}
.hero h1 em {
  font-style: normal;
  color: var(--green-ink);
  display: block;
}
.hero p {
  font-size: var(--t-lead);
  margin-top: 18px;
  max-width: 48ch;
  color: var(--gray-strong);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

.hero-note { margin-top: 16px; font-size: .85rem; color: var(--gray); }

/* --- The mark ------------------------------------------------------------
   Bare on the gradient. There was a white disc with a rotating conic halo
   behind it; both are gone. The disc read as a sticker pasted over the
   background, and the halo tinted the white it sat on, so the mark ended up
   floating in a murky ring instead of on the page.

   What replaces them is the green field in .hb-green, positioned to sit
   behind the mark: the same lift, with no edge to give it away. The drop
   shadow is tinted green rather than grey for the same reason.
   ------------------------------------------------------------------------ */
.hero-art {
  display: grid;
  place-items: center;
  width: 100%;
}
.hero-art img {
  width: 68%;
  max-width: 215px;
  filter: drop-shadow(0 18px 34px rgba(3, 120, 2, .18));
  animation: heroFloat 7s ease-in-out infinite;
}

/* --- Scroll cue ---------------------------------------------------------- */
.hero-cue {
  justify-self: center;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 10px 16px;
  min-height: 44px;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gray);
  transition: color .2s ease;
}
.hero-cue:hover { color: var(--ink); }
.hero-cue svg { width: 18px; height: 18px; animation: heroBob 2.4s ease-in-out infinite; }

/* --- Entrance ------------------------------------------------------------
   `both` fill mode matters: without it every element flashes at full opacity
   for one frame before its delay elapses, which is more distracting than no
   animation at all. The global prefers-reduced-motion block in section 13
   collapses all of this to nothing. */
.hero h1,
.hero-copy p,
.hero-actions,
.hero-note,
.hero-art,
.hero-cue { animation: heroRise .72s cubic-bezier(.22, .8, .28, 1) both; }

.hero h1        { animation-delay: .05s; }
.hero-copy p    { animation-delay: .14s; }
.hero-actions   { animation-delay: .23s; }
.hero-note      { animation-delay: .32s; }
.hero-cue       { animation-delay: .5s; }

/* The mark arrives on its own curve, then hands over to the float loop. */
.hero-art {
  animation: heroPop .9s cubic-bezier(.2, .9, .3, 1) both;
  animation-delay: .1s;
}

@keyframes heroRise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}
@keyframes heroPop {
  from { opacity: 0; transform: scale(.9); }
  to   { opacity: 1; transform: none; }
}
@keyframes heroFloat {
  0%, 100% { transform: translateY(-7px); }
  50%      { transform: translateY(7px); }
}
@keyframes heroSpin {
  to { transform: rotate(360deg); }
}
@keyframes heroBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}
@keyframes heroDriftA {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-7%, 6%, 0) scale(1.12); }
}
@keyframes heroDriftB {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(8%, -6%, 0) scale(1); }
}
@keyframes heroDriftC {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-9%, 8%, 0) scale(1.15); }
}


/* ==========================================================================
   7. Cards (product range + channels)
   ========================================================================== */

/* Explicit column counts, never auto-fit. Both grids hold a card count that
   divides by 1, 2 and 4 — a 3-column step would leave a ragged final row on
   the page's most important credibility section, which reads as a bug. */
.card-grid { display: grid; gap: clamp(16px, 2vw, 24px); }
.grid-4 { grid-template-columns: 1fr; }

@media (min-width: 560px)  { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .grid-4 { grid-template-columns: repeat(4, 1fr); } }

/* The whole card is an anchor. Everything inside is inert; the card carries
   the hover, the focus ring and the tap target. */
.card {
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(18px, 2.1vw, 24px);
  color: inherit;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.card:hover {
  border-color: var(--green);
  box-shadow: 0 10px 30px rgba(21, 21, 23, .07);
}

.card-icon {
  display: inline-flex;
  width: 40px; height: 40px;
  align-items: center;
  justify-content: center;
  border-radius: 11px;
  margin-bottom: 14px;
}
.card-icon svg { width: 23px; height: 23px; }

/* The one axis carried in colour: blue classifies food, yellow non-food.
   Never green — green is reserved for the arrow, which is the action. */
.card-food    .card-icon { background: var(--blue-tint);   color: var(--blue-ink); }
.card-nonfood .card-icon { background: var(--yellow-tint); color: var(--yellow-ink); }

/* Channels are a different taxonomy from products, so they get a neutral
   plate rather than borrowing the food/non-food colours — those mean one
   specific thing and reusing them here would dilute it. */
.card-channel .card-icon { background: var(--off-white); color: var(--ink-soft); }

/* Title and arrow on one row. The arrow used to sit in a footer under the
   body text, pinned with margin-top:auto — which left visible dead space in
   every card whose list was shorter than its neighbour's. */
.card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.card h3 {
  font-size: 1.02rem;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -.01em;
}

/* ⚠ Exceptions only. See the note on `tags` in content.js — a chip on every
   card is a chip on no card. */
.card-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.tag {
  font-size: .71rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--blue-tint);
  color: var(--blue-ink);
  box-shadow: inset 0 0 0 1px rgba(0, 168, 251, .25);
  white-space: nowrap;
}

.card-role { margin-top: 8px; font-size: .89rem; color: var(--gray); }
.card-sub  { margin-top: 11px; font-size: .845rem; color: var(--gray); line-height: 1.7; }

/* Arrow only. The word "Enquire" is kept for screen readers via .sr-only —
   printed eight times down the grid it was noise, but a link still needs to
   say where it goes. */
.card-go {
  flex: none;
  display: inline-flex;
  margin-top: 2px;
  color: var(--green-ink);
  transition: transform .18s ease;
}
.card-go svg { width: 17px; height: 17px; }
.card:hover .card-go { transform: translateX(3px); }

/* Labels the two halves of "who we work with". Without them the shopper row
   reads as a fifth channel, which would imply Nutricare sells to the public. */
.group-label {
  display: block;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--gray);
  margin-bottom: 14px;
}

/* The consumer lane. A row, not a card, and it does not sit in the grid —
   the visual difference IS the message: this is a different kind of answer
   from the four above it. */
.shopper-lane {
  margin-top: clamp(24px, 3vw, 34px);
  padding: clamp(20px, 2.4vw, 26px) clamp(20px, 2.6vw, 28px);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px 22px;
}
.shopper-icon {
  flex: none;
  margin-bottom: 0;
  background: var(--off-white);
  color: var(--ink-soft);
}
.shopper-copy { flex: 1 1 320px; }
.shopper-copy .group-label { margin-bottom: 6px; }
.shopper-copy h3 { font-size: 1.05rem; }
.shopper-copy p  { margin-top: 6px; font-size: .92rem; color: var(--gray); max-width: 62ch; }
.shopper-lane .text-link { flex: none; }

/* The catch-all under the grid. */
.range-scope {
  margin-top: clamp(26px, 3vw, 36px);
  padding: clamp(18px, 2.2vw, 24px) clamp(20px, 2.6vw, 28px);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px 24px;
  text-align: center;
}
.range-scope > div { display: flex; flex-wrap: wrap; gap: 4px 8px; justify-content: center; }
.range-scope strong { font-size: 1.02rem; font-weight: 700; color: var(--ink); }
.range-scope span   { font-size: .95rem; color: var(--gray); }


/* ==========================================================================
   8. How to order
   ========================================================================== */

/* The ordering spine. Numbers are generated from the <ol> with a counter, so
   deleting or adding a step in content.js renumbers the rest automatically —
   a hand-typed "3." in the copy would be wrong the moment a step moves. */
.steps {
  list-style: none;
  counter-reset: step;
  display: grid;
  gap: clamp(14px, 1.8vw, 20px);
}
@media (min-width: 700px)  { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1020px) { .steps { grid-template-columns: repeat(4, 1fr); } }

.steps li {
  counter-increment: step;
  position: relative;
  padding-top: 44px;
}
.steps li::before {
  content: counter(step);
  position: absolute;
  top: 0; inset-inline-start: 0;
  width: 32px; height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--green-tint);
  color: var(--green-ink);
  font-size: .85rem;
  font-weight: 800;
}
/* The rule joining one step to the next. Hidden on the last, and on any
   step that starts a new row — a line running off the end of a row points
   at nothing. */
.steps li::after {
  content: "";
  position: absolute;
  top: 15px;
  inset-inline-start: 42px;
  inset-inline-end: -10px;
  height: 2px;
  background: var(--border);
}
.steps li:last-child::after { display: none; }
@media (max-width: 1019px) {
  .steps li:nth-child(2n)::after { display: none; }
}
@media (max-width: 699px) {
  .steps li::after { display: none; }
}

.step-body strong {
  display: block;
  font-size: 1rem;
  font-weight: 700;
  margin-bottom: 5px;
}
.step-body span { font-size: .89rem; color: var(--gray); line-height: 1.65; }

/* Facts panel. Two columns of rows rather than one long list — nine stacked
   rows in a half-width column left a large void beside them. */
.panel {
  margin-top: clamp(26px, 3.2vw, 38px);
  padding: clamp(20px, 2.4vw, 28px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--white);
}
.panel-title {
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gray);
  margin-bottom: 14px;
}

.ops-list { display: grid; gap: 2px 36px; }
@media (min-width: 820px) { .ops-list { grid-template-columns: 1fr 1fr; } }

.ops-row {
  display: grid;
  grid-template-columns: minmax(120px, 34%) 1fr;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border);
  align-items: baseline;
}
.ops-row dt { font-weight: 700; color: var(--ink); font-size: .87rem; }
.ops-row dd { font-size: .89rem; color: var(--gray); }

/* ==========================================================================
   10. Contact, trade info & form
   ========================================================================== */
.contact-inner {
  max-width: var(--maxw);
  margin-inline: auto;
  display: grid;
  grid-template-columns: .9fr 1.1fr;
  gap: clamp(30px, 4.5vw, 60px);
  align-items: start;
}

.contact-list { display: grid; gap: 10px; margin: clamp(24px, 3vw, 32px) 0 0; }
@media (min-width: 620px) { .contact-list { grid-template-columns: 1fr 1fr; } }

.contact-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color .18s ease, box-shadow .18s ease;
}
a.contact-item:hover {
  border-color: var(--green);
  box-shadow: 0 6px 20px rgba(21, 21, 23, .06);
}

.ci-icon {
  width: 38px; height: 38px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--green-tint);
  color: var(--green-ink);
}
.ci-icon svg { width: 19px; height: 19px; }

.contact-item small {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gray);       /* NOT a lighter grey: this must pass AA */
}
.contact-item strong { display: block; color: var(--ink); font-weight: 600; font-size: .97rem; }

/* The form runs to about twice the height of the column beside it, so
   without this the phone number scrolls out of view exactly while somebody
   is deciding whether to type or just call. align-self:start is required:
   a stretched grid item is already as tall as the row and cannot stick. */
@media (min-width: 961px) {
  .contact-aside {
    position: sticky;
    top: calc(var(--header-h) + 24px);
    align-self: start;
  }
}

/* --- Form --- */
.form-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(22px, 3vw, 34px);
  box-shadow: var(--shadow);
}

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

.field { margin-bottom: 15px; }
.field label {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: .84rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 7px;
}
.opt {
  font-size: .74rem;
  font-weight: 500;
  color: var(--gray);
  text-transform: lowercase;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 12px 14px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: .95rem;
  color: var(--ink);
  background: var(--white);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.field textarea { resize: vertical; min-height: 128px; }

.field select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235A6069' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  background-size: 17px 17px;
}
[dir="rtl"] .field select { background-position: left 15px center; }

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--green-ink);
  box-shadow: 0 0 0 3px rgba(4, 201, 3, .18);
}

/* Qatar mobile numbers are 8 digits, so the country code is printed rather
   than typed — one less thing to get wrong on a phone. */
.input-prefix { display: flex; align-items: stretch; }
.prefix {
  display: flex;
  align-items: center;
  padding: 0 12px;
  font-size: .92rem;
  font-weight: 600;
  color: var(--gray);
  background: var(--off-white);
  border: 1.5px solid var(--border);
  border-inline-end: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.input-prefix input { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

.field-err { display: none; font-size: .8rem; color: #C0102A; margin-top: 6px; }
.field.invalid input,
.field.invalid select,
.field.invalid textarea { border-color: #C0102A; }
.field.invalid .field-err { display: block; }

.form-msg { display: none; margin-top: 14px; padding: 12px 15px; border-radius: var(--radius-sm); font-size: .89rem; }
.form-msg.show { display: block; }
.form-msg.ok   { background: var(--green-tint); color: var(--green-ink); }
.form-msg.bad  { background: #FDECEF; color: #C0102A; }

.form-card .btn { width: 100%; margin-top: 4px; }

.form-note { margin-top: 12px; font-size: .8rem; color: var(--gray); line-height: 1.6; }


/* ==========================================================================
   11. Footer
   ========================================================================== */
footer {
  background: var(--ink);
  color: var(--foot-text);
  padding: clamp(44px, 5.5vw, 68px) var(--pad) 0;
}

.foot-grid {
  max-width: var(--maxw);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1.7fr 1fr 1fr;
  gap: clamp(26px, 4vw, 54px);
  padding-bottom: 40px;
}

/* The wordmark is NOT used here — its text is near-black and would vanish
   on this ground. The mark plus live text keeps the brand legible. */
.foot-logo { display: inline-flex; align-items: center; gap: 11px; margin-bottom: 14px; }
.foot-logo img { height: 34px; width: auto; }
.foot-logo span { font-size: 1.12rem; font-weight: 800; color: var(--white); letter-spacing: -.01em; }

.foot-brand p { font-size: .89rem; max-width: 44ch; }

.foot-col h3 {
  color: var(--white);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 15px;
}
.foot-col li { margin-bottom: 9px; font-size: .89rem; }
.foot-col a { transition: color .16s ease; }
.foot-col a:hover { color: var(--green-light); }

.social { display: flex; gap: 10px; margin-top: 18px; }
.social a {
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: rgba(255, 255, 255, .09);
  color: var(--white);
  transition: background .18s ease, transform .18s ease;
}
.social a:hover { background: var(--green); color: var(--ink); transform: translateY(-2px); }
.social svg { width: 19px; height: 19px; }

.foot-bottom {
  max-width: var(--maxw);
  margin-inline: auto;
  border-top: 1px solid rgba(255, 255, 255, .1);
  padding: 18px 0 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: space-between;
  font-size: .82rem;
}


/* ==========================================================================
   12. Floating WhatsApp button
   --------------------------------------------------------------------------
   White glyph, as asked — which forces the fill. White on WhatsApp's own
   #25D366 measures 1.98:1, far below the 3:1 minimum that applies to a
   graphic carrying meaning, and this glyph IS the button's entire meaning.
   --wa-fab (#159B47) is the same green a step deeper, and carries white at
   3.61:1. Still unmistakably the WhatsApp button; actually readable.

   ⚠ Setting this back to var(--wa) with a white glyph is the one change that
   silently breaks it. If the exact brand green is required, the glyph has to
   go back to var(--ink) (9.19:1).

   It keeps a shadow where the page's buttons do not: a coloured glow under a
   solid fill is decoration, but a shadow under a floating element is what
   separates it from the content it sits on. That is why this one is neutral
   rather than green.
   ========================================================================== */
.wa-fab {
  position: fixed;
  inset-inline-end: clamp(16px, 3vw, 28px);
  bottom: clamp(16px, 3vw, 28px);
  z-index: 90;
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--wa-fab);
  color: var(--white);
  box-shadow: 0 8px 26px rgba(21, 21, 23, .18);

  /* Starts inert. pointer-events:none matters as much as the opacity — a
     0-opacity link is still clickable and would swallow taps on whatever
     sits under it in that corner. */
  opacity: 0;
  transform: translateY(12px) scale(.9);
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, background-color .18s ease;
}
.wa-fab.is-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.wa-fab:hover { background: #0F7F39; }
.wa-fab svg { width: 27px; height: 27px; }


/* ==========================================================================
   13. Motion
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }

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


/* ==========================================================================
   14. Responsive
   ========================================================================== */
@media (max-width: 960px) {
  /* Mark above the headline, everything centred. The hero is viewport-height
     and vertically centred, so the CTA is still in view without scrolling. */
  .hero-inner   { grid-template-columns: 1fr; text-align: center; gap: clamp(20px, 4vw, 32px); }

  /* The mark moves to the top centre, so the green field has to follow it.
     Left where it is, it reads as an unexplained blob off to one side. */
  .hb-green     { top: 0; inset-inline-end: auto; inset-inline-start: 20%; width: 60%; }
  .hb-warm      { top: -14%; inset-inline-end: -14%; width: 44%; }
  .hero p       { margin-inline: auto; }
  .hero-actions { justify-content: center; }
  .hero-art     { order: -1; }
  .hero-art img { max-width: 165px; }

  .contact-inner { grid-template-columns: 1fr; }
  .foot-grid     { grid-template-columns: 1fr 1fr; }
  .foot-brand    { grid-column: 1 / -1; }
}

@media (max-width: 960px) {
  .burger { display: flex; }

  /* .nav-links is taken out of the flow here, so the `margin-inline-start:
     auto` that pushes the nav right on desktop stops doing anything and the
     burger collapses against the logo. Push the actions instead. */
  .nav-actions { margin-inline-start: auto; }
  /* Line the bars up with the section edge, not 8px inside it. */
  .burger { margin-inline-end: -8px; }

  .nav-links {
    position: absolute;
    top: 100%;
    inset-inline: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--white);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow);
    padding: 8px var(--pad) 18px;
    display: none;
  }
  .nav-links.open { display: flex; }
  .nav-links a:not(.btn) { padding: 14px 0; border-bottom: 1px solid var(--border); }
  .nav-links a:not(.btn)::after { display: none; }

  /* The bar itself has room for the logo and the burger, and nothing else —
     so the CTA lives in the panel, full width, below the links. */
  .nav-actions > .btn { display: none; }
  .nav-menu-cta { display: flex; margin-top: 16px; width: 100%; }
}

@media (max-width: 780px) {
  /* No mark on a phone. The wordmark is already in the header immediately
     above it, and the space it frees is what lets the headline, both buttons
     and the reply promise sit in one screen without scrolling. */
  .hero-art   { display: none; }
  .hero-inner { gap: 22px; }

  /* With the mark gone, the green field has nothing to sit behind, so it
     becomes an ambient wash across the top instead of a glow around nothing. */
  .hb-green   { top: -8%; inset-inline-start: 8%; width: 84%; }
}

/* Genuinely short windows only — landscape phones, a half-height browser.
   A viewport-height hero on a 400px-tall window is a wall of padding with the
   headline crushed into it, so the height rule is dropped and the cue, which
   exists only to use up spare vertical space, goes with it.

   This used to fire at `max-height: 700px` on narrow screens, which caught
   ordinary phones — an iPhone SE is 667px tall — and left them with a short
   hero while every larger phone got a full-height one. 620px is below every
   phone in portrait, so portrait phones now get the same full-viewport hero
   as the desktop. */
@media (max-height: 620px) {
  .hero {
    min-height: 0;
    padding-block: calc(var(--header-h) + clamp(16px, 3vh, 32px)) clamp(28px, 5vh, 48px);
  }
  .hero-cue     { display: none; }
  .hero-art img { max-width: 190px; }
}

/* Single-column phones: the icon moves beside the title instead of sitting on
   its own row above it. Eight cards stacked vertically is already a long
   scroll; this takes ~54px off each one without shrinking any text. */
@media (max-width: 559px) {
  .card {
    display: grid;
    grid-template-columns: 38px 1fr;
    column-gap: 13px;
    align-items: start;
  }
  .card-icon  { width: 38px; height: 38px; margin-bottom: 0; }
  .card-head,
  .card-tags,
  .card-role,
  .card-sub   { grid-column: 2; }

  .shopper-lane { align-items: flex-start; }
  .shopper-lane .text-link { margin-inline-start: 51px; }
}

@media (max-width: 560px) {
  .form-row  { grid-template-columns: 1fr; gap: 0; }
  .foot-grid { grid-template-columns: 1fr; }
  .ops-row   { grid-template-columns: 1fr; gap: 2px; padding: 10px 0; }
  .hero h1 em { display: inline; }
}
