/**
 * jensik — Hero slider
 * =======================
 * The homepage's opening component: a horizontal scroll-snap track of
 * full-width slides, each a photograph with the headline set over it.
 *
 * Three things here are load-bearing:
 *
 * 1. The track is a real scrollport, so touch swiping and right-to-left scroll
 *    geometry are the browser's problem and not ours. hero.js only calls
 *    scrollBy and paints the dots; nothing is positioned by script. With the
 *    script blocked the hero is still swipeable and every link is reachable —
 *    so nothing here may hide a slide.
 *
 * 2. The photograph is never mirrored. Every hero crop is shot with a
 *    deliberately empty run on one side and the child on the other, and the
 *    copy sits in that run — placed with logical properties, so in Persian it
 *    lands at the right while the image stays exactly as it was taken. An
 *    `img { transform: scaleX(-1) }` under [dir="rtl"] would be a bug, not a
 *    localisation.
 *
 * 3. The aspect ratio swaps at 768px and so does the artwork, in the
 *    <picture>'s media query and in NK_HERO_ART_BREAKPOINT. The three must
 *    agree — if the CSS switches to 16:9 at a width where the markup is still
 *    serving the 4:3 crop, `object-fit: cover` quietly eats the top and bottom
 *    of a photograph that was composed to fit.
 */

/* -----------------------------------------------------------------------
 * The frame
 * --------------------------------------------------------------------- */

/* Width, centring and the safe-area gutter all come from `.nk-container` on the
   element itself — never re-implemented here. This adds only what is the
   hero's own: a positioning context for the controls, and a little air under
   the sticky header so the artwork does not read as part of the chrome. */
.nk-hero {
  position: relative;
  margin-block-start: var(--nk-space-4);
}

.nk-hero__viewport {
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  border-radius: var(--nk-radius-xl);
  /* An overscroll chain out of the track would bounce the whole page sideways
     on iOS the moment a swipe reaches the last slide. */
  overscroll-behavior-x: contain;
  /* The scrollbar is chrome on a photograph. The track is driven by swipe,
     arrows, dots and the keyboard, so nothing is lost by hiding it. */
  scrollbar-width: none;
}

.nk-hero__viewport::-webkit-scrollbar { display: none; }

/* The track is focusable so it can be scrolled from the keyboard; the ring has
   to be visible against the artwork, so it sits outside the rounded box. */
.nk-hero__viewport:focus-visible {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: var(--nk-focus-ring-offset);
}

/* -----------------------------------------------------------------------
 * A slide
 * --------------------------------------------------------------------- */

.nk-hero__slide {
  position: relative;
  flex: 0 0 100%;
  inline-size: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  /* Without this a flex item refuses to shrink below its content's intrinsic
     width, and one long headline widens every slide — which on a 100% track is
     horizontal overflow on the whole document. */
  min-inline-size: 0;
  isolation: isolate;
  /*
   * A slide paints inside its own box and nowhere else.
   *
   * `isolation` makes a stacking context but clips nothing, so an overflowing
   * decoration inside one slide lands on the next one along — which is exactly
   * how the veil's negative inset above became a visible band on the
   * neighbouring slide. Belt and braces: the inset is correct now, and this
   * makes the next such mistake impossible rather than merely unlikely.
   */
  overflow: hidden;
  /* The ratio is on the slide, not the image, so the box is reserved before
     the picture decodes. Mobile art is 4:3; see the file header. */
  aspect-ratio: var(--nk-ratio-banner-mobile);
}

.nk-hero__media {
  display: block;
  position: absolute;
  inset: 0;
}

.nk-hero__img,
.nk-hero__slide .nk-hero__img {
  /* Two classes: `.woocommerce-page img { max-width: 100%; height: auto }`
     out-specifies a single-class rule on every commerce route, and while the
     hero lives on the homepage today, the block is reusable and would silently
     collapse to auto height the first time it is placed on one.
     See .claude/rules/css.md. */
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* The crop is composed around the child, who is never centred — the empty
     run is what the headline sits in. Anchoring the cover to the block start
     keeps faces in frame when the box is shorter than the art. */
  object-position: center 20%;
  display: block;
}

/* -----------------------------------------------------------------------
 * The copy over the artwork
 * --------------------------------------------------------------------- */

