/* ==========================================================================
   Sarir Mode — base layer
   Reset, document defaults, accessibility. No components yet.
   Physical properties (margin-left, right, text-align: left) are forbidden;
   everything here is logical so RTL mirrors with no second stylesheet.
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Reserve the scrollbar gutter always, so locking overflow when the menu
     opens does not shift the page. */
  scrollbar-gutter: stable;
}

body {
  min-block-size: 100vh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-primary);
  font-size: var(--fs-base);
  font-weight: var(--fw-normal);
  font-stretch: var(--font-stretch-normal); /* pins Yekan Bakh to normal width */
  line-height: var(--lh-normal);
  text-align: start;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-primary);
  font-weight: var(--fw-light);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}

p, li {
  text-wrap: pretty;
}

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

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

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

a {
  color: inherit;
  text-decoration: none;
}

ul, ol {
  padding-inline-start: 0;
  list-style: none;
}

hr {
  border: 0;
  border-block-start: var(--rule-width) solid var(--color-rule);
}

/* --------------------------------------------------------------------------
   Accessibility
   -------------------------------------------------------------------------- */

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

.sarir-skip-link {
  position: absolute;
  inset-block-start: -100%;
  inset-inline-start: var(--space-4);
  z-index: 999;
  padding: var(--space-3) var(--space-5);
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
}

.sarir-skip-link:focus {
  inset-block-start: var(--space-4);
}

.screen-reader-text {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

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

/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */

.sarir-container {
  inline-size: 100%;
  max-inline-size: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.sarir-container--narrow {
  max-inline-size: var(--container-narrow);
}

/* --------------------------------------------------------------------------
   Icons
   -------------------------------------------------------------------------- */

.sarir-icon {
  display: inline-block; /* over the global svg { display: block } reset */
  vertical-align: middle;
  flex-shrink: 0;
  /* Size comes from width/height + viewBox on the <svg> tag, never from CSS. */
  /* NOTE, phase 9j §A: the reset's `max-inline-size: 100%` still applies here,
     so an icon's min-content is 0 and a zone with no floor of its own can
     squeeze it to nothing — that is how the menu button was 0px wide on every
     phone for fifteen days. `max-inline-size: none` was specified as the fix
     and measured NOT to be one: with the header's floor in place (see
     .sarir-header) it changed 0 of 198 icon renders across six pages, five
     widths and the open overlay, where the defect restored squashed 30. A
     rule that measurably does nothing does not ship. The floor belongs to the
     zone that holds the control. */
}

/* Directional glyphs are the ONE thing that flips explicitly. Object icons
   (textile, manufacturing, people, retail) must never be mirrored. */
[dir="rtl"] .sarir-icon--directional {
  transform: scaleX(-1);
}

/* --------------------------------------------------------------------------
   Logo
   -------------------------------------------------------------------------- */

/* The Latin wordmark is 12:1, the Persian one 5.4:1. Lock the WIDTH and the
   Persian logo renders twice as tall. The eye compares logos by height, so
   height is locked and width runs free. */
.sarir-logo {
  display: block;
  block-size: 1.25rem;
  inline-size: auto;
}

/* --------------------------------------------------------------------------
   Header — the bar, and the two navigation copies it holds

   Structure follows the Inditex reference (docs/phase-4-step-3-header.md):
   a fixed-height sticky bar; inline nav + a horizontal-rail panel from 64rem
   up; a hamburger + full-screen <dialog> below it. Colour, type and spacing
   are the Brand Book's own tokens throughout — none of Inditex's.
   -------------------------------------------------------------------------- */

/* BELOW 64rem THE WORDMARK IS CENTRED AND SCALES, never below --logo-min —
   Sarir's decision, phase 9j §A4. `1fr auto 1fr` centres only while both
   sides fit; on a phone the codes (78px) and the button (24px) are unequal, so
   it pushed the wordmark 81px off centre. Below 64rem both sides reserve
   --header-side, and the wordmark's column takes what is left — the logo SVG
   is compressible, which here is what lets it scale.

   The START side's reservation is the first track's minimum, and it YIELDS:
   min() takes the tools side, the floor and the two gaps from the header's
   width. 100% there is the header's own content box, so an unrelated page
   overflow cannot move it (it did, when this was written against 100vw: the
   homepage's item list overflows below 308px, and the emulated 100vw followed
   it). max(1.5rem, …) is the menu button's own width, the 24px icon: the
   yield stops there. The TOOLS side's reservation is on the language list
   (.sarir-langs--bar, below), where a min-inline-size raises the content's
   floor instead of replacing it — so a fourth language widens the column
   rather than spilling into the wordmark. On a grid ITEM it would have
   replaced it: measured, a 4px column under a 24px button.

   The order things give way in, narrowest last: centring, then the floor,
   never the button or the codes. Measured: centred to the pixel from 356px,
   144px at 360; at 320 exactly 140 and 18px off centre; at 280 the floor goes
   too, to 120, and the button and codes stay whole. */
.sarir-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 10;
  display: grid;
  grid-template-columns:
    minmax(max(1.5rem, min(var(--header-side), 100% - var(--header-side) - var(--logo-min) - 2 * var(--space-2))), 1fr)
    auto
    1fr;
  column-gap: var(--space-2);
  align-items: center;
  block-size: var(--header-h);
  padding-inline: var(--gutter);
  background: var(--color-bg);
  border-block-end: var(--rule-width) solid var(--color-rule);
}

.sarir-header__start {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  grid-column: 1;
}

.sarir-header__home {
  grid-column: 2;
}

.sarir-header__tools {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-5);
}

/* The search placeholder does nothing at any width (TODO(search)) and the
   reference shows none on a phone, measured at 360 and 390. Restored from
   64rem, where the search step will wire it. */
.sarir-header__tools .sarir-search-toggle {
  display: none;
}

/* The bar's language switcher below 64rem: the CODES, Fa | En | Ar, with 9b's
   hairline between them. The markup carries both labels (inc/i18n.php, 'both');
   this shows one, and the 64rem block below swaps them. Scoped under
   .sarir-header, (0,2,0), so it beats `.sarir-langs` further down this file on
   SPECIFICITY rather than on where it happens to sit — the trap CLAUDE.md
   records twice. space-2, not the overlay's space-3: the tightest step that
   keeps two adjacent links' centres 24px apart (WCAG 2.5.8), and the one that
   fits --header-side. */
.sarir-header .sarir-langs--bar {
  gap: var(--space-2);
  /* The tools side's half of the reservation; see .sarir-header. */
  min-inline-size: var(--header-side);
  justify-content: flex-end;
}

.sarir-header .sarir-langs--bar li + li {
  border-inline-start: var(--rule-width) solid var(--color-rule-strong);
  padding-inline-start: var(--space-2);
  line-height: 1;
}

.sarir-header .sarir-langs--bar .sarir-langs__name {
  display: none;
}

/* TWO breakpoints, as of phase 9e. Custom properties cannot be read inside
   @media, so each is written literally at the one place it is used.

   64rem, here: the bar-and-rail pair replaces the full-screen overlay. A
   layout decision.
   40rem, at .sarir-subnav__title: the sub-nav title is hidden below it. NOT a
   layout decision — it is the width at which the title's text stops colliding
   with a link's, measured across eight widths in three languages. The reason
   is written beside that rule.

   This note used to say "One breakpoint". It is corrected rather than left to
   contradict the second one. */
.sarir-header__nav {
  display: none;
}

