/* ==========================================================================
   JARRAH 2026 — DESIGN SYSTEM
   Loaded after the legacy assets/css/style.css. All new/redesigned markup
   uses the `j-` class prefix to stay collision-free from the legacy theme.
   Colors/fonts are driven by CSS custom properties set inline in style()
   (function.php) from the `theme` DB table + server-side $lang — this file
   only consumes var(--...), it never hardcodes brand colors.
   Logical properties only (RTL-first) — no left/right, no margin-left etc.
   Mobile-first: base rules target small screens; @media (min-width: ...)
   blocks layer on tablet/desktop enhancements. Single breakpoint at 861px
   unless a component needs its own.
   ========================================================================== */

/* Self-hosted Google Fonts (variable, wght 400-800) — replaces the
   fonts.googleapis.com stylesheet chain entirely. The woff2 files carry the
   whole weight range each, and unicode-range keeps browsers from fetching
   the subsets a page never renders. style() preloads the active language's
   primary files so text paints in its final font (no swap reflow → no CLS). */
@font-face {
  font-family: 'Cairo';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/google/cairo-arabic.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, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}
@font-face {
  font-family: 'Cairo';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/google/cairo-latin.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: 'Manrope';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/google/manrope-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/google/manrope-latin.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;
}

/* Pre-core offcanvas guards. The mini-cart drawer (.sidebar-cart-active),
   mobile menu (.clickalbe-sidebar-wrapper-style-1) and body overlays are
   positioned/hidden ONLY by the deferred core.min.css — without these they
   paint in-flow as full-height blocks and snap away when core arrives
   (measured as a whole-page CLS of 1.0). Values duplicate the legacy closed
   state; the open-state selectors in core are more specific and still win. */
.sidebar-cart-active,
.clickalbe-sidebar-wrapper-style-1 {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  visibility: hidden;
  opacity: 0;
  z-index: 9999;
}
.body-overlay,
.body-overlay-3 {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  visibility: hidden;
  opacity: 0;
}

/* First-paint typography baseline. core.min.css (bootstrap + purged legacy)
   loads DEFERRED, and its body{font-size:14px;...} rule used to arrive after
   first paint and reflow the entire document (measured CLS 1.0). These rules
   duplicate the document-level values the deferred bundle will re-assert, so
   its arrival changes nothing the eye can see. Keep in sync with the body /
   h+p rules at the top of style.css. */
/* Mirror core's overflow containment at first paint — before the deferred
   bundle lands, a horizontally-overflowing element (plus RTL initial scroll)
   can briefly distort the root's painted box, which Lighthouse records as a
   large layout shift. */
html, body {
  overflow-x: hidden;
}
body {
  font-size: 14px;
  font-weight: 400;
  color: #333;
  font-family: var(--font);
}
h1, h2, h3, h4, h5, h6, p {
  font-family: var(--font);
}
p {
  line-height: 24px;
}

/* Font import removed: --font-display/--font-body are always overridden
   inline by style() (function.php) to Cairo/Manrope (see
   assets/css/tailwind-src.css's own font import) — Cormorant Garamond and
   IBM Plex Sans/Arabic never actually rendered on any Golden Clarity page,
   this @import just downloaded three unused font families on every request. */

/* ---- local fallback tokens (overridden inline per-request by style()) ---- */
:root{
  --j-maxw: 1200px;
  --j-gutter: 28px;
  --j-shadow: 0 24px 60px -30px rgba(43,42,40,.35);
  --j-radius: 2px;
}

/* ==========================================================================
   RESET / BASE
   ========================================================================== */
.j-scope, .j-scope *{ box-sizing: border-box; }

body{
  font-family: var(--font-body, 'Cairo', sans-serif);
}