.nk-hero__content {
  position: relative;
  z-index: var(--nk-z-raised);
  block-size: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--nk-space-2);
  padding: var(--nk-space-4);
  /*
   * A lane at the block end for the controls chip, which is absolutely
   * positioned and so contributes nothing to this box's height. Without it the
   * primary CTA and the dots occupy the same band — the chip is centred and the
   * copy is 76% wide, so they overlap horizontally whatever the writing
   * direction — and the button ends up underneath them.
   *
   * The whole column is sized against the shortest case, a 328×246 slide at
   * 360px. The mobile chip is 32px tall and sits 8px off the bottom, so the
   * lane is 48px: 246 − 16 top − 48 lane leaves 182px for the copy. That is
   * why the type steps below are what they are; raising any of them without
   * re-doing this arithmetic pushes the subtitle out of the slide, where the
   * viewport's overflow clips it and it silently disappears.
   */
  padding-block-end: var(--nk-space-12);
  /* The copy takes the empty run of the crop and stops there; running it over
     the child is what makes a hero unreadable. 66% is where it stops clearing
     the boy's head in the 4:3 mobile crop at 360px. */
  max-inline-size: 66%;
}

/*
 * A wash under the copy, not a box.
 *
 * The art already carries a light, near-empty run where the text goes, so this
 * only has to insure against the edge cases — a slide swapped for a busier
 * photograph, or a crop that lands differently at an unusual width. A gradient
 * from the inline start fades to nothing well before it reaches the child.
 * `to left` under RTL is handled by the logical `inset-inline` box below plus
 * the direction-aware gradient keyword, so no [dir] rule is needed.
 */
.nk-hero__content::before {
  content: "";
  position: absolute;
  inset-block: 0;
  /*
   * Flush to the slide's inline-start edge — NOT negative.
   *
   * `.nk-hero__content` is the slide's only in-flow child, so its inline-start
   * edge already *is* the slide's. A negative inset here therefore puts the
   * veil outside its own slide, and since the slides sit side by side in the
   * track with nothing clipping between them, each slide's veil painted a pale
   * 24px band down the neighbouring slide's opposite edge. Every slide but the
   * last one wore one — reported, correctly, as "a curtain on the left".
   *
   * The inline-end stays negative: that end of the gradient is already
   * transparent, and reaching further into the slide only lengthens the fade.
   */
  inset-inline-start: 0;
  inset-inline-end: calc(var(--nk-space-16) * -1);
  z-index: -1;
  pointer-events: none;
}

.nk-hero__slide--light .nk-hero__content::before { background: var(--nk-veil-light); }
.nk-hero__slide--dark .nk-hero__content::before { background: var(--nk-veil-dark); }

/* The veil tokens are authored left-to-right and this copy sits at the inline
   start, so in Persian the strong end has to be at the right instead. Flipping
   the pseudo-element is safer than a second pair of tokens: it cannot drift
   from the originals, and the box holds nothing but the gradient.
   An intentional [dir="rtl"] rule — counted in the jensik-ui skill,
   references/mobile-rtl-a11y.md. */
[dir="rtl"] .nk-hero__content::before {
  scale: -1 1;
}

.nk-hero__eyebrow {
  margin: 0;
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-xs);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-accent);
}

.nk-hero__title {
  margin: 0;
  font-family: var(--nk-font-display);
  /* 20px at 360px, stepping up with the box at 480, 768 and 1024. Bold display
     Vazirmatn reads a size larger than it measures, and this is what the
     arithmetic on .nk-hero__content allows: at 24px the headline takes a fourth
     line and the subtitle leaves the slide. */
  font-size: var(--nk-text-xl);
  font-weight: var(--nk-weight-bold);
  line-height: var(--nk-leading-tight);
  color: var(--nk-text-strong);
  /* Persian is cursive — never track it positively. Pulling it very slightly
     tight at display sizes is safe because it does not break the joins. */
  letter-spacing: var(--nk-tracking-tight);
  text-wrap: balance;
}

.nk-hero__title-accent {
  display: block;
  color: var(--nk-text-accent);
}

.nk-hero__text {
  margin: 0;
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-default);
  /*
   * Clamped rather than trusted. The shop owner types this field, and a
   * sentence one line longer than the box has room for does not wrap
   * gracefully — it pushes the CTA past the artwork's edge, where the
   * viewport's overflow clips it and the slide loses its only link. One line
   * at 360px, where there is room for exactly one.
   */
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Styled from the parent rather than a class of its own: nk_button() prints its
   own class attribute and has no `class` argument, so a class passed through
   `attrs` becomes a second one and is dropped. See inc/hero.php. */