@media (min-width: 64rem) {
  .sarir-menu-open {
    display: none;
  }

  .sarir-header__nav {
    display: block;
  }

  /* Phase 9j §A: every phone-only rule is released here, in the one place the
     64rem breakpoint is written, and the desktop is exactly what it was —
     measured, every header box identical at 1024 and 1440 in three languages. */
  .sarir-header {
    grid-template-columns: 1fr auto 1fr;
    column-gap: normal;
  }

  .sarir-header__tools .sarir-search-toggle {
    display: revert;
  }

  .sarir-header .sarir-langs--bar {
    gap: var(--space-3);
    min-inline-size: auto;
    justify-content: normal;
  }

  .sarir-header .sarir-langs--bar li + li {
    border-inline-start: none;
    padding-inline-start: 0;
    line-height: inherit;
  }

  .sarir-header .sarir-langs--bar .sarir-langs__name {
    display: revert;
  }

  .sarir-header .sarir-langs--bar .sarir-langs__code {
    display: none;
  }
}

/* ---- the bar's inline nav items ---- */

.sarir-header__navlist {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

/* Sibling dimming, the bar half: at rest every entry sits dim, and the one
   under the pointer rises. The opposite of "highlight what you hover" — it is
   the siblings that change, and the effect reads as focus rather than
   decoration. No :has() needed; source order and specificity do it. */
.sarir-header__navitem {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-sm);
  font-weight: var(--fw-normal);
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-dim);
  text-decoration: none;
  transition: color var(--dur-menu) var(--ease-menu);
}

/* Two separate ideas, one trigger, so one rule. The COLOUR is the sibling
   dimming above — this entry rises while the others stay dim. The UNDERLINE
   is "this entry's rail section is the active one", in the text colour and
   never Vin Cuit, because a nav item is not a call to action. The focus RING
   is the global :focus-visible rule; the underline is additive to it, not a
   replacement. */
.sarir-header__navitem:hover,
.sarir-header__navitem:focus-visible,
.sarir-header__navitem[aria-expanded="true"] {
  color: var(--color-text);
  text-decoration: underline;
  text-decoration-color: var(--color-text);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
}

/* ---- the desktop panel: ONE horizontal rail, not a dropdown per entry ---- */

.sarir-header__panel {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%; /* .sarir-header is sticky, so this is positioned */
  background: var(--color-bg);
  border-block-end: var(--rule-width) solid var(--color-rule);
  padding-block: var(--space-6);
}

/* The rail is a viewport, not a scroll container: no scrollbar, no drag, no
   snap, and scrollLeft stays 0 forever. The track inside it moves. */
.sarir-header__rail {
  overflow: hidden;
  padding-inline: var(--gutter);
}

/* THE STRIDE IS EXACTLY --rail-item.
   Of the two ways to reconcile stride with the gap between sections, this
   takes the first: gap is 0 and the space between sections lives INSIDE each
   section as padding-inline-end. With the global border-box sizing,
   flex: 0 0 var(--rail-item) makes the section exactly one stride wide,
   padding included, so translate never has to know the gap exists. The
   alternative — a real gap folded into the calc — puts the same number in two
   places, and when they drift the carousel is off by one gap from the third
   section onward. */
.sarir-header__track {
  display: flex;
  gap: 0;
  --i: 0;
  --dir: 1;
  translate: calc(var(--rail-item) * -1 * var(--i) * var(--dir)) 0;
  transition: translate var(--dur-menu) var(--ease-menu);
}

/* flex already lays the sections out right-to-left under RTL, so only the
   SIGN of the movement needs mirroring — not the layout. */
[dir="rtl"] .sarir-header__track {
  --dir: -1;
}

.sarir-header__section {
  flex: 0 0 var(--rail-item);
  padding-inline-end: var(--space-8); /* the between-sections gap, folded in */
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-6);
  opacity: 0.25; /* measured on inditex.com */
  transition: opacity var(--dur-menu) var(--ease-menu);
}

.sarir-header__section[data-active="true"] {
  opacity: 1;
}

/* Sibling dimming, the links half. Same invariant as the bar above — the
   hovered item is at full strength and every sibling recedes — but the
   resting state is the opposite one, because a section's links sit at full
   strength until the pointer enters the list. */
.sarir-header__section-links a {
  display: block;
  font-size: var(--fs-sm);
  font-weight: var(--fw-light);
  color: var(--color-text);
  padding-block: var(--space-2);
  transition: color var(--dur-menu) var(--ease-menu);
}

.sarir-header__section-links:hover a {
  color: var(--color-text-dim);
}

.sarir-header__section-links a:hover {
  color: var(--color-text);
}

/* No photography yet — phase 5 wires this to a menu-item image field. An
   empty, correctly-proportioned ground so the layout is real today and the
   real photograph drops into the same box later. */
/* The section's photograph in the open rail — phase 9f.

   244px WIDE because that is the reference's own width, measured twice at
   1440: six images, 244x178 rendered, 244x178 natural, served at exactly
   display size. The width is what the eye reads across a row of six.

   4/3 RATIO because it is ours, and 244/178 = 1.371 is not a named ratio —
   it reads as a pixel size somebody chose rather than a ratio derived from
   anything. The 5px of height that differ are invisible; a third ratio in a
   vocabulary that has 16/9 and 4/3 is not. So the box is 244 x 183.

   The warm ground is GONE. It was a stand-in for a photograph, and an empty
   slot now renders the woven placeholder through sarir_media_slot() — the
   same renderer and the same empty-state as every other media slot on the
   site, which is what phase 9d built it for. A warm rectangle and a woven
   placeholder in the same page are two answers to one question. */
.sarir-header__figure {
  inline-size: 15.25rem; /* 244px */
  aspect-ratio: 4 / 3;
}

/* The slot's own children fill it. sarir_media_slot() writes the aspect-ratio
   inline, so this only has to make the box fill its parent and crop. */
.sarir-header__figure > * {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Full-screen menu overlay
   -------------------------------------------------------------------------- */

.sarir-menu {
  inline-size: 100%;
  max-inline-size: 100%;
  block-size: 100%;
  max-block-size: 100%;
  margin: 0;
  border: 0;
  padding: 0;
  background: var(--color-bg);
  color: var(--color-text);
  overflow-y: auto;
}

/* Author CSS beats the UA stylesheet regardless of specificity, so a bare
   `.sarir-menu { display: flex }` would override dialog:not([open]) {
   display: none } and leave the CLOSED dialog rendered and tabbable. Scope
   the flex layout to [open], the same way [hidden] is respected below. */
.sarir-menu[open] {
  display: flex;
  flex-direction: column;
}

/* var(--c-black) cannot be split into r/g/b channels for a literal rgb()
   without relative-colour syntax, so color-mix() stands in — 40% Midnight
   Black, same token the rest of the theme uses, never a hand-picked value. */
.sarir-menu::backdrop {
  background: color-mix(in srgb, var(--c-black) 40%, transparent);
}

/* The head stacks: the close label above a wordmark that is deliberately
   larger than the closed header's. It does not line up with the header — the
   wordmark moves on purpose. */
.sarir-menu__head {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--space-4);
  padding-block: var(--space-5);
  padding-inline: var(--gutter);
}

.sarir-menu__head .sarir-logo {
  block-size: 2.25rem;
}

.sarir-menu-close {
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-kicker);
  color: var(--color-text-muted);
}

/* Persian and Arabic have no uppercase: text-transform does nothing to most
   of their glyphs and mangles a few. Latin only. */
:lang(en) .sarir-menu-close {
  text-transform: uppercase;
}

.sarir-menu__nav {
  flex: 1;
  padding: var(--space-6) var(--gutter);
}

.sarir-menu__toggle,
.sarir-menu__link {
  display: flex;
  align-items: center;
  inline-size: 100%;
  font-size: var(--fs-lg);
  font-weight: var(--fw-light);
  letter-spacing: var(--tracking-display);
  color: var(--color-text-muted);
  padding-block: var(--space-3);
}

/* Weight tells you which row is open: the closed rows recede, the open one
   is the subject of the screen. */
.sarir-menu__toggle[aria-expanded="true"],
.sarir-menu__toggle:hover,
.sarir-menu__link:hover,
.sarir-menu__toggle:focus-visible,
.sarir-menu__link:focus-visible {
  color: var(--color-text);
}

