/* ==========================================================================
   HAZ MED — Base
   Font loading, reset, element typography, layout primitives, accessibility.
   Requires tokens.css to be loaded first.

   HARD RULE for this codebase: no physical direction properties.
   Use margin-inline-start / padding-inline-end / inset-inline-start /
   border-inline-start / text-align:start|end. A `left`, `right`,
   `margin-left` or `text-align: right` in this project is a bug, not a style
   choice — it will not mirror and the Arabic build will drift.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONTS — self-hosted, subset, woff2 only.
   Latin is one variable file covering 400–600 (40 KB).
   Arabic ships two static weights (33 KB + 35 KB).
   unicode-range means an English page never downloads the Arabic files and an
   Arabic page only downloads the Latin file if Latin glyphs actually appear.

   PRELOAD, per language, in the document head — one file only, the one that
   paints the hero:
     EN:  <link rel="preload" href="/assets/fonts/hazmed-plex-latin-var.woff2"
                as="font" type="font/woff2" crossorigin>
     AR:  <link rel="preload" href="/assets/fonts/hazmed-plex-arabic-600.woff2"
                as="font" type="font/woff2" crossorigin>
   Do not preload all of them. Do not preload the Arabic files on English pages.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/hazmed-plex-latin-var.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/hazmed-plex-arabic-400.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1,
    U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF,
    U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/hazmed-plex-arabic-600.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1,
    U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF,
    U+FE70-FE74, U+FE76-FEFC;
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-block-start: calc(var(--header-h) + var(--space-6));
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul, fieldset, legend {
  margin: 0;
  padding: 0;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
}

img,
picture,
svg,
video,
canvas {
  display: block;
  max-inline-size: 100%;
  block-size: auto;
}

svg {
  fill: currentColor;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

fieldset {
  border: 0;
  min-inline-size: 0;
}

hr {
  border: 0;
  border-block-start: 1px solid var(--border-decorative);
  margin-block: var(--space-8);
}

/* --------------------------------------------------------------------------
   3. DOCUMENT
   -------------------------------------------------------------------------- */
body {
  font-family: var(--font-body);
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--track-body);
  color: var(--text);
  background-color: var(--surface);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  min-block-size: 100vh;
  /* `clip`, not `hidden`. `overflow-x: hidden` silently establishes a scroll
     container, which breaks `position: sticky` on descendants — including the
     site header and the frozen first column of the dilution table. `clip`
     suppresses the axis without creating a scroll port. The `hidden` line is
     the fallback for engines without `clip`. */
  overflow-x: hidden;
  overflow-x: clip;
}

html {
  overflow-x: hidden;
  overflow-x: clip;
}

::selection {
  background-color: var(--cyan-200);
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   4. HEADINGS
   Tracking is applied only to Latin. `:lang(ar)` inherits track-* = 0 from
   tokens.css, so these rules are safe as written — but any NEW rule adding
   letter-spacing must use a --track-* token, never a literal em value.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--font-head);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  text-wrap: balance;
  /* Arabic ascenders/diacritics need headroom; fixed heights clip them. */
  padding-block-start: 0.02em;
}

h1, .h1 {
  font-size: var(--fs-4xl);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
}

h2, .h2 {
  font-size: var(--fs-3xl);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-heading);
}

h3, .h3 {
  font-size: var(--fs-2xl);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-heading);
}

h4, .h4 {
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
}

h5, .h5 {
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
}

h6, .h6 {
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
}

.display {
  font-size: var(--fs-5xl);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   5. TEXT
   -------------------------------------------------------------------------- */
p {
  text-wrap: pretty;
}

.lead {
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--text-muted);
  max-inline-size: var(--measure);
}

.text-sm  { font-size: var(--fs-sm); }
.text-xs  { font-size: var(--fs-xs); }
.text-muted { color: var(--text-muted); }
.text-strong { color: var(--text-strong); }
.text-accent { color: var(--text-accent); }

/* Eyebrow / kicker. Uppercase + tracking is a Latin-only treatment:
   text-transform does nothing in Arabic and tracking breaks the joins, so
   both are switched off under :lang(ar) and weight carries the emphasis. */
.eyebrow {
  display: block;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--text-accent);
  margin-block-end: var(--space-3);
}

.eyebrow:lang(ar) {
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--fs-xs);
}

.eyebrow--inverse { color: var(--text-inverse-accent); }

/* --------------------------------------------------------------------------
   6. LINKS
   -------------------------------------------------------------------------- */
a {
  color: var(--text-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--text-accent-hover);
}

.prose a {
  text-decoration: underline;
}