.j-h1, .j-h2, .j-h3,
.j-scope h1, .j-scope h2, .j-scope h3{
  font-family: var(--font-display, 'Manrope', sans-serif);
  font-weight: 500;
  line-height: 1.15;
  color: var(--ink, #2B2A28);
  margin: 0 0 20px;
}
body:not(.en) .j-h1, body:not(.en) .j-h2, body:not(.en) .j-h3,
body:not(.en) .j-scope h1, body:not(.en) .j-scope h2, body:not(.en) .j-scope h3{
  font-family: var(--font-body, 'Cairo', sans-serif);
  font-weight: 400;
  line-height: 1.3;
}

.j-h1{ font-size: clamp(36px, 6vw, 76px); letter-spacing: -.01em; }
.j-h2{ font-size: clamp(28px, 4.2vw, 46px); }
.j-h3{ font-size: 20px; font-weight: 600; }

.j-lead{
  font-size: clamp(16px, 1.7vw, 19px);
  font-weight: 300;
  line-height: 1.75;
  color: var(--ink-soft, #4a4844);
  max-width: 60ch;
}
.j-lead + .j-lead{ margin-block-start: 18px; }

.j-eyebrow{
  font-size: 12px;
  letter-spacing: .28em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--accent, #9A6B1F);
  margin-block-end: 16px;
}
body.en .j-eyebrow{ letter-spacing: .30em; }

/* ==========================================================================
   LAYOUT
   ========================================================================== */
.j-container{
  max-width: var(--j-maxw);
  margin-inline: auto;
  padding-inline: var(--j-gutter);
}
.j-section{ padding-block: 64px; }
.j-section-sm{ padding-block: 40px; }
@media (min-width: 861px){
  .j-section{ padding-block: 96px; }
  .j-section-sm{ padding-block: 56px; }
}

.j-surface{ background: var(--surface, #FBF7EF); color: var(--ink, #2B2A28); }
.j-ink{ background: var(--ink, #2B2A28); color: var(--surface, #FBF7EF); }
.j-ink .j-eyebrow{ color: var(--accent-deep, #cba15f); }
.j-ink .j-lead{ color: rgba(251,247,239,.72); }

.j-grid{ display: grid; gap: 24px; }
.j-grid-2, .j-grid-3, .j-grid-4{ grid-template-columns: 1fr; }
@media (min-width: 861px){
  .j-grid{ gap: 32px; }
  .j-grid-2{ grid-template-columns: 1fr 1fr; }
  .j-grid-3{ grid-template-columns: repeat(3, 1fr); }
  .j-grid-4{ grid-template-columns: repeat(4, 1fr); }
}

/* .j-grid-5 (story timeline). Written standalone rather than folded into the
   selector lists above so it stays a pure append — production's copy of this
   file has drifted from local before, and an additive block can be applied to
   whatever is actually live without a whole-file overwrite.
   Steps 1 → 3 → 5: five text columns are unreadable on a tablet. */
.j-grid-5{ grid-template-columns: 1fr; }
@media (min-width: 601px){
  .j-grid-5{ grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 861px){
  .j-grid-5{ grid-template-columns: repeat(5, 1fr); }
}

/* ==========================================================================
   BUTTONS
   ========================================================================== */
.j-btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: .04em;
  padding-block: 15px;
  padding-inline: 38px;
  border-radius: var(--j-radius);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: .25s;
}
.j-btn-primary{
  background: var(--accent, #9A6B1F);
  color: #fff;
}
.j-btn-primary:hover{ background: var(--accent-deep, #7d5416); color:#fff; }
.j-btn-secondary{
  background: transparent;
  color: var(--ink, #2B2A28);
  border-color: var(--line, #e4dbc7);
}
.j-btn-secondary:hover{ border-color: var(--accent, #9A6B1F); color: var(--accent, #9A6B1F); }

/* ==========================================================================
   CARDS
   ========================================================================== */
.j-card{
  background: #fff;
  border: 1px solid var(--line, #e4dbc7);
  border-radius: 4px;
  padding: 34px;
}
.j-card-shadow{ box-shadow: var(--j-shadow); border: none; }
.j-card .j-icn{ width: 40px; height: 40px; margin-block-end: 18px; color: var(--accent, #9A6B1F); }

.j-pillars{
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  background: var(--line, #e4dbc7);
  border: 1px solid var(--line, #e4dbc7);
}
.j-pillar{ background: var(--surface, #FBF7EF); padding: 32px 26px; }
.j-pillar .j-icn{ width: 40px; height: 40px; margin-block-end: 18px; color: var(--accent, #9A6B1F); }
.j-pillar h3{ font-size: 19px; font-weight: 600; margin-block-end: 12px; }
.j-pillar p{ font-size: 15px; color: var(--ink-soft, #4a4844); font-weight: 300; line-height: 1.65; }
@media (min-width: 641px){
  .j-pillars-4{ grid-template-columns: 1fr 1fr; }
}
@media (min-width: 861px){
  .j-pillars{ grid-template-columns: repeat(3, 1fr); }
  .j-pillars-4{ grid-template-columns: repeat(4, 1fr); }
  .j-pillar{ padding: 44px 34px; }
  .j-pillar .j-icn{ width: 44px; height: 44px; margin-block-end: 22px; }
  .j-pillar h3{ font-size: 20px; margin-block-end: 14px; }
  .j-pillar p{ font-size: 15.5px; line-height: 1.7; }
}

/* Quality steps — numbered editorial rows (quality-certification.php).
   Horizontal marker+text layout so rows hug their content regardless of
   how much text each step carries; same hairline-grid treatment as
   .j-pillars. Logical properties keep it RTL-clean. */
.j-qsteps{
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  background: var(--line, #e4dbc7);
  border: 1px solid var(--line, #e4dbc7);
}
.j-qstep{
  background: var(--surface, #FBF7EF);
  padding: 26px 24px;
  display: flex;
  align-items: flex-start;
  gap: 20px;
}
.j-qstep-marker{
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  min-width: 46px;
}
.j-qstep-num{
  font-family: var(--font-display, 'Manrope', sans-serif);
  font-size: 36px;
  line-height: 1;
  font-weight: 500;
  color: var(--accent, #9A6B1F);
  opacity: .32;
}
.j-qstep-marker .j-icn{
  font-size: 20px;
  color: var(--accent, #9A6B1F);
  opacity: .85;
}
.j-qstep h3{ font-size: 18px; font-weight: 600; margin-block-end: 8px; }
.j-qstep p{ font-size: 14.5px; color: var(--ink-soft, #4a4844); font-weight: 300; line-height: 1.65; }
@media (min-width: 861px){
  .j-qsteps{ grid-template-columns: 1fr 1fr; }
  .j-qstep{ padding: 34px 32px; gap: 26px; }
  .j-qstep-num{ font-size: 42px; }
  .j-qstep h3{ font-size: 19px; margin-block-end: 10px; }
  .j-qstep p{ font-size: 15px; line-height: 1.7; }
}

/* ==========================================================================
   GRADE LADDER (TA35 / TA44 / TA55+ / Lord)
   ========================================================================== */
.j-grade-ladder{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line, #e4dbc7);
  border: 1px solid var(--line, #e4dbc7);
  border-radius: 4px;
  overflow: hidden;
}
.j-grade-step{
  background: #fff;
  padding: 22px 14px;
  text-align: center;
  transition: .25s;
}
.j-grade-step:hover, .j-grade-step.is-current{
  background: var(--ink, #2B2A28);
  color: var(--surface, #FBF7EF);
}
.j-grade-step:hover .j-grade-code, .j-grade-step.is-current .j-grade-code{ color: var(--accent-deep, #cba15f); }
.j-grade-code{
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  color: var(--accent, #9A6B1F);
  display: block;
  margin-block-end: 8px;
}
.j-grade-label{ font-size: 13px; font-weight: 300; }
@media (min-width: 861px){
  .j-grade-ladder{ grid-template-columns: repeat(4, 1fr); }
  .j-grade-step{ padding: 28px 20px; }
}

/* ==========================================================================
   BADGES / PROOF
   ========================================================================== */
.j-badge{
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-alt, #6B7A5E);
  font-weight: 600;
}
.j-badge svg{ width: 17px; height: 17px; }

.j-proof-card{
  border: 1px solid var(--line, #e4dbc7);
  background: #fff;
  border-radius: 4px;
  padding: 34px;
  box-shadow: var(--j-shadow);
}
.j-proof-card .j-ref{
  margin-block-start: 18px;
  padding-block-start: 16px;
  border-block-start: 1px solid var(--line, #e4dbc7);
  font-size: 12px;
  color: var(--accent-alt, #6B7A5E);
}

/* ==========================================================================
   BIDI / NUMERALS
   Latin tokens (grade codes, batch codes) inside Arabic copy — see
   bidiIsolate() in function.php, which wraps tokens in <bdi class="j-bdi">.
   ========================================================================== */
.j-bdi{ unicode-bidi: isolate; }

/* ==========================================================================
   REVEAL-ON-SCROLL (shared with Story-style sections)
   ========================================================================== */
.j-reveal{ opacity: 0; transform: translateY(24px); transition: .8s cubic-bezier(.2,.7,.2,1); }
.j-reveal.in{ opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce){ .j-reveal{ opacity: 1; transform: none; transition: none; } }

/* ==========================================================================
   SITE CHROME — header / nav / footer / cart drawer
   Colors already come from --header-bg/--header-text/--footer-bg/--footer-text
   (repointed to the new palette in the theme DB table) via the legacy
   style.css rules; this section only refines typography, spacing and the
   new nav items on top of that.
   ========================================================================== */
.header-large-device .header-bottom{
  border-block-end: 1px solid var(--line, #e4dbc7);
}
.header-large-device .logo img.logo{ max-height: 52px; width: auto; }

.main-menu nav ul.j-nav,
.clickable-mainmenu-wrap nav ul.j-nav{
  display: flex;
  align-items: center;
  gap: 30px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.clickable-mainmenu-wrap nav ul.j-nav{ flex-direction: column; align-items: flex-start; gap: 4px; }

.j-nav li a{
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--ink, #2B2A28);
  text-decoration: none;
  padding-block: 8px;
  position: relative;
  transition: color .2s;
}
.j-nav li a:hover,
.j-nav li.active a{
  color: var(--accent, #9A6B1F);
}
.j-nav li.j-nav-lang a{
  border: 1px solid var(--line, #e4dbc7);
  padding-inline: 14px;
  border-radius: var(--j-radius);
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.j-nav li.j-nav-lang a:hover{ border-color: var(--accent, #9A6B1F); }

/* ---- footer ---- */
.footer-bottom.border-top-2{ border-block-start: 1px solid rgba(251,247,239,.16); }
.footer-widget .footer-title-2{
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: .04em;
  margin-block-end: 18px;
}
.footer-info-list-2 ul li a{
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 14.5px;
  opacity: .85;
  transition: opacity .2s;
}
.footer-info-list-2 ul li a:hover{ opacity: 1; color: var(--accent-deep, #cba15f); }
.copyright-2 p{ font-family: var(--font-body); font-size: 13px; font-weight: 300; opacity: .75; }

/* ---- cart drawer ---- */
.sidebar-cart-all .cart-content h3,
.sidebar-cart-all .cart-empty h3{
  font-family: var(--font-display);
  font-weight: 600;
}
.sidebar-cart-all .cart-checkout-btn a.cart-btn-style{
  font-family: var(--font-body);
  border-radius: var(--j-radius);
}

/* ==========================================================================
   STORY PAGE — ported from the standalone Story HTML's own <style> block.
   Centralized here (not a page-local <style>) so it's part of the shared
   design system, per Phase 11 of the revamp plan.
   ========================================================================== */
.j-story-hero{
  min-height: 92vh; display: flex; flex-direction: column; justify-content: center;
  position: relative; padding-block: 120px 90px;
  background:
    radial-gradient(120% 90% at 80% 0%, rgba(154,107,31,.10), transparent 60%),
    radial-gradient(120% 90% at 10% 100%, rgba(107,122,94,.10), transparent 55%),
    var(--surface, #FBF7EF);
  overflow: hidden;
}
.j-story-h1{
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(36px, 6.5vw, 88px); line-height: 1.05; letter-spacing: -.01em;
  max-width: 15ch; margin-block-end: 30px; color: var(--ink, #2B2A28);
}
body:not(.en) .j-story-h1{ font-family: var(--font-body); font-weight: 300; line-height: 1.15; }
.j-story-h1 em{ font-style: italic; color: var(--accent, #9A6B1F); }
body:not(.en) .j-story-h1 em{ font-style: normal; font-weight: 500; }
.j-story-mark{
  position: absolute; inset-inline-start: 50%; bottom: 34px; transform: translateX(-50%);
  font-size: 11px; letter-spacing: .3em; text-transform: uppercase; color: var(--accent-alt, #6B7A5E);
  opacity: .7;
}
.j-story-petal{ position: absolute; border-radius: 50% 0 50% 50%; opacity: .07; background: var(--accent, #9A6B1F); }
.j-story-p1{ width: 320px; height: 320px; top: -60px; inset-inline-end: 6%; transform: rotate(25deg); }
.j-story-p2{ width: 180px; height: 180px; bottom: 8%; inset-inline-start: 4%; transform: rotate(-40deg); background: var(--accent-alt, #6B7A5E); opacity: .08; }

.j-story-bloom{ background: var(--ink, #2B2A28); padding-block: 64px; position: relative; overflow: hidden; }
.j-story-bloom-grid{ display: grid; grid-template-columns: 1fr; gap: 44px; align-items: center; }
@media (min-width: 861px){
  .j-story-bloom{ padding-block: 96px; }
  .j-story-bloom-grid{ grid-template-columns: 1fr 1fr; gap: 70px; }
}

/* Bullets under the bloom copy. list-style is dropped for a manual marker so
   the dot sits on the correct side in both LTR and RTL. */
.j-story-bloom-pts{ list-style: none; margin: 26px 0 0; padding: 0; }
.j-story-bloom-pts li{
  position: relative; padding-inline-start: 20px; margin-bottom: 12px;
  font-size: 15.5px; line-height: 1.7; color: rgba(251,247,239,.82);
}
.j-story-bloom-pts li:last-child{ margin-bottom: 0; }
.j-story-bloom-pts li::before{
  content: ""; position: absolute; inset-inline-start: 0; top: .62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-deep, #cba15f);
}

.j-story-cycle{
  aspect-ratio: 1; border: 1px solid rgba(251,247,239,.16); border-radius: 50%;
  display: flex; align-items: center; justify-content: center; position: relative;
  max-width: 360px; margin-inline: auto; width: 100%;
}
.j-story-cycle::before{
  content: ""; position: absolute; inset: 26px; border: 1px dashed rgba(203,161,95,.4);
  border-radius: 50%;
}
.j-story-cycle-core{ text-align: center; }
.j-story-num{ font-family: var(--font-display); font-size: 96px; line-height: 1; color: #cba15f; font-weight: 500; }
.j-story-lbl{ font-size: 13px; letter-spacing: .2em; text-transform: uppercase; color: rgba(251,247,239,.6); margin-block-start: 8px; }
.j-story-bud{ position: absolute; width: 14px; height: 14px; background: #cba15f; border-radius: 50% 0 50% 50%; }
.j-story-b-top{ top: -7px; inset-inline-start: calc(50% - 7px); transform: rotate(45deg); }
.j-story-b-bot{ bottom: -7px; inset-inline-start: calc(50% - 7px); transform: rotate(45deg); opacity: .35; }

.j-story-step-dot{
  width: 54px; height: 54px; border-radius: 50%; background: var(--surface, #FBF7EF); border: 1px solid var(--accent, #9A6B1F);
  color: var(--accent, #9A6B1F); display: flex; align-items: center; justify-content: center; margin: 0 auto 22px;
  font-family: var(--font-display); font-size: 24px; position: relative; z-index: 2;
}
body:not(.en) .j-story-step-dot{ font-family: var(--font-body); font-weight: 500; font-size: 20px; }

.j-story-yr{
  display: inline-block; font-family: var(--font-display); font-size: 26px; font-weight: 600;
  color: var(--surface, #FBF7EF); background: var(--accent, #9A6B1F); width: 70px; height: 70px; line-height: 70px; border-radius: 50%;
  margin-block-end: 20px;
}
body:not(.en) .j-story-yr{ font-family: var(--font-body); font-weight: 600; font-size: 19px; }

.j-story-sig{ font-family: var(--font-display); font-style: italic; font-size: 22px; color: #cba15f; margin-block-start: 44px; }
body:not(.en) .j-story-sig{ font-family: var(--font-body); font-style: normal; font-weight: 400; }

/* ==========================================================================
   PRICE RANGE SLIDER (jQuery UI, Shop page) — plain CSS, deliberately not
   run through Tailwind's @apply pipeline: for reasons not fully root-caused,
   Tailwind 3.4's build silently drops any `@layer components` rule scoped
   under this element's ID when compiled against this project's content
   globs (isolated repro: identical rules under a renamed ID compile fine in
   a clean project; something in this project's PHP corpus + JIT candidate
   extraction interacts badly specifically with ID-prefixed selectors here).
   The jQuery UI plugin ships tiny (~19px) low-contrast handles by default;
   this makes them a real touch target and puts them on-brand. jQuery UI
   positions handles with a physical `left` + `margin-left` regardless of
   page direction, so this stays physical too rather than fighting the
   plugin with logical properties.
   ========================================================================== */
#slider-range.ui-slider{
  position: relative; height: 6px; border-radius: 999px; border: 0;
  background: var(--line, #e4dbc7);
}
#slider-range .ui-slider-range{
  position: absolute; height: 100%; border-radius: 999px;
  background: var(--accent, #C08A2E);
}
#slider-range .ui-slider-handle{
  position: absolute; top: 50%; width: 24px; height: 24px; margin-top: -12px; margin-left: -12px;
  border-radius: 50%; border: 2px solid var(--accent, #C08A2E); background: #fff;
  box-shadow: 0 2px 6px rgba(43,42,40,.25); cursor: grab; outline: none;
}
#slider-range .ui-slider-handle:active{ cursor: grabbing; }
#slider-range .ui-slider-handle:focus-visible{
  box-shadow: 0 0 0 3px rgba(192,138,46,.35);
}

/* ==========================================================================
   PDP gallery — Comvita-style desktop grid
   Below lg the gallery is a slick slider (main.js). At lg+ slick unslicks
   (breakpoint 1008, see main.js) and these rules lay the same children out
   as one full-width main image + 2-across tiles. The :not(.slick-initialized)
   guard means grid rules can never touch a live slick instance (slick's
   destroy removes that class).
   ========================================================================== */
@media (min-width: 1024px) {
  #pdpGallery:not(.slick-initialized) {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
  }
  #pdpGallery:not(.slick-initialized) .pdp-gallery-item:first-child {
    grid-column: 1 / -1;
  }
}
/* Pre-JS flash guard: before slick mounts on mobile, show only the first
   image instead of a tall stack of all slides. */
@media (max-width: 1023.98px) {
  #pdpGallery:not(.slick-initialized) .pdp-gallery-item:not(:first-child) {
    display: none;
  }
}
body.pdp-lightbox-open { overflow: hidden; }

/* ==========================================================================
   Slick pre-init CLS guards (same idea as the #pdpGallery guard above).
   Before main.js initializes Slick, slides render stacked and the section
   is several viewports tall; when Slick mounts they collapse to one slide
   and everything below jumps (measured CLS 0.22 on the homepage hero).
   Single-slide fade carousels show only their first slide pre-init; the
   multi-card certificate rail approximates its final horizontal layout.
   Slick's destroy removes .slick-initialized, so these can never touch a
   live instance.
   ========================================================================== */
.grade-collage-slider:not(.slick-initialized) > div:not(:first-child),
.testimonial-active-7:not(.slick-initialized) > div:not(:first-child) {
  display: none;
}
.certificate-slider:not(.slick-initialized) {
  display: flex;
  overflow: hidden;
}
.certificate-slider:not(.slick-initialized) > * {
  flex: 0 0 25%;
  min-width: 0;
}
@media (max-width: 575.98px) {
  .certificate-slider:not(.slick-initialized) > * {
    flex-basis: 71.4%; /* matches slick's mobile slidesToShow: 1.4 */
  }
}
/* Certificate images have no intrinsic dimensions in markup (DB-driven,
   varied sizes) — reserve a square box up front so cards don't grow when
   the images arrive (this was the last big CLS source after the slider
   stack guards above). */
.certificate-slider .j-card img {
  aspect-ratio: 1 / 1;
  width: 100%;
  object-fit: contain;
}
/* RTL fix: slick.css ships a generic `[dir="rtl"] .slick-slide{float:right}`
   rule keyed off the page's ambient dir attribute — it fires on every AR
   page regardless of Slick's own `rtl` JS option (confirmed live: passing
   `rtl:true`/`false` to .slick() made zero difference here, since Slick's
   getLeft() offset math never lined up with the float:right layout either
   way — a real bug in this vendored Slick build, not a config gap). On AR
   pages this desynced slick-active's "current" bookkeeping from what
   actually rendered in .slick-list's visible area — dots highlighted a
   position that didn't match what was on screen. Forcing float:left here
   (matching main.js, which intentionally leaves `rtl` unset for this
   slider) is the verified fix; text stays RTL, only this rail's internal
   slide flow stays LTR. Needs to beat slick.css's equal-specificity
   ambient-dir rule, hence !important. */
.certificate-slider.slick-initialized .slick-slide {
  float: left !important;
}
/* ==========================================================================
   FULL-BLEED HOMEPAGE HERO (index.php .hero-full)
   Plain min-height, deliberately NOT aspect-ratio-locked — an aspect-ratio
   version was tried and shipped same-day 2026-07-30, then reverted after
   testing on mobile surfaced two real bugs: (1) whenever min-height ended
   up taller than the aspect-derived height (common on phones — 62vh
   comfortably exceeds 100vw/2), CSS's aspect-ratio sizing algorithm treated
   the default "auto" width as free to solve for and computed it as
   height×ratio instead of filling the container (reproduced at 375px: the
   section rendered 1006px wide, blowing out the whole page horizontally);
   (2) even after pinning width:100% to fix that, the same
   min-height-overrides-aspect-height scenario stopped the box from growing
   for content the normal way a plain block does — the CTA buttons rendered
   past the hero's bottom edge, sitting on the next section instead of on
   the image. Both only ever showed up in the "min-height wins" branch
   (mobile) — desktop, where the aspect-derived height was already taller
   than min-height, looked fine, which is exactly what made this easy to
   ship without noticing. Plain min-height (matching .why-parallax, which
   never had either bug) is simple, reliable block-sizing: width always
   fills the container, height always grows for content, on every viewport.
   The trade-off is object-cover crops the source photo by whatever the
   viewport's aspect ratio actually demands — normal for any full-bleed
   hero, and importantly NOT the severe crop from the boss's original
   complaint, which came from a 130%-tall scroll-parallax overscan that no
   longer exists (heroParallax was deleted entirely, see git history).
   Single fixed image only (2026-07-30, at the user's request) — index.php
   only ever renders the first admin-managed row now, no crossfade rotator,
   no .hero-full-slide/.is-active classes any more. No `overflow-hidden` on
   the section: content that needs more height than the min-height floor
   just grows the box, never clips.
   ========================================================================== */
.hero-full{ min-height: 62vh; }
@media (min-width: 768px){ .hero-full{ min-height: 78vh; } }
.hero-full-content{ position: relative; z-index: 2; }
.hero-full-bg{
  position: absolute; inset: 0;
  z-index: 0;
}
.hero-full-bg img{ display: block; }
/* Directionally neutral scrim (works for LTR and RTL text placement):
   darker at top and bottom, lighter mid, keeping cream text readable on
   any uploaded background. */
.hero-full-scrim{
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg,
    rgba(28,27,25,.62) 0%, rgba(28,27,25,.38) 45%, rgba(28,27,25,.56) 100%);
}

/* ==========================================================================
   WHY JARRAH — fixed-reveal parallax, clip-path + position:fixed
   (index.php .why-parallax). karibee.com.au reference: the background
   image itself never moves as the page scrolls over it, and it is only
   ever visible inside this section's box.

   FOUR earlier implementations of this pin were WRONG. Don't reach for
   any of them again:

   (1) CSS `background-attachment: fixed` — confirmed broken on a real
   iPhone 2026-07-30 ("not even working on the scrolling"). Not a
   version-specific bug that gets patched: iOS Safari has never honored it
   for page-level scrolling (deliberate WebKit limitation tied to how iOS
   composites scroll), and there's no sign that changes. Test on a real
   iPhone before believing otherwise.

   (2) A real `position:fixed` layer with `z-index:-1`, toggled by an
   IntersectionObserver. The theory was that negative-z-index would let
   every other in-flow section paint over it for free. In THIS page it
   renders the section as a solid near-black rectangle instead, because
   `.why-parallax` has an opaque `background: var(--ink)` AND does not
   create a stacking context (position:relative + z-index:auto) — so the
   -1 layer escapes up to the <html> stacking context and paints BELOW
   the section's own opaque background. Verified from computed styles, not
   guessed. Negative z-index only works for this pattern when every
   ancestor up to the stacking context is transparent, which is fragile
   and was not true here.

   (3) A normal in-section `position:absolute` layer that main.js
   translated on scroll (`transform: translate3d(0,-rect.top,0)`) to fake a
   pin. This one actually worked, but was janky on mobile: JS scroll events
   fire asynchronously and get coalesced relative to the compositor thread
   during momentum/fling scrolling on iOS, so the counteracting transform
   lags the real scroll position by a frame or more — the image visibly
   swims/jitters instead of reading as pinned. No amount of rAF tuning
   fixes this; it's inherent to driving a "pin" from JS scroll events.

   (4) The "sticky curtain": `position:sticky; top:0; height:100vh;
   margin-bottom:-100vh` as the section's first in-flow child. Smooth
   (compositor-native), but wrong in two user-visible ways. (a) It BLED a
   full viewport-height past the section: sticky's push-out constraint uses
   the MARGIN box, and the equal negative margin collapses that to zero
   height — so the border box was never pushed up at the section's end and
   kept covering the viewport while the NEXT section (Special Offers)
   scrolled over it card-by-card with the beehive image behind them. The
   verification data actually showed this (bg top still 0 when the
   section's own bottom had already passed the viewport top) and was
   misread as a clean release — trust the numbers, not the summary of them.
   (b) Even absent the bleed, sticky rides WITH the section during entry
   and only pins at the top — the reference behavior (karibee.com.au) is an
   image that is motionless from the first revealed pixel.

   What's actually implemented (#5): a `position:fixed` viewport layer,
   hard-clipped to the section by `clip-path: inset(0)` on `.why-parallax`.
   The fixed layer never moves — motionless from the moment the section's
   edge reveals it, exactly the reference behavior — and the clip
   guarantees it can never paint a single pixel outside this section, so
   the trailing-bleed class of bug is structurally impossible. clip-path
   (unlike overflow:hidden, which does NOT clip fixed descendants) clips
   the fixed layer AND creates a stacking context, so the layer needs no
   cooperation from any other section — failure modes (2) and (4a) can't
   recur. Zero per-frame JS; fixed-position + ancestor clip are both
   handled in the compositor's property trees, so scrolling stays smooth on
   iOS/Android/desktop. Guarded by @supports: browsers without clip-path
   keep the plain absolute cover fallback rather than an unclipped fixed
   layer bleeding over the whole page.

   min-height:100vh (100dvh where supported, for mobile browser-chrome
   resizing) on md+ makes the band full-screen, matching the reference.
   (The 130vh from the sticky attempt is gone — that extra travel room
   existed only because sticky needed leftover scroll distance to show its
   pin; a fixed layer is pinned by definition, at any section height.)
   Below md, the source image (1600x800) doesn't have enough native
   resolution to cover a full-screen-tall, content-stacked mobile section
   without visible upscale/pixelation (background-size:cover was measured
   stretching it ~3x past native res on a 375px-wide phone); until a
   higher-res replacement is uploaded via Admin → Why Jarrah Background,
   mobile deliberately runs shorter (content-height only, no min-height
   floor) to keep the upscale factor down — see index.php's matching
   `md:min-h-screen` on .why-parallax-content and the mobile line-clamp on
   the cards, both part of the same mobile height reduction. With >1
   admin-managed slide (admin/v2/whyjarrahbg), main.js crossfades
   .is-active between the stacked layers, same pattern as the hero used to
   have before it was simplified to a single fixed image.
   ========================================================================== */
.why-parallax{
  position: relative;
  background: var(--ink, #1C1B19); /* fallback tone while the image decodes */
}
@media (min-width: 768px){
  .why-parallax{ min-height: 100vh; min-height: 100dvh; }
}
/* Default (no clip-path support / reduced-motion): plain full-section
   cover image — correct, just without the fixed-reveal effect. */
.why-parallax-bg{
  position: absolute; inset: 0; z-index: 0;
}
/* The fixed reveal: a viewport-filling motionless layer, clipped to the
   section's box by the clip-path above. Only enabled where clip-path
   actually clips it — an UNclipped fixed layer would cover the page. */
@supports (clip-path: inset(0)) or (-webkit-clip-path: inset(0)){
  .why-parallax{
    -webkit-clip-path: inset(0);
    clip-path: inset(0);
  }
  .why-parallax-bg{
    position: fixed;
    inset: 0;
  }
}
.why-parallax-slide{
  position: absolute; inset: 0;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  opacity: 0; transition: opacity 1.1s ease;
}
.why-parallax-slide.is-active{ opacity: 1; }
.why-parallax-scrim{
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg,
    rgba(28,27,25,.12) 0%, rgba(28,27,25,.40) 45%, rgba(28,27,25,.74) 100%);
}
.why-parallax-content{ position: relative; z-index: 2; }
@media (prefers-reduced-motion: reduce){
  /* The fixed layer's differential motion (bg holding still while content
     moves) IS the parallax, so under reduced-motion drop it back to a
     plain, correct full-section cover image. Declared after the @supports
     block above so it wins at equal specificity. */
  .why-parallax-bg{ position: absolute; inset: 0; }
  .why-parallax-slide{ transition: none; }
}

/* ==========================================================================
   SCROLL REVEALS — fade + rise for any [data-reveal] element (Why Jarrah
   heading + cards today, reusable elsewhere). IntersectionObserver in
   main.js adds .is-revealed the first time an element crosses ~20% into
   view, then stops watching it — a one-way reveal, never re-hidden.
   Staggered per element via the inline --reveal-delay custom property.
   Fully inert under reduced-motion: elements simply start visible.
   ========================================================================== */
[data-reveal]{
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .7s cubic-bezier(.16,.84,.44,1),
              transform .7s cubic-bezier(.16,.84,.44,1);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-revealed{
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce){
  [data-reveal]{ opacity: 1; transform: none; transition: none; }
}