/* The chevron shows only on the open row, pointing up. opacity rather than
   display, so the row does not reflow when it appears.

   Recorded, not to act on: this removes the only visual hint that a collapsed
   row opens rather than navigates. aria-expanded covers screen-reader users;
   a sighted user now has to discover it. If review finds that confusing, the
   middle path is opacity 0.25 here rather than 0. */
.sarir-menu__toggle .sarir-icon {
  margin-inline-start: auto;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.sarir-menu__toggle[aria-expanded="true"] .sarir-icon {
  opacity: 1;
  transform: rotate(180deg);
}

.sarir-menu__submenu a {
  display: block;
  font-size: var(--fs-base);
  color: var(--color-text-muted);
  padding-block: var(--space-2);
  padding-inline-start: var(--space-4);
}

/* A class `display` would beat the bare [hidden] UA rule, so state it. */
.sarir-menu__submenu[hidden] {
  display: none;
}

/* One utility row over a hairline, not a stack. */
.sarir-menu__foot {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-6) var(--gutter);
  border-block-start: var(--rule-width) solid var(--color-rule);
}

.sarir-menu__foot .sarir-search-toggle {
  margin-inline-start: auto;
}

/* Language switcher. Same sibling-dimming idea as the nav: the language you
   are already in sits at full strength and is not a link; the others recede
   until hovered. */
.sarir-langs {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-wide);
}

.sarir-langs__link {
  color: var(--color-text-dim);
  transition: color var(--dur-menu) var(--ease-menu);
}

.sarir-langs__link:hover,
.sarir-langs__link:focus-visible {
  color: var(--color-text);
}

.sarir-langs__current {
  color: var(--color-text);
}

/* Phase 9b: the overlay's codes — Fa | En | Ar — separated by a hairline on the
   inline-start edge of every item but the first.

   A BORDER, NOT THE MIDDOT THE SPECIFICATION DRAFTED, and that was decided by
   measurement. Built first as `content: "·"` on ::after, it reached assistive
   technology verbatim. Chrome's accessibility tree carried StaticText "·" after
   each code, and Windows UI Automation — what Narrator reads — named the list
   items `Fa·` and `En·` (U+00B7 inside the name) and read the line as
   "Fa· / En· / Ar". A separator that is spoken twice per language switch is
   noise in the one control a reader uses to find their own language. A border
   is painted and never announced.

   Stone Gray, which the contrast table allows for rules. Logical edge, so it
   sits on the correct side of each item in both directions with no [dir]. */
.sarir-langs--overlay li + li {
  border-inline-start: var(--rule-width) solid var(--color-rule-strong);
  padding-inline-start: var(--space-3);
  line-height: 1;
}

/* translateY, not translateX: a vertical move reads the same in both
   directions; a horizontal one would need mirroring under RTL. */
@media (prefers-reduced-motion: no-preference) {
  .sarir-menu[open] {
    animation: sarir-menu-in var(--dur-base) var(--ease-out);
  }
}