/* Inline "read more" link with a chevron that must mirror in RTL. */
/* NOT flex. A flex container turns every element child AND every text run
   between element children into a separate flex item, so `gap` gets injected
   mid-phrase and the label can no longer wrap. Both copy decks mandate <bdi>
   around Latin runs in Arabic prose and around HAZ TAB in both languages, so a
   flex .link-arrow shatters the moment it receives a real deck string:
     "View HAZ TAB and the dilution guide" -> View | HAZ TAB | and the ... | ->
   Staying inline makes the component immune to its own content instead of
   relying on every author remembering to wrap the label in a span. */
.link-arrow {
  display: inline;
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.link-arrow .icon {
  display: inline-block;
  vertical-align: -0.125em;
  margin-inline-start: var(--space-2);
  transition: transform var(--dur-base) var(--ease-out);
  /* DIRECTIONAL icon — must mirror. */
  transform: scaleX(var(--flip));
}

.link-arrow:hover .icon {
  transform: scaleX(var(--flip)) translateX(3px);
}

/* --------------------------------------------------------------------------
   7. BIDIRECTIONAL TEXT
   Latin strings inside Arabic reorder unpredictably. Every SKU, order code,
   concentration, dilution ratio, phone number, email and URL in Arabic copy
   must be wrapped in one of these — or in a bare <bdi>.

   This is not optional polish. `HT-167-200` inside an Arabic sentence renders
   as `200-167-HT` without isolation, and QA will not catch it.
   -------------------------------------------------------------------------- */
bdi,
.bidi-isolate {
  unicode-bidi: isolate;
}

/* Numerals, measurements, ppm values, order codes. Always LTR, always
   tabular so table columns align. */
.num,
.code {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

.code {
  font-family: var(--font-mono);
  font-size: 0.94em;
  letter-spacing: 0;
}

/* Latin runs inside an Arabic document must use the Latin face. IBM Plex Sans
   Arabic is unicode-range subset to Arabic, so a Latin run under --font-arabic
   silently falls through to Tahoma/Geeza — off-brand, and it hits exactly the
   strings that matter most: order codes, `10,000 ppm`, `1.67 g`, HAZ TAB.
   Routed on the isolation hooks the copy decks already mandate, so authors get
   it by following the <bdi> convention rather than by remembering a font rule.
   .code is deliberately NOT in this list: it is already routed to --font-mono,
   which is Latin-glyphed, and a higher-specificity rule here would silently
   override the monospace face on every order code. */
html[lang="ar"] .num,
html[lang="ar"] .is-num,
html[lang="ar"] .bidi-isolate,
html[lang="ar"] .product-name {
  font-family: var(--font-latin);
}

/* With JS off the header cannot collapse, so at phone widths it stands ~540px
   tall. Sticky, that permanently occludes the viewport and makes the contact
   form's submit button unreachable — pointer events land on the header. It only
   needs to stick once JS can collapse it. */
.no-js .site-header {
  position: static;
}

/* --------------------------------------------------------------------------
   8. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.container {
  inline-size: 100%;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--wide { max-inline-size: var(--container-wide); }
.container--prose { max-inline-size: var(--container-prose); }

/* Owl stack — vertical rhythm without margin bookkeeping. */
.stack > * + * { margin-block-start: var(--space-4); }
.stack-2 > * + * { margin-block-start: var(--space-2); }
.stack-3 > * + * { margin-block-start: var(--space-3); }
.stack-6 > * + * { margin-block-start: var(--space-6); }
.stack-8 > * + * { margin-block-start: var(--space-8); }
.stack-12 > * + * { margin-block-start: var(--space-12); }

.prose {
  max-inline-size: var(--measure);
}

.prose > * + * { margin-block-start: var(--space-5); }
.prose h2 { margin-block-start: var(--space-12); }
.prose h3 { margin-block-start: var(--space-10); }
.prose ul,
.prose ol { padding-inline-start: var(--space-6); }
.prose li + li { margin-block-start: var(--space-2); }

.grid {
  display: grid;
  gap: var(--grid-gap);
}

.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

.flow-end { margin-inline-start: auto; }
.text-start { text-align: start; }
.text-end { text-align: end; }
.text-center { text-align: center; }

/* --------------------------------------------------------------------------
   9. ACCESSIBILITY
   -------------------------------------------------------------------------- */
.visually-hidden:not(:focus):not(:active) {
  clip-path: inset(50%);
  block-size: 1px;
  inline-size: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  z-index: var(--z-skiplink);
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--text-inverse);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  border-radius: var(--radius-md);
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
  color: var(--text-inverse);
}

/* One focus treatment for the whole site. Visible on every focusable thing.
   :focus-visible only — keyboard users get the ring, mouse users do not. */
:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-xs);
}