/*
 * On a phone the hero CTA is the `sm` button, not the default `md`.
 *
 * At 360px the slide is 328×246 and the copy column 66% of it, so a full-size
 * primary button was ~190px of a 184px column: it filled the crop's empty run
 * edge to edge and read as a banner ad rather than a link out of a photograph,
 * with the accent glow blooming another 24px of coral past its own box. The
 * geometry below is `.nk-btn--sm`'s exactly — its type, padding, gap, icon and
 * radius — so this is a smaller documented size, not a fourth one; only the
 * shadow is ours, dropped to the neutral small one. `md` returns at 768px with
 * the 16:9 crop, where the column is 52% of a far wider slide.
 *
 * The block axis does not shrink: `min-block-size` stays at the 44px touch
 * target, which is also what `--sm` itself takes under `pointer: coarse`. How
 * easy the button is to hit is unrelated to how loud it looks.
 */
.nk-hero__content .nk-btn {
  margin-block-start: var(--nk-space-1);
  flex: none;
  min-block-size: var(--nk-touch-target);
  padding-inline: var(--nk-space-3);
  padding-block: var(--nk-space-2);
  gap: var(--nk-space-1);
  font-size: var(--nk-text-base);
  border-radius: var(--nk-radius-sm);
  /*
   * The copy column is deliberately narrow — it has to clear the child in the
   * crop — and at 360px that is 184px of inside width against a 190px button,
   * so "مشاهده محصولات" broke across two lines and the button grew to 58px.
   * A wrapped label on a primary CTA reads as a layout fault. It absorbs the
   * 6px out of the column's own padding and still lands well inside the slide.
   */
  white-space: nowrap;
}

.nk-hero__content .nk-btn--primary { box-shadow: var(--nk-shadow-sm); }

.nk-hero__content .nk-btn .nk-icon {
  inline-size: var(--nk-icon-sm);
  block-size: var(--nk-icon-sm);
}

/* Dark artwork: the copy inverts, the accent lifts to a tint that still clears
   AA on navy — coral-700 there is 3.01:1 and fails at body size. */
.nk-hero__slide--dark .nk-hero__title,
.nk-hero__slide--dark .nk-hero__text {
  color: var(--nk-text-inverse);
}

.nk-hero__slide--dark .nk-hero__eyebrow,
.nk-hero__slide--dark .nk-hero__title-accent {
  color: var(--nk-text-accent-inverse);
}

/* -----------------------------------------------------------------------
 * Controls
 *
 * Printed `hidden` by the PHP and revealed by hero.js — a dot that cannot move
 * the track is worse than no dot, the same rule the product rails follow.
 * --------------------------------------------------------------------- */

/*
 * On a phone the chip is the dots and nothing else — no ground, no shadow, no
 * blur. A 360px slide is 328×246, and a floating pill with a background took a
 * visible bite out of the photograph for controls that are only a hint: the
 * gesture there is the swipe. From 768px up the chip earns its ground back,
 * because it is carrying arrows too and sits on a much larger picture.
 *
 * The *targets* stay 44px throughout — only the ground and the marks got
 * smaller. Shrinking the hit area was the first attempt and it was wrong: it
 * bought back sixteen pixels of a photograph by making every control harder to
 * hit on the device the whole design is for. Flush to the block end so a 44px
 * box still reads as a small mark near the edge.
 */
.nk-hero__controls {
  position: absolute;
  inset-block-end: 0;
  /*
   * Centred on the artwork, which both reference comps do — and which is the
   * only placement that is not wrong in one writing direction. Pinned to a
   * side, the chip either lands under the copy (inline start) or on top of the
   * child the crop is composed around (inline end); centred, it sits in the
   * dead ground below both. `inset-inline: 0` plus `margin-inline: auto` rather
   * than a transform, so the chip is centred on the hero's padding box and
   * needs no counter-translation in RTL.
   */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: fit-content;
  z-index: var(--nk-z-raised);
  display: flex;
  align-items: center;
  gap: 0;
  padding: 0;
  border-radius: var(--nk-radius-pill);
}

.nk-hero__controls[hidden] { display: none; }

/* The arrows are desktop affordances. On a phone the gesture is the swipe, and
   two 44px targets over a 360px photograph cost more than they return. */
.nk-hero__arrow { display: none; }

.nk-hero__dots {
  display: flex;
  align-items: center;
  gap: var(--nk-space-half);
}

/*
 * The dot is a full touch target with a small visible mark inside it, rather
 * than a small button. Shrinking the hit area to the size of the dot is the
 * usual mistake and fails WCAG 2.5.5 by a wide margin.
 *
 * 44px everywhere, including mobile where the chip around them is invisible.
 * A transparent target costs no pixels of artwork — only the reserved lane
 * does — so there is nothing to buy by shrinking it.
 */