@keyframes sarir-menu-in {
  from {
    opacity: 0;
    transform: translateY(-1rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.sarir-scroll-locked {
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   Footer — band four of the page grammar: the dense footer, the one place
   small multi-column type is allowed.

   Legible, not designed. Enough to judge as a footer and no more; the ground
   colour is deliberately NOT decided here. Midnight Black inverse would be a
   strong choice and --color-bg-inverse exists, but that is a composition
   decision that belongs with the homepage bands in phase 6. White for now.
   -------------------------------------------------------------------------- */

.sarir-footer {
  padding-block: var(--space-9);
  padding-inline: var(--gutter);
  border-block-start: var(--rule-width) solid var(--color-rule);
}

/* auto-fit mirrors itself under RTL with no [dir] override. */
.sarir-footer__nav {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-7) var(--space-6);
}

.sarir-footer__head {
  font-size: var(--fs-2xs);
  /* The next three used to arrive for free from the `h1, h2 …` base rule,
     and phase 9 made this a <p> — each column is now a <nav> named by its
     title, and the titles left the heading list. Measured after the tag
     swap and before this was added: weight 300 -> 400, line-height 16.1px
     -> 23.1px, every head 7px taller. Restated here so the change is to the
     accessibility tree and not to the pixels. */
  font-weight: var(--fw-light);
  line-height: var(--lh-tight);
  text-wrap: balance;
  letter-spacing: var(--tracking-kicker);
  margin-block-end: var(--space-4);
}

/* Same precedent as the overlay's close label: Persian and Arabic have no
   uppercase, so scope the transform to Latin. */
:lang(en) .sarir-footer__head {
  text-transform: uppercase;
}

.sarir-footer__col a {
  display: block;
  font-size: var(--fs-sm);
  color: var(--color-text-dim);
  padding-block: var(--space-2);
  transition: color var(--dur-menu) var(--ease-menu);
}

.sarir-footer__col a:hover,
.sarir-footer__col a:focus-visible {
  color: var(--color-text);
}

.sarir-footer__base {
  margin-block-start: var(--space-8);
  display: flex;
  align-items: center;
  gap: var(--space-5);
  border-block-start: var(--rule-width) solid var(--color-rule);
  padding-block-start: var(--space-5);
}

.sarir-footer__copy {
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Editorial link — the site's default call to action, and about 90% of them.

   Midnight Black, small, uppercase, letterspaced, with a 1px Vin Cuit
   underline. Vin Cuit is the colour of ATTENTION and at most one Vin Cuit
   element may appear in a viewport, so it appears here as a rule and never as
   text: Vin Cuit at body size is 3.58:1 and fails contrast, while the same
   colour as a 1px rule under black text is exactly what it is allowed to be.

   The reference site's version of this link carries no underline at all. This
   one does, because the underline is the Sarir signal inside the Inditex form
   — the tier-1 treatment recorded in CLAUDE.md — and dropping it would leave
   an 11px black label that reads as a caption rather than a link.

   Hover changes the underline and nothing else. text-decoration-thickness
   rather than a border, so growing it does not push the next line down by a
   pixel; that shift was invisible inside the old preview card and would not be
   invisible under a statement.
   -------------------------------------------------------------------------- */

.sarir-link {
  display: inline-block;
  color: var(--color-text);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-kicker);
  /* The rule is drawn by ::after, not by text-decoration. Measured that way on
     the reference, and the reason is visible once you look: an underline that
     is part of the text box has to clear the descenders, so it sits either too
     close to them or too far from the word. A positioned rule sits where the
     design wants it. It also means hover can thicken it without the
     text-decoration-thickness transition, which not every engine animates. */
  position: relative;
  padding-block-end: var(--space-2);
  transition: color var(--dur-fast) var(--ease-out);
}

.sarir-link::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: 1px;
  background: var(--color-cta);
  transition:
    block-size var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

/* Persian and Arabic have no uppercase. Same precedent as the footer heads. */
:lang(en) .sarir-link {
  text-transform: uppercase;
}

.sarir-link:hover::after,
.sarir-link:focus-visible::after {
  block-size: 2px;
  background: var(--color-cta-hover);
}

/* --------------------------------------------------------------------------
   Homepage — the band sequence

   docs/phase-6-homepage-wireframe.md, with the band ORDER from
   docs/phase-6-addendum-audience.md. Bands are separated by whitespace and by
   nothing else: no borders, no cards, no shaded panels. If a band here ever
   seems to need a box to make sense, the band is wrong.

   TWO ABSENCES, both measured on the reference and both deliberate. Neither is
   an unfinished piece of work:

     1. No scroll-triggered entrance animation anywhere on this page. Every
        band is opacity 1 before it is scrolled to.
     2. No :hover rule on any band, image or item container. Nothing zooms,
        lifts, tints or shifts.

   .sarir-link is the single exception and is not a band effect: it is the
   site's link treatment, it changes an underline, and a link that answers the
   pointer with nothing at all is a defect.
   -------------------------------------------------------------------------- */

/* The gap between bands, and the ONLY thing between them. A margin on the
   following band rather than a flex gap, so a band can still be full-bleed.

   Both selectors say .sarir-band deliberately, not `* + *`: the first child of
   .sarir-home is the visually-hidden <h1>, and `* + *` would count it as a
   sibling and push the hero 160px down the page, away from the header it is
   supposed to sit under. It takes no space itself — it is positioned — so the
   symptom would be a gap with nothing in it. */
.sarir-band + .sarir-band {
  margin-block-start: var(--band-gap);
}

/* The last band needs the same air beneath it before the footer rule. */
.sarir-home {
  padding-block-end: var(--band-gap);
}

/* ---- 1. Hero -------------------------------------------------------------
   89vh, not 100vh, and that 11% is the whole point: a sliver of the next band
   shows below the fold, which is what tells the reader there is a page under
   this. A full-height hero looks like a dead end. */

.sarir-hero {
  block-size: 89vh;
  /* svh is the SMALL viewport height — the one that ignores a mobile
     browser's collapsing toolbar. Without it, 89vh on a phone is measured
     against a viewport taller than the one actually visible, the sliver
     disappears and the hero reads as full height again. Older engines ignore
     this line and keep the vh above. */
  block-size: 89svh;
  overflow: hidden;
}

/* Two class names, on purpose. The .sarir-weave block further down sets
   block-size: auto — right for every other slot, whose height comes from an
   inline aspect-ratio — and it comes LATER in this file, so at equal
   specificity it wins. The hero is the one slot sized by its band instead of
   by a ratio, and an <svg> that loses this fight does not collapse: it falls
   back to the SVG default of 150px, which looks like a deliberate short band
   rather than a bug. Measured at 1425x150 before this rule existed. Winning on
   specificity rather than on source order keeps it fixed if the file is ever
   reordered. */
.sarir-hero .sarir-hero__media {
  inline-size: 100%;
  block-size: 100%;
}

/* ---- 2 / 4 / 6. Statement ------------------------------------------------
   32px / 42px / weight 300, CENTRED, in a 992px column inside a 1024px
   wrapper.

   THIS IS A CORRECTION, and the previous version of this block is worth
   knowing about because of HOW it was wrong. Phase 6 recorded the statement as
   20px / 24px / weight 400 / 0.8px tracking / left-aligned — every value of it
   wrong, and all from one mistake. The reference's statement is an <h4> inside
   a wrapper <div>. The WRAPPER computes to 20/24/400/0.8px; the <h4> that
   actually paints the glyphs computes to 32/42/100/normal. Phase 6 read the
   wrapper and reported it as the text.

   Font properties inherit, so a container will always hand back a
   plausible-looking number for something it is not setting. Read type off the
   element that paints the glyphs.

   Phase 6 also had CLAUDE.md changed from "centred statement" to
   left-aligned on the strength of that reading. It had been right.

   Weight: the measurement says 100, which does not exist in Manrope — its
   lightest cut is 200, and we load 300. --fw-light it is. A second webfont
   file costs more than the difference is worth. Recorded here so a later
   session reading 100 in the phase 7b document does not think the build
   drifted. */

.sarir-statement__inner,
.sarir-media__inner {
  max-inline-size: var(--container-statement); /* 1024px border box */
  margin-inline: auto;
  padding-inline: var(--space-4);              /* leaves a 992px content box */
  text-align: center;
}

.sarir-statement__text {
  font-size: var(--fs-statement);
  font-weight: var(--fw-light);
  letter-spacing: var(--tracking-normal);
  line-height: var(--lh-statement);
  margin-block-end: var(--space-6);
}

/* The supporting texts under a brand's opening statement: the same voice, one
   step down.

   THE MODIFIER CARRIES ITS OWN WEIGHT, and that is the fix rather than a
   nicety — phase 9j §B2. `front-page.php` writes this class in six places
   WITHOUT the base, which is legitimate: the base also carries a bottom margin
   that belongs to the homepage band, and adding it there would move every
   band. With only size and line-height here the weight fell through to the
   body's 400, so the homepage's supporting voice was 400 while the brands page
   and every inner page were 300 — measured 2026-09-23 from Chrome's own
   cascade, which reported `font-weight: (not set by any rule — inherited)` on
   the homepage's `--sm` and `var(--fw-light)` everywhere else.

   A modifier that reads the same with or without its base cannot acquire that
   difference again. */
.sarir-statement__text--sm {
  font-size: var(--fs-statement-sm);
  font-weight: var(--fw-light);
  line-height: var(--lh-statement-sm);
}

/* ---- 2. A named-item list -------------------------------------------------
   Four capabilities under OUR DIFFERENCE, two modes under PARTNERSHIPS. The
   band's statement is the voice; these are the set beneath it.

   IT REPLACES `.sarir-architecture`, which is DELETED rather than left beside
   it. That band — three columns of labels where the reference has three
   figures — is gone with the content document: Sarir's homepage names four
   capabilities instead. The reasoning it carried is worth keeping and lives in
   CLAUDE.md, where the numbers-band decision is recorded; two contradicting
   layouts in one stylesheet is how the next session picks the wrong one.

   auto-fit wraps to two on a phone and mirrors itself under RTL with no [dir]
   override, which is the whole reason the grid is written this way. */

.sarir-itemlist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-8) var(--space-6);
  margin-block-start: var(--space-8);
}

/* Two items read as a pair rather than as a row that happens to have two in
   it: they hold half the width each and stop stretching. */
.sarir-itemlist--pair {
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

.sarir-itemlist__label {
  font-size: var(--fs-md);
  letter-spacing: var(--tracking-subtle);
  margin-block-end: var(--space-3);
}

:lang(en) .sarir-itemlist__label {
  text-transform: uppercase;
}

.sarir-itemlist__text {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* ---- 3. The value chain ---------------------------------------------------
   Four stages, each with the portrait that shows it. The four portraits were a
   band of their own until content v2 — four pictures in a row with no words,
   which said nothing about which part of the company each one was. Same
   images, same 3:4 crop, now carrying their stage's name and line.

   The gap is --space-6 rather than the portrait band's --space-2: those
   almost-touched so they read as one picture, and these are four separate
   things that each have a label. */

.sarir-chain__head {
  font-size: var(--fs-xl);
  font-weight: var(--fw-light);
  letter-spacing: var(--tracking-normal);
  margin-block-end: var(--space-6);
  text-align: center;
}

:lang(en) .sarir-chain__head {
  text-transform: uppercase;
}

.sarir-chain__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-6) var(--space-5);
  margin-block-start: var(--space-8);
}

.sarir-chain__media {
  margin-block-end: var(--space-4);
}

.sarir-chain__label {
  font-size: var(--fs-md);
  letter-spacing: var(--tracking-subtle);
  margin-block-end: var(--space-2);
}

:lang(en) .sarir-chain__label {
  text-transform: uppercase;
}

.sarir-chain__text {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* ---- 7. The three brands ------------------------------------------------- */

.sarir-brandband__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-6);
}

.sarir-brandband__link {
  display: grid;
  gap: var(--space-3);
}

.sarir-brandband__media img {
  inline-size: 100%;
}

.sarir-brandband__name {
  font-size: var(--fs-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-tight);
}

.sarir-brandband__line {
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-kicker);
  color: var(--color-text-muted);
}

:lang(en) .sarir-brandband__line {
  text-transform: uppercase;
}

/* The one hover on this band, and it is the link's underline, not the item's.
   Scoped to the name so the strapline and the image stay still: the whole
   item is the hit area, but only the name behaves like a link. */
.sarir-brandband__link:hover .sarir-brandband__name,
.sarir-brandband__link:focus-visible .sarir-brandband__name {
  text-decoration: underline;
  text-decoration-color: var(--color-cta);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
}