.on-ink :focus-visible,
.band--ink :focus-visible,
.site-footer :focus-visible,
.hero :focus-visible {
  outline-color: var(--focus-ring-inverse);
}

/* --------------------------------------------------------------------------
   10. ICON CONVENTION
   Two classes, and getting this wrong is a correctness bug, not a nitpick:

   .icon            — REAL-WORLD MEANING. Hazard symbols, biohazard, flame,
                      corrosive, PPE pictograms, the logo mark, a tick, a
                      clock. These NEVER mirror. A biohazard trefoil mirrored
                      is still a trefoil; a flame mirrored is wrong; and any
                      standardised safety pictogram must match the printed
                      label on the physical product.

   .icon--dir       — DIRECTIONAL MEANING. Chevrons, arrows, "next", "back",
                      carousel controls, breadcrumb separators, the external-
                      link glyph. These MUST mirror via scaleX(var(--flip)).

   Never mirror an icon by swapping the SVG file. Use the class.
   -------------------------------------------------------------------------- */
.icon {
  inline-size: 1.25em;
  block-size: 1.25em;
  flex: none;
  display: inline-block;
  vertical-align: -0.22em;
}

.icon--dir {
  transform: scaleX(var(--flip));
}

.icon--sm { inline-size: 1em; block-size: 1em; }
.icon--lg { inline-size: 1.75em; block-size: 1.75em; }
.icon--xl { inline-size: 2.5em; block-size: 2.5em; }

/* --------------------------------------------------------------------------
   11. MOTION
   Content is visible by DEFAULT. .reveal starts at opacity 1 and JS opts it
   into the animation by adding .reveal--armed. If the script never runs, the
   page is simply static — it is never blank.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 1;
}

.js .reveal--armed {
  opacity: 0;
  transform: translateY(var(--reveal-y));
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.js .reveal--armed.is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .js .reveal--armed {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* --------------------------------------------------------------------------
   12. NO-JS
   The document ships with class="no-js"; main.js swaps it to "js" as its
   first statement. Anything that only works with a script must be gated on
   .js so the no-script rendering stays navigable.
   -------------------------------------------------------------------------- */
.no-js .js-only { display: none !important; }
.js .no-js-only { display: none !important; }

/* --------------------------------------------------------------------------
   13. IMAGE PLACEHOLDERS
   HAZ MED has no approved photography and no licence to depict people as its
   staff or customers. Until real assets land, every image slot ships as one
   of these, with the photography brief written into the visible caption AND
   the alt attribute so it cannot be shipped by accident.
   -------------------------------------------------------------------------- */
.media {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background-color: var(--surface-sunken);
  /* Reserve space — no CLS when the real asset arrives. */
  aspect-ratio: var(--media-ratio, 4 / 3);
}

.media > img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.media--16x9 { --media-ratio: 16 / 9; }
.media--3x2  { --media-ratio: 3 / 2; }
.media--1x1  { --media-ratio: 1 / 1; }
.media--21x9 { --media-ratio: 21 / 9; }

.media-placeholder {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-6);
  block-size: 100%;
  background-color: var(--surface-sunken);
  background-image: repeating-linear-gradient(
    135deg,
    transparent 0 10px,
    rgba(9, 171, 197, 0.05) 10px 20px
  );
  border: 1px dashed var(--border-card);
  border-radius: inherit;
  color: var(--text-muted);
  text-align: start;
}

.media-placeholder__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  align-self: start;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--text-accent);
}

.media-placeholder__label:lang(ar) {
  text-transform: none;
  letter-spacing: 0;
}

.media-placeholder__brief {
  display: block;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  max-inline-size: 42ch;
}

/* Dark variant, for hero slots */
.media-placeholder--ink {
  background-color: var(--ink);
  background-image: repeating-linear-gradient(
    135deg,
    transparent 0 10px,
    rgba(255, 255, 255, 0.035) 10px 20px
  );
  border-color: var(--border-inverse);
  color: var(--text-inverse-muted);
}

.media-placeholder--ink .media-placeholder__label { color: var(--text-inverse-accent); }

/* --------------------------------------------------------------------------
   14. PRINT
   Spec sheets and the HAZ TAB dilution table will be printed and pinned up in
   facilities. Make that not look broken.
   -------------------------------------------------------------------------- */
@media print {
  .site-header,
  .site-footer,
  .cta-band,
  .skip-link,
  .lang-switch {
    display: none !important;
  }

  body {
    color: #000;
    background: #fff;
    font-size: 11pt;
  }

  .band { padding-block: var(--space-6); }
  .table-wrap { overflow: visible; border: 0; }
  .data-table { font-size: 9.5pt; }

  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #444;
  }
}