.nk-hero__dot {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  inline-size: var(--nk-touch-target);
  block-size: var(--nk-touch-target);
  display: grid;
  place-items: center;
  border-radius: var(--nk-radius-pill);
  color: inherit;
}

/*
 * Fill plus ring, so the mark survives whatever is behind it.
 *
 * The chip has no ground on mobile now, and a flat mark in any single colour
 * disappears against half the catalogue — cream on a bright wall, navy on a
 * dark interior. The two --nk-mark-media tokens are a translucent navy fill
 * with a cream hairline: whichever the photograph swallows, the other reads.
 * Cheaper and steadier than putting a panel back under it.
 */
.nk-hero__dot > span {
  display: block;
  inline-size: var(--nk-space-2);
  block-size: var(--nk-space-2);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-mark-media);
  box-shadow: 0 0 0 1px var(--nk-mark-media-ring);
  transition: background-color var(--nk-transition-base),
    inline-size var(--nk-duration-normal) var(--nk-ease-standard);
}

/* Selected is never signalled by colour alone: the mark also changes shape,
   from a dot to a short bar. */
/* The active mark keeps the ring on mobile: coral on a coral-toned photograph
   would otherwise vanish exactly where it matters most. */
.nk-hero__dot[aria-selected="true"] > span {
  inline-size: var(--nk-space-5);
  background-color: var(--nk-action-primary);
}

@media (hover: hover) {
  .nk-hero__dot:hover > span { background-color: var(--nk-navy-700); }
  .nk-hero__dot[aria-selected="true"]:hover > span { background-color: var(--nk-action-primary-hover); }
}

.nk-hero__dot:active > span { background-color: var(--nk-action-primary-active); }

.nk-hero__dot:focus-visible {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: calc(var(--nk-focus-ring-offset) * -1);
}

/* -----------------------------------------------------------------------
 * Fade transition
 *
 * The slides stop being a scrollport and become a single-cell grid — every
 * slide in the same cell, one visible at a time. Grid rather than absolute
 * positioning so the tallest slide still sizes the box and the aspect-ratio
 * work above keeps holding.
 *
 * Keyed off `data-nk-transition`, which **hero.js writes** after resolving the
 * `hero_transition` setting. The default, `auto`, means "fade where there is a
 * real pointer, slide on touch": sliding necessarily shows part of the
 * neighbouring slide for the length of the animation, which is unwanted on
 * desktop and *correct* on touch, where the visitor's own finger is dragging
 * it. A media query cannot express that on its own, because the script has to
 * agree with it — one attribute, written once, keeps CSS and JS from drifting.
 *
 * No JS ⇒ no attribute ⇒ the plain scroll-snap slider above, which is the
 * right fallback: swipeable, and every link reachable.
 * --------------------------------------------------------------------- */

.nk-hero__viewport[data-nk-transition="fade"] {
  display: grid;
  overflow: hidden;
  scroll-snap-type: none;
}

.nk-hero__viewport[data-nk-transition="fade"] > .nk-hero__slide {
  grid-area: 1 / 1;
  inline-size: 100%;
  opacity: 0;
  transition: opacity var(--nk-duration-slow) var(--nk-ease-standard);
  /*
   * Only the visible slide takes pointer input. Without this the stack's last
   * child sits on top of every other slide and swallows clicks meant for the
   * CTA underneath it — `inert` handles the keyboard and the assistive tree,
   * but a mouse would still land on the wrong slide.
   */
  pointer-events: none;
}

/* The current slide is marked by JS, and — like the reveal layer — nothing is
   hidden until the script says so. */
.nk-hero__viewport[data-nk-transition="fade"] > .nk-hero__slide[data-nk-current] {
  opacity: 1;
  pointer-events: auto;
}

/* -----------------------------------------------------------------------
 * Responsive
 *
 * Three steps, at three of the project's six breakpoints. More media queries
 * than a component normally wants, and deliberate: this one has to fit editable
 * copy inside a photograph whose height is a fixed ratio of the viewport, so
 * the type scale genuinely is a function of the width and there is no token
 * that already expresses it. Each step is sized against that breakpoint's real
 * box, not stepped for its own sake.
 * --------------------------------------------------------------------- */

/* 480px — the 4:3 box reaches ~330px tall, which buys back the headline size
   and a second line of subtitle. */
@media (min-width: 480px) {
  .nk-hero__content {
    max-inline-size: 68%;
    padding: var(--nk-space-6);
    padding-block-end: var(--nk-space-16);
  }

  .nk-hero__title { font-size: var(--nk-text-2xl); }
  .nk-hero__text { -webkit-line-clamp: 2; }
}