/* ---- 8. Feature: people --------------------------------------------------
   The one emotional band, and the page's close. Heading large and very light,
   image beneath it, link beneath that. */

.sarir-feature__head {
  max-inline-size: var(--container-statement);
  font-size: var(--fs-xl);
  font-weight: var(--fw-light);
  margin-block-end: var(--space-7);
}

.sarir-feature__media {
  margin-block-end: var(--space-6);
}

/* Phase 9c: a photograph in a homepage slot, from the Home page's fields. It
   takes the slot's geometry the way the weave does — the ratio inline, per
   slot, from front-page.php — and crops into it rather than letterboxing. The
   hero sets no ratio: `.sarir-hero .sarir-hero__media` is (0,2,0) and gives it
   the band's height over this rule's `auto`, on specificity, not position. */
.sarir-home__photo {
  display: block;
  inline-size: 100%;
  block-size: auto;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Scroll reveal

   A REVERSAL, recorded as one. Phase 6 measured "no scroll-triggered entrance
   animation" and built the absence deliberately. Phase 7b found
   `.text-cta__animation` on the reference computing to `opacity: 0;
   translateY(100px)` below the fold and `opacity: 1; translateY(0)` above it,
   six times on the homepage alone. The mechanism was there all along; phase 6
   measured the elements that had already been revealed.

   Sarir decided on 2026-09-12 to build it. See CLAUDE.md, where the decision
   is recorded together with the wrong version it replaces.

   THE UNREVEALED STATE IS NEVER IN THE BASE CSS. `.sarir-reveal` on its own
   paints normally; only `.sarir-reveal--armed`, which nothing but
   assets/js/reveal.js ever adds, hides anything. Put `opacity: 0` in the base
   rule and a scripting failure leaves a blank page — which is not a
   hypothetical, it is how this exact pattern usually fails. The gate is the
   script itself rather than a generic `.js` class on <html>, because a `.js`
   class would still arm the elements if the reveal script alone failed to
   load.
   -------------------------------------------------------------------------- */

.sarir-reveal--armed {
  opacity: 0;
  transform: translateY(100px);
}

.sarir-reveal--in {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}

/* Off entirely, not merely faster. A 100px rise is exactly the motion this
   query exists for, and the global transition-duration override further up
   would leave the transform snapping rather than removing it. */
@media (prefers-reduced-motion: reduce) {
  .sarir-reveal--armed,
  .sarir-reveal--in {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   TEMPORARY — the woven placeholder that stands in for photography.

   Delete this block together with inc/placeholder.php and
   assets/icons/placeholder.svg. Everything it styles disappears with it.
   -------------------------------------------------------------------------- */

.sarir-weave {
  display: block;
  inline-size: 100%;
  /* Over the global svg { block-size: auto } reset, which would otherwise let
     an <svg> with no height attribute fall back to its default 150px — the
     same trap the icon sprite hit in phase 3. aspect-ratio is set inline per
     slot, so the height follows from the width; the hero sets none and is
     stretched to its band instead. */
  block-size: auto;
  background: var(--c-berber-30);
}

/* The weave's own threads, inside the <pattern>. See placeholder.svg for why
   this is a custom property and not currentColor. */
.sarir-weave__thread {
  fill: none;
  stroke: var(--weave-ink);
  /* 6 against a 48 pitch. Butt caps, left at the default on purpose: a square
     thread end is what makes the pass under the crossing thread read as a
     pass. Round caps would close the gap back up optically. */
  stroke-width: 6;
}

/* --------------------------------------------------------------------------
   Fallback template — search results, 404, anything with no richer template.
   Plain on purpose: phase 7 designs the inner pages, and a half-designed
   archive here would have to be undone first.
   -------------------------------------------------------------------------- */

.sarir-page {
  padding-block: var(--space-9);
}

.sarir-page__title {
  font-size: var(--fs-xl);
  margin-block-end: var(--space-7);
}

.sarir-page__entry + .sarir-page__entry {
  margin-block-start: var(--space-7);
}

.sarir-page__entry-title {
  font-size: var(--fs-lg);
  margin-block-end: var(--space-3);
}

/* --------------------------------------------------------------------------
   Inner pages — one template, and the sub-navigation that makes it work

   docs/phase-7-inner-pages.md. Every inner page is the same object: an <h1>,
   a sticky sub-navigation of that page's own in-page anchors, and a sequence
   of anchor-separated sections built from the homepage's band vocabulary.
   Nothing below forks a homepage band; it adds the chrome around them.

   The smooth scroll these anchors ride on is NOT declared here. `html {
   scroll-behavior: smooth }` and its prefers-reduced-motion override have been
   at the top of this file since phase 2, which is where they belong — they are
   document behaviour, not a component's.
   -------------------------------------------------------------------------- */

/* `.sarir-inner__head` and `.sarir-inner__title` are DELETED, not commented
   out beside their replacement — phase 9e, and the same rule the 7c statement
   column was removed under: two contradicting instructions in a file is how
   the next session picks the wrong one.

   What they were: a full band, 185.59px tall, holding a 64px <h1>. Measured on
   the reference, every inner page's <h1> is `sr-only` and the visible name at
   the start of the sticky bar is a different element that is not a heading.
   The <h1> now carries `.screen-reader-text`, the same class the homepage's
   has always used, and `.sarir-subnav__title` below is the visible name.

   The consequence, measured at 1440: the bar moves from y=257.59 to y=72,
   directly under the header, which is where the reference puts it. The gap
   between the bar and the first content band was 0 before and is 0 after —
   that relationship is untouched. */

/* ---- The sub-navigation --------------------------------------------------
   Sticky, not fixed. Sticky participates in layout, so the content below it
   does not need a compensating margin that would then have to be kept in sync
   with the bar's height — the class of bug --scroll-offset exists to prevent. */

.sarir-subnav {
  position: sticky;
  inset-block-start: var(--header-h);
  z-index: 9; /* under the header, which is 10 */
  /* The token IS the rendered height, not a guess about it. --scroll-offset is
     built from this value, so if the bar were allowed to size itself to its
     content, every anchor on the page would land a few pixels off. */
  block-size: var(--subnav-h);
  background: var(--color-bg);
  border-block-end: var(--rule-width) solid var(--color-rule);
  overflow-x: auto;
  overflow-y: hidden;
  /* Three brands fit. Fourteen sustainability anchors will not, and the bar
     must scroll rather than wrap — wrapping would make it two rows tall and
     silently invalidate --scroll-offset. */
  overscroll-behavior-inline: contain;
  /* Room for the focus ring when subnav.js scrolls a focused entry into view.
     The global :focus-visible ring is 2px wide at a 3px offset, so it reaches
     5px beyond the link's box; scrollIntoView honours scroll-padding, and 8px
     keeps the whole ring inside the bar rather than flush against its edge.
     Phase 9 measured the ring cut off at 400px without this. */
  scroll-padding-inline: var(--space-2);
  /* Hidden, not absent: the bar still scrolls by touch, trackpad and by
     tabbing through it. A visible horizontal scrollbar inside a 56px bar eats
     the height the links need. */
  scrollbar-width: none;
}

.sarir-subnav::-webkit-scrollbar {
  display: none;
}

/* The page's name at the start of the bar — phase 9e.

   `position: absolute` IS THE MECHANISM, NOT A DETAIL, and this is the one
   line in this block that must not be changed for tidiness. It earns its place
   on BOTH axes, and the second reason was found by trying to break the first.

   HORIZONTAL — the reason the specification gives. The track carries
   `justify-content: safe center`, and centring distributes the FREE SPACE of
   the flex container. Move this title INTO `.sarir-subnav__inner` and it eats
   some of that space, so every link shifts off-centre — and it would look
   almost right, which is the worst kind of wrong. Measured by doing it: the
   links move by (title + one flex gap) / 2, which is 72.74px on
   `/group/our-story/` and 98.23px on `/group/vision-approach/`, matching the
   prediction to 0.01px on all six pages that have a title.

   VERTICAL — and this one is ours, because our markup is not the reference's.
   The title is a SIBLING of the track, not a member of it, so simply removing
   `position: absolute` does NOT move the links sideways at all; the first
   negative control asserted it would and reported six false failures. What it
   actually does is make the title a block ABOVE the track inside a bar that is
   exactly `--subnav-h` tall: measured, the track drops 19.8px (LTR) and
   22.19px (RTL) and the bar's contents no longer fit its own height — which
   would silently invalidate `--scroll-offset`, since that token is built from
   this bar's height.

   So a later session tidying this away breaks the layout one way or the other
   depending on where it moves the element, and criterion 6 now measures both.

   NOT the reference's own 20px/16px insets. Its bar is a different height, so
   copying a padding would misalign the title with our links; `inset-block: 0`
   plus centring derives the position from our bar instead. Same reasoning as
   --scroll-offset: derive it, never type the number.

   The type is not a new object. `--fs-xs` is 12px and `--tracking-subtle` is
   0.04em — 0.48px at that size — which are the reference's measured 12px and
   0.48px exactly, and they are already what a sub-nav link uses. Only the
   colour differs: the title is full Midnight Black, an inactive link is the
   60% token. */
.sarir-subnav__title {
  /* HIDDEN BELOW 40rem, and the breakpoint is a measurement — see the media
     query at the end of this block. */
  display: none;
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  align-items: center;
  /* The same gutter the track uses, so the title and a start-aligned first
     link land on one vertical line rather than two a few pixels apart. */
  padding-inline-start: var(--gutter);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-subtle);
  color: var(--color-text);
  white-space: nowrap;
  /* It is aria-hidden and it is not a link. Letting it swallow pointer events
     would make the start of the bar dead to a click that was aimed at the
     track behind it. */
  pointer-events: none;
}

/* THE NARROW-WIDTH RULE, CHOSEN FROM A MEASUREMENT — phase 9e §4.1, which is
   the one thing the reference does not answer.

   An absolute title over a centred link row collides at narrow widths, and the
   collision is text on text, not box on box. Measured across eight widths, in
   all three languages, as the overlap of the title's own text rect with the
   nearest link's:

       400px   Our Story 12.48  ·  Vision & Approach 49.53  ·  fa 50.11  ·  ar 24.33
       480px   0                ·  44.30              ·  fa 50.11  ·  ar 0
       560px   0                ·  6.10               ·  fa 30.25  ·  ar 0
       640px   0                ·  0                  ·  fa 0      ·  ar 0

   Zero from 640px up, in every language and on every page that has a title. So
   the breakpoint is 40rem because that is where the measurement says the
   overlap ends, not because it is a round number.

   TWO REJECTED ALTERNATIVES, both of which the specification offered first:

   - Reserving the title's width in the track's `padding-inline-start`. The
     reservation is a NUMBER THAT CANNOT SEE THE TITLE'S LENGTH: 56.5px of text
     for "Our Story", 107.47px for "Vision & Approach", 94.48px for its Persian.
     Size it for the longest and the links sit off-centre on the shortest; size
     it for today and the overlap returns silently the day somebody renames a
     page. It also shifts the centre the moment the links fit, which is what
     criterion 6 exists to protect.
   - Making the title a flex item in the track at narrow widths. No magic
     number and no overlap — but it puts a non-link, at link size, in a row of
     links, and the one thing that tells a reader it is not a link is that it
     sits apart from them.

   The cost, stated because it is a real loss: BELOW 640px THE PAGE HAS NO
   VISIBLE NAME. The <h1> is still in the document, so assistive technology is
   unaffected, and the header's menu still says which section you are in — but
   a sighted phone reader does not see "Our Story" anywhere on the page. That
   is the price of the bar staying one row tall, and it is Sarir's to overturn.

   This is the file's SECOND breakpoint. The note at the top of the stylesheet
   said "One breakpoint" and has been corrected rather than left to contradict
   this one. */
@media (min-width: 40rem) {
  .sarir-subnav__title {
    display: flex;
  }
}

.sarir-subnav__inner {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  block-size: 100%;
  padding-inline: var(--gutter);
  /* Keeps the last link clear of the edge when the bar is scrolled to its end
     under both directions. */
  inline-size: max-content;
  min-inline-size: 100%;
  /* SAFE centre, and the `safe` is the whole point.

     When the links fit, the inner is 100% wide — its min-inline-size — there
     is free space, and they centre. When they do not fit, the inner is
     max-content, wider than the bar, there is no free space to distribute, and
     they sit at the leading edge while the bar scrolls.

     Plain `center` breaks the second case: centred overflow spills equally in
     BOTH directions, and the first items become unreachable because you cannot
     scroll into negative space. `safe` falls back to `start` at exactly that
     point. Three Latin brand names will not overflow at 1440px; fourteen
     anchors at 400px will, and so might three Persian names. The narrowest
     viewport sets the constraint, not the widest. */
  justify-content: safe center;
}

.sarir-subnav__link {
  flex-shrink: 0;
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-subtle);
  /* NOT uppercase, unlike every other small label on this site. Measured that
     way on the reference, and it is right: a table of contents is read, not
     scanned, and these are proper nouns. */
  color: var(--color-text-dim);
  white-space: nowrap;
  /* The border is ALWAYS present and only its colour changes — transparent
     when inactive, the text colour when active. Giving the border only to the
     active link would add a pixel to that link's height and nudge the whole
     row every time the highlight moved. The reference avoids it the same way,
     with white rather than transparent; transparent is the same trick and
     survives a change of ground colour. */
  border-block-end: var(--rule-width) solid transparent;
  transition:
    color var(--dur-menu) var(--ease-menu),
    border-color var(--dur-menu) var(--ease-menu);
}

/* The site-wide 60% rule, third appearance: active is full Midnight Black,
   everything else is the same 60% alpha as the nav bar and the rail links.
   See CLAUDE.md — this is a rule, not a component style. */
.sarir-subnav__link[aria-current="true"],
.sarir-subnav__link:hover,
.sarir-subnav__link:focus-visible {
  color: var(--color-text);
  border-block-end-color: var(--color-text);
}

/* ---- The anchor ---------------------------------------------------------- */

/* The one property this whole mechanism turns on. Without it an anchor jump
   puts the section's first line underneath the header and the sub-nav, and the
   reader lands on text they cannot see. Logical, not scroll-margin-top: it is
   the one that stays correct if a page ever scrolls in another direction.

   The second selector is phase 7c: on a PAGE, a section is an <h2> the editor
   gave an HTML anchor to, and it carries no class of ours. Rewriting the
   rendered content to add one would mean rewriting an editor's markup on every
   request to set a property a selector can reach for free. */
.sarir-anchor,
.sarir-page__content h2[id] {
  scroll-margin-block-start: var(--scroll-offset);
}

/* THERE IS A LINE BETWEEN BRANDS, and phase 7 recorded that there was not.

   Phase 7 measured a 33px wrapper and concluded 33px of nothing. Inside that
   wrapper is an <hr>: 1px, full bleed, with 16px of its own margin. The same
   error as the statement typography — reading a container and reporting its
   contents — in a different place on the same day, which is what makes it a
   pattern rather than a slip.

   Our page grammar forbids rules between BANDS and that still stands. This
   line is not between bands, it is between BRANDS: a boundary between two long
   stories, which is exactly what a hairline is for. The grammar is amended
   with that distinction rather than the line being treated as a breach of it.

   NOTE the deleted `.sarir-anchor + .sarir-anchor` rule. Putting a separator
   element between two anchors breaks adjacent-sibling selectors — the same
   trap the zero-height anchor marker hit in phase 7 — so the boundary spacing
   moved onto the separator itself and nothing competes to space the same
   joint. */

.sarir-brandsep {
  margin-block: var(--band-gap);
  /* flow-root, and it is load-bearing rather than tidy. Without it the <hr>'s
     own 16px margins COLLAPSE THROUGH this wrapper — the wrapper has no
     padding or border to stop them — and merge with the 160px outside, which
     wins because collapsed margins take the larger. Measured: the boundary
     came to 321px instead of 353, and the rule sat hard against the space
     rather than in the middle of its own 33px. flow-root establishes a block
     formatting context, which is the one-property way to contain them. */
  display: flow-root;
}

.sarir-brandsep hr {
  margin-block: var(--space-4);
  border-block-start: var(--rule-width) solid var(--color-text);
}

/* Blocks INSIDE one brand sit at half the distance. The eye reads the tighter
   spacing as "still the same brand", which is the whole reason for the pair —
   see --band-gap-tight, which is derived from --band-gap rather than typed. */
.sarir-brandpage > .sarir-band + .sarir-band {
  margin-block-start: var(--band-gap-tight);
}

/* ---- A brand on the brands page ------------------------------------------ */

.sarir-brandpage__name {
  font-size: var(--fs-xl);
  font-weight: var(--fw-light);
}

.sarir-brandpage__line {
  margin-block-start: var(--space-3);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-kicker);
  color: var(--color-text-muted);
}

:lang(en) .sarir-brandpage__line {
  text-transform: uppercase;
}

.sarir-brandpage__body {
  margin-block-start: var(--space-5);
}

/* ---- The media band ------------------------------------------------------
   In the SAME 992px column as the text, not merely contained and not
   full-bleed. That is what makes a brand read as one object rather than as
   text interrupted by pictures. The homepage hero is the exception; inside a
   brand nothing is full-bleed. */

/* THE RATIO HAS TWO CONSUMERS AND ONE SOURCE — phase 9h.

   A FIELD slot writes the ratio into its own style attribute (since 9d), and
   an inline declaration beats any stylesheet, so those slots ask
   sarir_ratio() in PHP. A BLOCK slot has no inline ratio and is sized here.
   Both read the same setting; the fallback below is the token file's value and
   the acceptance run checks the two paths compute the same number. */
.sarir-media img,
.sarir-media video,
.sarir-media .sarir-weave {
  inline-size: 100%;
  aspect-ratio: var(--ratio-media, 16 / 9);
  object-fit: cover;
}

/* THE ONE !important OUTSIDE THE REDUCED-MOTION BLOCK, and it is here because
   it is overriding an INLINE style rather than another rule.

   core/video's render callback writes `style="aspect-ratio: W / H"` onto the
   <video> from the attachment's real dimensions — deliberately, to stop the
   page jumping while the file loads, and with a comment in core saying attr()
   would be the better answer if browsers supported it. An inline declaration
   beats any selector, so without this a 4:3 clip would sit in a 4:3 box inside
   a 16:9 slot and the row of sections would stop lining up.

   Forcing the ratio is what the slot already does to an <img>, and object-fit:
   cover means it crops rather than distorts. Scoped to .sarir-media, so a
   video anywhere else keeps core's behaviour. */