/* 768px — the artwork swaps to the 16:9 desktop crop, matching the <picture>
   media query and NK_HERO_ART_BREAKPOINT. All three must agree: switch the
   ratio at a width where the markup still serves the 4:3 file and object-fit
   quietly crops the top and bottom off a composed photograph. */
@media (min-width: 768px) {
  .nk-hero { margin-block-start: var(--nk-space-6); }

  .nk-hero__viewport { border-radius: var(--nk-radius-2xl); }

  /* The chip earns its ground back: it is carrying arrows now, and it sits on
     a much larger picture. See the note on .nk-hero__controls. */
  .nk-hero__controls {
    inset-block-end: var(--nk-space-4);
    gap: var(--nk-space-1);
    padding: var(--nk-space-1);
    background-color: var(--nk-surface-floating);
    box-shadow: var(--nk-shadow-sm);
  }

  /* On the chip's own ground the ring is noise — the contrast is settled. */
  .nk-hero__dot > span,
  .nk-hero__dot[aria-selected="true"] > span {
    box-shadow: none;
  }

  .nk-hero__dot > span { background-color: var(--nk-navy-300); }

  @media (hover: hover) {
    .nk-hero__dot:hover > span { background-color: var(--nk-navy-500); }
  }

  .nk-hero__slide { aspect-ratio: var(--nk-ratio-banner); }

  .nk-hero__content {
    max-inline-size: 52%;
    padding: var(--nk-space-8);
    /* The chip is back to 44px and sits 16px off the bottom, so the lane
       grows again: 44 + 16 + a little air. */
    padding-block-end: var(--nk-space-16);
    gap: var(--nk-space-3);
  }

  /* The CTA goes back to the default `md` button — see the note on
     .nk-hero__content .nk-btn for why it is smaller below this width. */
  .nk-hero__content .nk-btn {
    padding-inline: var(--nk-space-5);
    padding-block: var(--nk-space-3);
    gap: var(--nk-space-2);
    font-size: var(--nk-text-md);
    border-radius: var(--nk-radius-md);
  }

  .nk-hero__content .nk-btn--primary { box-shadow: var(--nk-shadow-accent); }

  .nk-hero__content .nk-btn .nk-icon {
    inline-size: var(--nk-icon-md);
    block-size: var(--nk-icon-md);
  }

  .nk-hero__eyebrow { font-size: var(--nk-text-sm); }
  /* 28px, not the 44px --nk-text-5xl reads at this width: 16:9 of a 720px
     slide is only 405px tall, and the larger size took four lines and pushed
     the subtitle out of the frame entirely. */
  .nk-hero__title { font-size: var(--nk-text-3xl); }
  .nk-hero__text { font-size: var(--nk-text-base); }

  .nk-hero__arrow {
    appearance: none;
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
    inline-size: var(--nk-touch-target);
    block-size: var(--nk-touch-target);
    display: grid;
    place-items: center;
    border-radius: var(--nk-radius-pill);
    color: var(--nk-text-muted);
    transition: color var(--nk-transition-base), background-color var(--nk-transition-base);
  }

  @media (hover: hover) {
    .nk-hero__arrow:hover {
      color: var(--nk-text-strong);
      background-color: var(--nk-action-secondary-subtle);
    }
  }

  .nk-hero__arrow:active { color: var(--nk-text-strong); }

  .nk-hero__arrow:focus-visible {
    outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
    outline-offset: calc(var(--nk-focus-ring-offset) * -1);
  }

  .nk-hero__arrow:disabled {
    color: var(--nk-action-disabled-text);
    cursor: not-allowed;
  }
}

/* 1024px — the slide is now ~550px tall and the hero can carry display type. */
@media (min-width: 1024px) {
  .nk-hero__content {
    max-inline-size: 48%;
    padding: var(--nk-space-12);
    padding-block-end: var(--nk-space-16);
    gap: var(--nk-space-4);
  }

  .nk-hero__title { font-size: var(--nk-text-5xl); }
  .nk-hero__text { font-size: var(--nk-text-lg); -webkit-line-clamp: 3; }
}

/* -----------------------------------------------------------------------
 * Reduced motion
 *
 * The duration tokens are already zeroed globally, but `scroll-behavior` is
 * not a token and a smooth programmatic scroll is exactly the sideways
 * movement this preference is about. hero.js also refuses to autoplay at all.
 * --------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .nk-hero__viewport { scroll-behavior: auto; }
  .nk-hero__dot > span { transition: none; }
}