.sarir-media video {
  aspect-ratio: 16 / 9 !important;
}

/* FULL BLEED — phase 9j §C2, built 2026-09-25 on the specification approved
   2026-09-21. Sarir has asked for this three times; before it, the editor's
   "Full width" button was measured doing NOTHING: 992px with the class and
   992px without it, which is the 9d finding in another place — a control that
   silently does nothing is worse than none, because the editor believes the
   picture was placed.

   ONE CLASS, BOTH PATHS. `.alignfull` is what core already writes when an
   editor presses Full width, so the block path needs no PHP at all; the FIELD
   path puts the same class on its own wrapper from a switch beside the field.
   The two paths are then not "consistent" by inspection — they are the same
   rule, and a mutation of it moves both.

   `cqi`, NEVER `vw`, AND THAT IS THE WHOLE TRAP. `100vw` is the viewport
   INCLUDING the classic scrollbar, so a full-bleed band built on it is ~15px
   wider than the page on every desktop and the document scrolls sideways for
   ever after. `100cqi` is the inline size of the nearest container, and <main>
   is exactly the client width. This file has been bitten by `vw` once already
   — see the header's start track, where an emulated `100vw` followed an
   unrelated page overflow. Measured here: scrollWidth === clientWidth at every
   width tested, in all three languages.

   <main> IS THE CONTAINER, not <body>: the containment context is as small as
   it can be, the <dialog> overlay and the header sit outside it, and this
   theme has no `position: fixed` anywhere for layout containment to catch.

   `main .alignfull` is (0,1,1) ON PURPOSE. `.sarir-media__inner` is (0,1,0)
   and so is a bare `.alignfull`, and equal specificity is decided by source
   order — the trap this file records twice, once at 400 lines' distance. The
   element selector wins the argument outright instead.

   The margin is the classic breakout, in the same unit as the width so the two
   cannot disagree: half the container minus half the element, which is zero
   when the wrapper is already full-bleed (the brand band) and the exact pull
   when it is not (a block in the 992 column). */
main {
  container-type: inline-size;
}

main .alignfull {
  inline-size: 100cqi;
  max-inline-size: none;
  margin-inline: calc(50% - 50cqi);
}

/* A full-bleed slot has no business keeping the column's side padding: that is
   what made it a 992px box in the first place. */
main .sarir-media__inner.alignfull,
main .sarir-feature__media.alignfull {
  padding-inline: 0;
}

/* SARIR'S PAUSE BUTTON — phase 9j §C1. The browser's native bar is removed on
   the server, on both paths; this is what replaces it, and only when Sarir's
   switch is on. `assets/js/media.js` builds it as a real <button>, so Enter,
   Space and the focus ring come from the element rather than from us.

   ITS CONTAINING BLOCK IS A FRAME THE SCRIPT BUILDS AROUND THE VIDEO, and this
   REPLACES what stood here — §C1b, 2026-09-25, from Sarir's screenshot. The
   rule used to read

       .sarir-media, .sarir-media figure, .sarir-home__media { position: relative }

   with a comment claiming "the host is whatever wraps the <video>: a figure on
   the block path, the slot's own div on the field path". MEASURED, that was
   true of neither path. The homepage's video is a child of
   `div.sarir-band.sarir-hero`, which is static and has no positioned ancestor,
   so the containing block was the INITIAL one and the button's bottom was the
   VIEWPORT's: 888 at a 900px viewport, 588 at 600px. It looked right only
   because the hero is 89svh. On /brands/ the nearest positioned ancestor was
   the full-bleed `.sarir-media` band, 1425px wide around a 992px video, so the
   button sat 205px from the video it controls. One root cause, two shapes: the
   element given `position: relative` was not the video's box.

   A frame built in the script IS that box, on every path — see the docblock in
   media.js for why it is built there and not in PHP. Nothing else needed those
   three selectors: the pause button is the only absolutely positioned thing
   inside a media slot.

   `inset-inline-end` and `inset-block-end`, never right/bottom — the button
   sits at the trailing corner and MIRRORS under RTL, which is the whole of
   what hard rule 7 is for. Measured in all three languages.

   Midnight Black on White at 18.88:1, and the editorial link's own type: this
   is a control, not a call to action, so no Vin Cuit. */
.sarir-media__frame {
  position: relative;
}

/* The hero is the ONE slot sized by its band rather than by its own ratio —
   `.sarir-hero .sarir-hero__media` above says so and sets the video to
   `block-size: 100%`. With the frame between them that percentage resolves
   against the frame, so the frame needs the band's height or the video
   collapses. Measured: 1425x801 at a 900px viewport, unchanged by the frame. */
.sarir-hero .sarir-media__frame {
  block-size: 100%;
}

.sarir-media__pause {
  position: absolute;
  inset-inline-end: var(--space-3);
  inset-block-end: var(--space-3);
  z-index: 2;

  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--c-black);
  background: var(--c-white);
  color: var(--c-black);

  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-regular);
  letter-spacing: var(--tracking-subtle);
  text-transform: uppercase;
  cursor: pointer;
}

:lang(fa) .sarir-media__pause,
:lang(ar) .sarir-media__pause {
  /* Persian and Arabic have no case, and the tracking is already 0 in those
     languages' token block. */
  text-transform: none;
}

.sarir-media__pause:hover,
.sarir-media__pause:focus-visible {
  background: var(--c-black);
  color: var(--c-white);
}

/* A media slot on a PAGE is a core/group the author dropped an image or a
   video into, so the markup around the media is the editor's rather than ours.
   Three lines to make the two cases the same object:

   theme.json sets layout.contentSize to 46rem, and a group left on the default
   CONSTRAINED layout caps its own children there — 736px inside a 992px
   column, which reads as a picture that failed to load properly rather than as
   a decision. `sarir_block_media_slot()` writes `layout: default` for exactly
   this reason; the max-inline-size here is the belt to that pair of braces,
   because a group inserted by hand will not have it.

   The figure margin reset is core's: .wp-block-image and .wp-block-video both
   carry a bottom margin that would land on top of the 80px slot gap.

   SCOPED TO .sarir-page__content, and that is not neatness — it is the same
   trap the hero weave hit and main.css already records. Written as
   `.sarir-media > *` it is (0,1,0), exactly the specificity of the
   `.sarir-statement__inner, .sarir-media__inner` rule 400 lines above it, and
   it comes later, so it won: every media band on /brands/ went from 992px to
   1393px — full bleed inside a page grammar that says nothing inside a brand
   is full bleed. Caught by re-running phase 7b's list, not by looking. */
.sarir-page__content .sarir-media > * {
  max-inline-size: 100%;
}

.sarir-media figure,
.sarir-media .wp-block-video {
  margin-block: 0;
}

/* The last band before the footer wants the same air the homepage gives it. */
.sarir-inner {
  padding-block-end: var(--band-gap);
}

/* ---- A brand's opening block --------------------------------------------
   The logo, the name, the strapline, the intro and the outbound link. Centred
   with everything else in the column. */

.sarir-brandpage__logo {
  margin-inline: auto;
  margin-block-end: var(--space-6);
  max-inline-size: 100%;
  inline-size: auto;
}

.sarir-brandpage__visit {
  margin-block-start: var(--space-5);
}

/* --------------------------------------------------------------------------
   A page's body — page.php

   THE STATEMENT COLUMN: 992px inside a 1024px wrapper, CENTRED. Phase 7e.

   THIS REVERSES WHAT PHASE 7C WROTE HERE, and the old rule is worth a
   sentence because the reasoning was sound and the premise was wrong. 7c set
   the body to --container-narrow, aligned to the inline start, on the grounds
   that a whole page of centred running text has no fixed edge to return to and
   the reader hunts for the start of every line. That is true, of running
   prose.

   This is not running prose. Every page on this site is now four or five short
   paragraphs per section, which is the exact shape the centred statement
   column was measured for on the reference — and the alternative was a site
   whose homepage and brands page are centred and whose Group pages are not,
   which is three visual languages again rather than one.

   The 7c rule is DELETED rather than left commented out beside this one: two
   contradicting instructions in a file is how the next session picks the wrong
   one.
   -------------------------------------------------------------------------- */

.sarir-page__content {
  max-inline-size: var(--container-statement); /* 1024px border box */
  margin-inline: auto;
  padding-inline: var(--space-4);              /* leaves a 992px content box */
  text-align: center;
}

/* The rhythm, in four gaps, and the ORDER OF THESE RULES IS THE MECHANISM —
   they are all on one parent and they resolve by specificity, so a change of
   order changes the page.

   Default: paragraph rhythm, for two paragraphs of one slot.               */
.sarir-page__content > * + * {
  margin-block-start: var(--space-6);
}

/* A named block inside a section — one of the five values, one of the four
   value propositions — opens at half a band and its text sits under its name. */
.sarir-page__content > h3 {
  margin-block-start: var(--band-gap-tight);
  font-size: var(--fs-lg);
  font-weight: var(--fw-light);
}

.sarir-page__content > h3 + * {
  margin-block-start: var(--space-4);
}

/* A media slot is a band, so it takes the band's air on BOTH sides — 80px,
   the same distance phase 7b puts between the slots of a brand.

   `:not(h2)` is load-bearing. `.sarir-media + *` is 0-2-1 and `> h2` is 0-1-1,
   so without it a section that ENDS in a media slot would give the next
   section's heading 80px instead of 160 — the section boundary would quietly
   halve, and only on the sections that happen to end in a picture. */
.sarir-page__content > .sarir-media,
.sarir-page__content > .sarir-media + *:not(h2) {
  margin-block-start: var(--band-gap-tight);
}

/* A section begins at its title, and sections are a full band apart.

   AND IT IS A BAND HEAD, so it takes the band head's treatment — Sarir's
   decision B-h2, 2026-09-21: "one look for the title of a band, wherever the
   band is." It already matched `.sarir-chain__head` in size and weight (both
   --fs-xl / --fw-light, measured 44px/50.6px/300). What differed was the base
   heading rule's `--tracking-display` (-0.015em, painting -0.66px) and the
   absence of the uppercase the homepage's band heads carry in English. Both
   are restated here rather than the base rule being changed, which would move
   every other heading on the site. */
.sarir-page__content > h2 {
  margin-block-start: var(--band-gap);
  font-size: var(--fs-xl);
  font-weight: var(--fw-light);
  letter-spacing: var(--tracking-normal);
}

/* Uppercase in English only — the same condition `.sarir-chain__head` carries,
   and for the same reason: Persian and Arabic have no case. */
:lang(en) .sarir-page__content > h2 {
  text-transform: uppercase;
}

/* Last, so it beats every rule above it at equal specificity. */
.sarir-page__content > *:first-child {
  margin-block-start: 0;
}

/* The voice. `.sarir-statement__text` and its `--sm` variant are set once, up
   with the statement band, and are the SAME components a brand section uses —
   the seed and the block pattern both write those class names, so a page and a
   brand speak in one voice rather than in two that resemble each other.

   This is the default for a paragraph that carries neither: an author who
   types a bare paragraph gets the supporting voice, not 16px body copy in a
   1024px column.

   `:where()` IS THE MECHANISM, not tidiness — phase 9j §B1. The selector said
   "the default for a paragraph that carries neither class" and its
   SPECIFICITY did not: `.sarir-page__content p` is (0,1,1) and
   `.sarir-statement__text` is (0,1,0), so the default beat both component
   classes and EVERY section's opening statement on every page rendered at
   24px in the supporting voice. Measured from Chrome's cascade on
   /ecosystem/: font-size, line-height AND font-weight all won by
   `.sarir-page__content p`, on the statement and on the supporting text
   alike — so a page had no statement voice at all, and the two were
   indistinguishable. The defect is as old as the rule (phase 7e, 2026-09-13).

   `:where()` contributes ZERO specificity, so this is (0,0,1): it still beats
   the bare element, and any single class beats it. That is what the sentence
   above always meant. `!important` and a longer selector would both have made
   the default harder to override, which is the opposite of its job. */
:where(.sarir-page__content) p {
  font-size: var(--fs-statement-sm);
  font-weight: var(--fw-light);
  line-height: var(--lh-statement-sm);
}

/* The statement's own bottom margin belongs to the homepage band, where it
   separates the statement from the link beneath it. In a page the rhythm above
   owns every gap, and two mechanisms spacing one joint is how a gap ends up
   being 112px for no reason anybody can find. */
.sarir-page__content .sarir-statement__text {
  margin-block-end: 0;
}
