/* AL QAYED storefront — fonts, reset, design tokens, typography, the header
   and footer shell, buttons and the shared partials.

   Two rules run through every declaration below and are worth stating once:

   1. LOGICAL PROPERTIES ONLY (margin-inline, inset-inline, text-align: start).
      The Arabic store is the default one and is RTL; not a single physical
      left/right may appear except inside a `transform`, which has no logical
      form at all — those are written against [dir="rtl"] where the direction
      matters (the drawer keyframes, the button arrow).
   2. ARABIC NEVER GETS LETTER-SPACING OR UPPERCASE. Rather than repeat that
      exception per rule, the two properties are driven by --tracking-wide
      and --caps, which html[lang="ar"] resets to normal/none. Any new rule
      that wants tracked small caps must use those variables. */

/* ---------------------------------------------------------------------------
   Fonts — self-hosted, never a CDN.

   An Arabic page sets its words in Amiri and its figures (.num: prices,
   counts, order numbers) in Archivo; an English page sets everything in
   Archivo and Cormorant Garamond, and its font stacks never name Amiri.
   unicode-range is what keeps a page from paying for type it cannot show:
   the Arabic page fetches amiri-*-ar for the Arabic glyphs, amiri-*-lat for
   the spaces, punctuation and Latin letters between them, Archivo for the
   figures, and never Cormorant. Arabic inside an English page — the
   language switcher's one word, an Arabic-only product name — deliberately
   falls through to the system Arabic face rather than pulling in a 100 KB
   subset.
--------------------------------------------------------------------------- */

/* Archivo and Cormorant Garamond are VARIABLE fonts — one file each, carrying
   a `wght` axis (Archivo 100-900, Cormorant 300-700, verified by reading the
   `fvar` table out of the woff2). They shipped as four and three identically
   named copies of that one file; declaring each copy as a separate weight made
   four cache entries out of one face and cost an English page ~70 KB of
   duplicate bytes. One declaration with a weight RANGE is both smaller and
   truthful: the browser sets the axis to whatever weight the rule asks for. */
@font-face { font-family: Archivo; src: url("/fonts/Archivo-var.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

@font-face { font-family: "Cormorant Garamond"; src: url("/fonts/CormorantGaramond-var.woff2") format("woff2"); font-weight: 300 700; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Cormorant Garamond"; src: url("/fonts/CormorantGaramond-var-italic.woff2") format("woff2"); font-weight: 300 700; font-style: italic; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* Amiri — the Arabic store's face, a revival of the Bulaq (Amiria) Press
   Naskh; OFL, licence beside the files (public/fonts/OFL-Amiri.txt). These
   are Google Fonts' v30 files with Google's own unicode-ranges, one static
   file per weight and subset: Amiri is not variable, and ships 400 and 700
   only. The bold face answers every weight from 500 up, because the store's
   "medium" (500: buttons, labels, eyebrows, a notice's emphasised name)
   would otherwise match the regular — the nearest weight below — and lose
   its emphasis on the Arabic page. No figure reaches these faces: .num is
   Archivo there too (see .num). */
@font-face { font-family: Amiri; src: url("/fonts/amiri-400-ar.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; unicode-range: U+0600-06FF, U+0750-077F, U+0870-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC7, U+10EC9-10EEE, U+10EF0-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1; }
@font-face { font-family: Amiri; src: url("/fonts/amiri-700-ar.woff2") format("woff2"); font-weight: 500 700; font-style: normal; font-display: swap; unicode-range: U+0600-06FF, U+0750-077F, U+0870-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC7, U+10EC9-10EEE, U+10EF0-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1; }

@font-face { font-family: Amiri; src: url("/fonts/amiri-400-lat.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: Amiri; src: url("/fonts/amiri-700-lat.woff2") format("woff2"); font-weight: 500 700; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* ---------------------------------------------------------------------------
   Tokens layered on public/css/tokens.css (which owns the palette and is
   shared with the admin UI — never edited from here).
--------------------------------------------------------------------------- */

:root {
  --font-body: Archivo, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --tracking-wide: 0.14em;
  --tracking-tight: 0.02em;
  --caps: uppercase;
  --lh-display: 1.08;
  --lh-body: 1.7;
  --wt-display: 500;

  --gold-line: rgba(143, 107, 51, 0.42);
  --ivory-dim: rgba(253, 252, 250, 0.72);

  --wrap: 1240px;
  --gutter: 1rem;
  --section: 3.5rem;

  --dur: 320ms;
  --dur-slow: 560ms;
  --ease: cubic-bezier(0.32, 0.72, 0, 1);

  /* The drawer's scrim lives inside the header's stacking context, so the
     floating WhatsApp seal has to sit BELOW --z-header or it would hover,
     undimmed and clickable, over an open drawer. */
  --z-float: 20;
  --z-header: 30;
  /* Room reserved for Phase D. The nav drawer resolves its scrim/panel/burger
     as 1/2/3 INSIDE .drawer, which works only because .drawer is a child of
     the header and inherits its stacking context; a cart drawer is not, so it
     needs a real rung on this ladder rather than a copy of those numbers. */
  --z-cart: 40;
  --z-toast: 50;
  --z-drawer: 60;
  --z-skip: 80;
}

/* WHICH webfont the page pays for is a whole-document decision: an English
   page must not fetch a 100 KB Arabic subset for the one word in its language
   switcher, so the family swap keys on the document. So does everything that
   answers to Amiri itself rather than to Arabic in general:
   - its headings are bold (--wt-display): Amiri has no 500, and its 400 is a
     text face, not a display one;
   - its tall ascenders and deep descenders want more leading, ~1.8 for
     running text (--lh-body, and --lh-copy for the notes, hints and ledes
     that set their own line-height);
   - it sits visibly smaller than a sans at the same size, so the Arabic page
     raises its type: running text 14 %, headings 10 %, labels, buttons and
     form controls 8 %. Every rule multiplies its size by its role's factor —
     --fs-text, --fs-head or --fs-ui — and only this block defines them, so
     an English page reads each rule's fallback (1, or the rule's own
     line-height) and renders exactly as before. Figures and prices (.num)
     are Archivo on both pages and are not raised. */
html[lang="ar"] {
  --font-body: Amiri, "Noto Naskh Arabic", "Geeza Pro", serif;
  --font-display: Amiri, "Noto Naskh Arabic", "Geeza Pro", serif;
  --wt-display: 700;
  --lh-display: 1.5;
  --lh-body: 1.8;
  --lh-copy: 1.8;
  --fs-text: 1.14;
  --fs-head: 1.1;
  --fs-ui: 1.08;
}

/* HOW text is set follows the text, not the document. These two rules are the
   whole of the "Arabic never gets letter-spacing or uppercase" guarantee, and
   they are element-scoped on purpose: the `عربي` switch sits inside an English
   page, and localName() deliberately falls back to an Arabic product name when
   the English one is blank, so Arabic strings DO appear inside English
   documents. Custom properties inherit, so tagging an element `lang="ar"` also
   covers everything under it — and tagging a Latin island inside an Arabic
   page `lang="en"` puts the tracking back.
   The leading and weight below are for Arabic set in a system face, inside
   an English page: the Arabic document's own Amiri values (html[lang="ar"],
   (0,1,1)) outrank them on <html>, and every element inherits from there.
   Both selectors are (0,1,0), the same weight as :root above, so they must
   stay after it. */
[lang="ar"] {
  --tracking-wide: normal;
  --tracking-tight: normal;
  --caps: none;
  --lh-display: 1.45;
  --lh-body: 1.95;
  --wt-display: 400;
}

[lang="en"] {
  --tracking-wide: 0.14em;
  --tracking-tight: 0.02em;
  --caps: uppercase;
  --lh-display: 1.08;
  --lh-body: 1.7;
  --wt-display: 500;
}

@media (min-width: 700px) {
  :root { --gutter: 2rem; --section: 5rem; }
}
@media (min-width: 1100px) {
  :root { --gutter: 2.5rem; --section: 7rem; }
}

/* ---------------------------------------------------------------------------
   Reset and base
--------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--ivory-050);
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: calc(1rem * var(--fs-text, 1));
  font-weight: 400;
  line-height: var(--lh-body);
  text-align: start;
  -webkit-font-smoothing: antialiased;
}

main { flex: 1 0 auto; }

img, svg { max-width: 100%; }
img { height: auto; }

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--wt-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-tight);
}

p, ul, ol { margin: 0; }

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

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

:focus-visible {
  outline: 2px solid var(--gold-600);
  outline-offset: 3px;
}

::selection { background: var(--gold-600); color: var(--ivory-050); }

/* ---------------------------------------------------------------------------
   Utilities
--------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Latin numerals inside Arabic text: isolated so the bidi algorithm cannot
   reorder a price, and tabular so a column of them lines up. */
.num {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}
/* The Arabic page sets its figures in the English page's face, lining and
   tabular, so a price reads the same in both languages: Amiri is for the
   words. The English page needs no rule — Archivo is already its body face,
   and a figure inside its Cormorant headings keeps that face's own. */
html[lang="ar"] .num {
  font-family: Archivo, system-ui, sans-serif;
  font-variant-numeric: lining-nums tabular-nums;
}

/* The new Omani Rial symbol (server/pages/partials.js's rialMark), after the
   figure of every amount. Sized in em, so it scales with the amount it sits
   in — a card's price or a checkout total — and filled with currentColor,
   so it takes that amount's colour: gold on green, ink on ivory, muted
   beside a struck price. It follows the figure in the page's direction, and
   its start margin is the gap on the figure's side either way. Khamra POS's
   proportions: 0.66em high, its box 16:9, its foot on the baseline. */
.omr {
  display: inline-block;
  width: auto;
  height: 0.66em;
  aspect-ratio: 1024 / 576;
  margin-inline-start: 0.25em;
  vertical-align: -0.02em;
}

/* A tracked micro-label — the "eyebrow" above a heading. Arabic gets the
   same size and weight but neither tracking nor caps (see --tracking-wide). */
.eyebrow, .sec-head__link, .hdr__nav a, .hdr__lang, .ftr__head, .badge, .btn, .pager__link {
  font-family: var(--font-body);
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.skip-link {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: var(--z-skip);
  padding: 0.85rem 1.25rem;
  background: var(--green-900);
  color: var(--ivory-050);
  font-size: calc(0.875rem * var(--fs-ui, 1));
  transform: translateY(-120%);
  transition: transform var(--dur) var(--ease);
}
.skip-link:focus-visible { transform: none; }

/* ---------------------------------------------------------------------------
   Buttons — rectangular, 2px radius, a thin gold outline on hover and focus.
   Never a pill, never a drop shadow.
--------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: var(--tap);
  padding-block: 0.9rem;
  padding-inline: 2.25rem;
  border: 1px solid var(--green-900);
  border-radius: 2px;
  background: var(--green-900);
  color: var(--ivory-050);
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:hover {
  background: transparent;
  color: var(--green-900);
  border-color: var(--gold-600);
}
.btn:active { transform: translateY(1px); }

/* Switched off (checkout while online payment is unavailable): a quiet
   slab that no longer answers the pointer. */
.btn:disabled, .btn:disabled:hover {
  background: var(--surface-200);
  border-color: var(--surface-200);
  color: var(--muted-600);
  cursor: not-allowed;
  transform: none;
}

.btn--ghost {
  background: transparent;
  color: var(--green-900);
  border-color: var(--gold-line);
}
.btn--ghost:hover { background: var(--green-900); color: var(--ivory-050); border-color: var(--green-900); }

/* The same button on a dark ground: the hero, a promo band. */
.btn--light {
  background: var(--ivory-050);
  color: var(--green-900);
  border-color: var(--ivory-050);
}
.btn--light:hover { background: transparent; color: var(--ivory-050); border-color: var(--gold-600); }

/* The hairline arrow that trails a call to action, and slides a few pixels
   further out under the cursor — the one piece of kinetic tension the buttons
   get, in place of the colour-flooding hover a cheaper design would use.
   translateX rather than an inline offset because it is a transform, and RTL
   is handled by mirroring the glyph itself. */
.btn__arrow {
  flex: none;
  width: 17px;
  height: 17px;
  transition: transform var(--dur) var(--ease);
}
.btn:hover .btn__arrow { transform: translateX(4px); }
[dir="rtl"] .btn__arrow { transform: scaleX(-1); }
[dir="rtl"] .btn:hover .btn__arrow { transform: scaleX(-1) translateX(4px); }

/* nav.js hides the sort form's submit button with the `hidden` property, and
   .btn's own `display` would otherwise beat the UA stylesheet's [hidden]. */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
   Test-mode ribbon
--------------------------------------------------------------------------- */

.ribbon {
  margin: 0;
  padding-block: 0.4rem;
  background: var(--gold-600);
  color: var(--ivory-050);
  font-size: calc(0.75rem * var(--fs-ui, 1));
  letter-spacing: var(--tracking-tight);
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Header — deep green, sticky, one gold hairline at its foot.
--------------------------------------------------------------------------- */

.hdr {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background: var(--green-900);
  color: var(--ivory-050);
  border-block-end: 1px solid var(--gold-line);
}

/* Phone budget, measured at 375px: burger 48 + mark 30 + "AL QAYED" at
   0.14em tracking ~90 + three 48px targets + the 32px gutter leaves barely
   20px of slack, so the gaps here are deliberately tight and open up at
   900px. Anything added to the bar has to be re-measured against that.

   Below 375px — and at ANY width once the owner types a longer store_name,
   which is an editable setting — that budget is simply overdrawn, and the bar
   has to decide what gives. The three rules that follow decide it: the tap
   targets never shrink, the brand is the only elastic item, and its wordmark
   ellipsises instead of printing out of its own box. Without them the flex
   default (shrink: 1 on everything, no min-width) let `.brand` shrink below
   its content while `white-space: nowrap` kept the glyphs on one line, so at
   320px the wordmark's ink ran 24px over the language switch in both
   locales, and a long name pushed the cart icon past the viewport edge and
   gave every page of the store horizontal scroll. */
.hdr__inner {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 64px;
}

/* flex: none — a 48px tap target that shrinks is not a 48px tap target. */
.drawer, .hdr__actions { flex: none; }

.brand {
  display: inline-flex;
  align-items: center;
  /* The wordmark is a link home, and the mark inside it is only 30px: without
     this the whole brand is a 30px-tall target in a header where everything
     else honours --tap. */
  min-height: var(--tap);
  gap: 0.5rem;
  margin-inline: auto;
  /* Without this the automatic minimum size resolves through .brand's own
     flex children, not the wordmark's real width, and the box shrinks under
     its content. min-width: 0 lets it shrink honestly, and .brand__name then
     handles the overflow. */
  min-width: 0;
}

/* The mark is a green monogram printed on ivory, so on the green header it
   reads as a small stamped plate rather than a floating cut-out. It is the
   one part of the brand that must survive at any width — the wordmark can be
   cut, the monogram cannot — so it does not shrink either. */
.brand__mark {
  flex: none;
  width: 30px;
  height: 30px;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  object-fit: cover;
}

/* nowrap keeps the wordmark on one line; overflow + ellipsis is what makes
   that safe. A store name too long for the bar is cut with an ellipsis
   instead of painting over the language switch and the cart. */
.brand__name {
  font-family: var(--font-display);
  font-size: calc(0.9375rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hdr__nav { display: none; }

.hdr__nav ul {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.hdr__nav a {
  position: relative;
  display: block;
  padding-block: 0.5rem;
  color: var(--ivory-dim);
  font-size: calc(0.75rem * var(--fs-ui, 1));
  font-weight: 500;
  transition: color var(--dur) var(--ease);
}
.hdr__nav a::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  height: 1px;
  background: var(--gold-600);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--dur) var(--ease);
}
.hdr__nav a:hover { color: var(--ivory-050); }
.hdr__nav a:hover::after { transform: scaleX(1); }

.hdr__actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.hdr__lang {
  min-width: var(--tap);
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ivory-dim);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  transition: color var(--dur) var(--ease);
}
/* On the deep green, hover BRIGHTENS — it never goes gold. Gold measures
   3.51:1 on --green-900 and 2.93:1 on --green-800, so a gold hover state
   would drop a link below the text floor at the exact moment a customer is
   reading it. The same rule applies to the drawer and footer links below;
   gold-as-text is fine on ivory (4.74:1), which is why the breadcrumb, pager
   and card hovers keep it. */
.hdr__lang:hover { color: var(--ivory-050); }

.hdr__icon {
  position: relative;
  width: var(--tap);
  height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ivory-dim);
  transition: color var(--dur) var(--ease);
}
.hdr__icon:hover { color: var(--ivory-050); }
.hdr__icon .icon { width: 21px; height: 21px; }

.hdr__count {
  position: absolute;
  inset-block-start: 6px;
  inset-inline-end: 4px;
  min-width: 17px;
  padding-inline: 4px;
  border-radius: 2px;
  background: var(--gold-600);
  color: var(--ivory-050);
  font-size: 0.625rem;
  line-height: 17px;
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Drawer (<900px). Without JS the <details> alone does the whole job: the
   scrim is the toggle's own ::after, so a click anywhere outside the panel
   lands on the <summary> and closes the drawer natively. nav.js only adds
   aria-expanded, Escape and close-on-navigate.
--------------------------------------------------------------------------- */

/* display: flex, not the <details> default block. The <summary> is
   inline-flex, so as a block container's only in-flow child it sat on a line
   box and was baseline-aligned against that line's strut: giving `.burger` the
   full 48px tap box moved the summary's own baseline down with it, and the
   whole toggle rode 5.4px ABOVE the centre line the language switch and the
   two header icons share. As a flex container the summary is a flex item, laid
   out by its margin box instead of a baseline, so the glyph centres exactly. */
.drawer {
  position: relative;
  z-index: var(--z-drawer);
  display: flex;
  align-items: center;
}

/* NO z-index here, deliberately. The scrim below is this element's own
   ::after — that is what makes click-outside-to-close work with JavaScript
   off, because a click anywhere on it still targets the <summary>. But a
   z-index on the toggle would make it a STACKING CONTEXT, and the scrim's
   z-index would then resolve inside it, painting the full-viewport wash on
   top of the panel: every drawer link became untappable and tapping a
   category closed the drawer instead of navigating. With z-index: auto here,
   the scrim (1), the panel (2) and the burger (3) all resolve inside
   `.drawer` and stack in that order. */
.drawer__toggle {
  position: relative;
  width: var(--tap);
  height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ivory-050);
  cursor: pointer;
  list-style: none;
}
.drawer__toggle::-webkit-details-marker { display: none; }

/* The focus ring moves onto the burger, which is the one part of the toggle
   above the panel. The <summary> itself has z-index: auto (see above), so
   while the drawer is open its own outline painted UNDER the `z-index: 2`
   panel and a keyboard user closing the drawer with Return saw no ring at
   all. `.burger` is the same 48x48 box as the summary, so the ring is pixel
   for pixel the one the base :focus-visible rule drew — only now it is
   always visible. */
.drawer__toggle:focus-visible { outline: none; }
.drawer__toggle:focus-visible .burger {
  outline: 2px solid var(--gold-600);
  outline-offset: 3px;
}

/* The burger carries the toggle's z-index instead of the <summary> itself, so
   the X stays lit above both the scrim and the panel while the scrim stays
   below them. Clicks on it bubble to the <summary> and toggle the drawer
   exactly as before.

   Because it is the only part of the toggle above the panel, it must also BE
   the tap target: it fills the whole var(--tap) box while background-clip
   keeps the painted middle bar at the content box's 20x1.5px. Sizing it to
   the glyph instead left a 48x48 control that was ~5% tappable with the
   drawer open — the panel's own top padding swallowed the rest. */
.burger {
  position: relative;
  z-index: 3;
  display: block;
  box-sizing: border-box;
  width: var(--tap);
  height: var(--tap);
  padding: calc((var(--tap) - 1.5px) / 2) calc((var(--tap) - 20px) / 2);
  background: currentColor;
  background-clip: content-box;
  transition: background var(--dur) var(--ease);
}

/* The two outer bars sit centred on the box and are offset by transform
   alone, so the open state only has to replace that offset with a rotation
   and both bars land on the same centre line as a true X. */
.burger::before, .burger::after {
  content: "";
  position: absolute;
  inset-block-start: calc(50% - 0.75px);
  inset-inline-start: calc((var(--tap) - 20px) / 2);
  width: 20px;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--dur) var(--ease);
}
.burger::before { transform: translateY(-6px); }
.burger::after { transform: translateY(6px); }

.drawer[open] .burger { background: transparent; }
.drawer[open] .burger::before { transform: rotate(45deg); }
.drawer[open] .burger::after { transform: rotate(-45deg); }

.drawer[open] .drawer__toggle::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  background: rgba(0, 17, 2, 0.55);
  animation: scrim-in var(--dur) var(--ease) both;
}

.drawer__panel {
  position: fixed;
  z-index: 2;
  inset-block: 0;
  inset-inline-start: 0;
  width: min(84vw, 340px);
  /* Clears the header (and the UAT ribbon above it) so the first link never
     sits under the toggle that opened the panel. */
  padding: 5.75rem 1.75rem 2rem;
  overflow-y: auto;
  background: var(--green-900);
  border-inline-end: 1px solid var(--gold-line);
  animation: drawer-in var(--dur-slow) var(--ease) both;
}
[dir="rtl"] .drawer__panel { animation-name: drawer-in-rtl; }

/* Ivory, not gold: this is t(locale, 'nav.categories') — the label for the
   drawer's list, i.e. content — and gold on --green-900 measures 3.51:1
   against the phase's 4.5:1 floor for text. The gold stays on the hairline
   below it, which is where an ornament belongs. Same call as .hero__eyebrow. */
.drawer__eyebrow {
  margin-block-end: 1.25rem;
  padding-block-end: 0.9rem;
  border-block-end: 1px solid var(--gold-line);
  color: var(--ivory-dim);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.drawer__list a {
  display: block;
  padding-block: 0.85rem;
  color: var(--ivory-050);
  font-family: var(--font-display);
  font-size: calc(1.375rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
/* Already ivory at rest, so the hover signal is the gold rule underneath it
   rather than a colour change (see .hdr__lang:hover for why not gold). */
.drawer__list a:hover {
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
}

.drawer__list--quiet {
  margin-block-start: 2rem;
  padding-block-start: 1.25rem;
  border-block-start: 1px solid var(--gold-line);
}
.drawer__list--quiet a {
  font-family: var(--font-body);
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  color: var(--ivory-dim);
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

@media (min-width: 700px) {
  .brand { gap: 0.7rem; }
  .brand__mark { width: 34px; height: 34px; }
  .brand__name { font-size: calc(1.0625rem * var(--fs-head, 1)); }
}

@media (min-width: 900px) {
  .drawer { display: none; }
  .hdr__nav { display: block; margin-inline: auto; }
  .hdr__inner { min-height: 76px; gap: 1rem; }
  .brand { margin-inline: 0; }
}

/* ---------------------------------------------------------------------------
   Footer
--------------------------------------------------------------------------- */

.ftr {
  margin-block-start: var(--section);
  padding-block: 3rem 2rem;
  background: var(--green-800);
  color: var(--ivory-dim);
  border-block-start: 1px solid var(--gold-line);
  font-size: calc(0.875rem * var(--fs-text, 1));
}

/* Ivory for the same reason as .drawer__eyebrow: this line is
   t(locale, 'footer.trust'), the store's own promise to the customer — and
   the string it also ships as half its meta description. Content, not trim. */
.ftr__trust {
  padding-block-end: 2.5rem;
  color: var(--ivory-dim);
  font-size: calc(0.75rem * var(--fs-text, 1));
  letter-spacing: var(--tracking-tight);
  text-align: center;
}

.ftr__cols {
  display: grid;
  gap: 2.5rem;
  padding-block: 2.5rem;
  border-block: 1px solid var(--gold-line);
}

.ftr__brand {
  display: block;
  color: var(--ivory-050);
  font-family: var(--font-display);
  font-size: calc(1.25rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.ftr__tagline { margin-block-start: 0.75rem; max-width: 30ch; }

.ftr__head {
  margin-block-end: 1rem;
  color: var(--ivory-050);
  font-family: var(--font-body);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
}

/* The policy links are the ones a customer reaches for on a phone right before
   paying, so they get the store's --tap floor like every other control. The
   height has to come from the LINK, not from a margin on the <li>: margin is
   whitespace, not hit box, and the 0.6rem that used to sit here left three
   30px targets (16px in English, where the <a> was still inline) pretending to
   be comfortable. inline-flex keeps the target as wide as its words — a
   full-width strip of footer would swallow taps meant for nothing — but never
   narrower than --tap: in Amiri «واتساب» is 40px wide. */
.ftr__col li a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  min-inline-size: var(--tap);
}

.ftr__col a { transition: color var(--dur) var(--ease); }
.ftr__col a:hover { color: var(--ivory-050); }

.ftr__address { max-width: 24ch; }

.ftr__rights {
  padding-block-start: 2rem;
  font-size: calc(0.75rem * var(--fs-text, 1));
  text-align: center;
}

/* FutureLine's signature: the agency's mark (its own panel colour, kept as it was
   approved) with one line of text, centred under the rights line. */
.ftr__sign {
  display: flex;
  justify-content: center;
  padding-block-start: 1.25rem;
  font-size: calc(0.8rem * var(--fs-text, 1));
}
.ftr__sign a {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 44px;
  color: inherit;
  text-decoration: none;
}
.ftr__sign a:hover .ftr__sign-name, .ftr__sign a:focus-visible .ftr__sign-name { text-decoration: underline; }
.ftr__sign img {
  height: 3.25rem;
  width: auto;
  border-radius: 6px;
}
.ftr__sign-name {
  font-family: Archivo, system-ui, sans-serif;
  font-weight: 500;
}

@media (min-width: 600px) {
  .ftr__cols { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .ftr { padding-block: 4.5rem 2.5rem; }
  .ftr__cols { grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 3rem; }
}

/* A floating seal, not a candy bubble: square, 2px radius, gold hairline. */
.wa-float {
  position: fixed;
  z-index: var(--z-float);
  inset-block-end: 1.25rem;
  inset-inline-end: 1.25rem;
  width: 52px;
  height: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--green-900);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  color: var(--ivory-050);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.wa-float:hover { background: var(--green-800); border-color: var(--gold-600); }
.wa-float .icon { width: 25px; height: 25px; }

/* A page that carries the .purchase slot (server/pages/product.js sets the
   class) does NOT get the seal. The seal is fixed 52x52 in the corner where
   .product__ask runs full width below 700px — a 14% overlap on a control the
   page already offers — and Phase D puts add-to-cart in the same band, where
   a mis-tap would silently leave the store mid-purchase. Nothing is lost:
   that page's own WhatsApp CTA is the better version of this button. */
.has-purchase .wa-float { display: none; }

/* ---------------------------------------------------------------------------
   Typography scale
--------------------------------------------------------------------------- */

.page-title, .prose__title, .error__title {
  font-size: calc(clamp(2rem, 1.35rem + 2.8vw, 3.25rem) * var(--fs-head, 1));
}

.sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  margin-block-end: 2rem;
  padding-block-end: 1rem;
  border-block-end: 1px solid var(--gold-line);
}

.sec-head__title { font-size: calc(clamp(1.5rem, 1.15rem + 1.5vw, 2.25rem) * var(--fs-head, 1)); }

.sec-head__link {
  flex: none;
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  transition: color var(--dur) var(--ease);
}
.sec-head__link:hover { color: var(--gold-600); }

/* ---------------------------------------------------------------------------
   Partials: media, cards, badges, price, breadcrumbs, pagination
--------------------------------------------------------------------------- */

.media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--green-900);
}

.media__img, .media__blank {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.media__blank { background: var(--green-800); }

.media__img { transition: transform var(--dur-slow) var(--ease); }
.card__link:hover .media__img { transform: scale(1.03); }

.card__body { padding-block: 1rem 0; }

.card__name {
  font-size: calc(1.0625rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  transition: color var(--dur) var(--ease);
}
.card__link:hover .card__name { color: var(--gold-600); }

.card--sold .media__img { opacity: 0.55; }

.badges {
  position: absolute;
  inset-block-start: 0.75rem;
  inset-inline-start: 0.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.badge {
  padding: 0.3rem 0.55rem;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  background: var(--ivory-050);
  color: var(--ink-900);
  font-size: calc(0.5625rem * var(--fs-ui, 1));
  font-weight: 500;
  line-height: 1;
}
.badge--sold { background: var(--green-900); color: var(--ivory-050); border-color: var(--gold-600); }
.badge--sale { background: var(--gold-600); color: var(--ivory-050); border-color: var(--gold-600); }

.price {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-block-start: 0.4rem;
}

.price__now { font-size: 0.9375rem; font-weight: 500; }
/* A struck price strikes its rial symbol too. A line-through is painted
   across text only, never across an inline SVG, so the compare-at price
   draws one rule of its own through the whole amount — figure, gap and
   symbol — at the middle of the figure, on which the symbol is centred. */
.price__was {
  position: relative;
  display: inline-flex;
  align-items: center;
  color: var(--muted-600);
  font-size: 0.8125rem;
  text-decoration: none;
}
.price__was::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: 50%;
  border-block-start: 1px solid;
}

.crumbs {
  margin-block-end: 1.5rem;
  color: var(--muted-600);
  font-size: calc(0.75rem * var(--fs-ui, 1));
}
.crumbs ol { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.crumbs li + li::before { content: "/"; margin-inline-end: 0.5rem; color: var(--gold-line); }
.crumbs a { transition: color var(--dur) var(--ease); }
.crumbs a:hover { color: var(--gold-600); }
.crumbs [aria-current] { color: var(--ink-900); }

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  margin-block-start: 3rem;
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--gold-line);
}

/* A pager step is one short word — «التالي» is 19px wide in Amiri, "Next"
   36px — so its box, not its word, is the target: --tap square at least. */
.pager__link {
  min-height: var(--tap);
  min-inline-size: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  transition: color var(--dur) var(--ease);
}
.pager__link:hover { color: var(--gold-600); }
/* --muted-600 (5.65:1 on ivory), not --surface-200 (1.25:1): the disabled
   step is aria-hidden, so it is not a WCAG failure — it is simply a state
   nobody could see. Quieter than the live link's ink (19.65:1) still reads as
   "off" while remaining a word on the page. */
.pager__link--off { color: var(--muted-600); }

.pager__status { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-ui, 1)); }

/* ---------------------------------------------------------------------------
   Content pages and error pages
--------------------------------------------------------------------------- */

.prose {
  padding-block: var(--section);
  max-width: calc(68ch + 2 * var(--gutter));
}
html[lang="ar"] .prose { max-width: calc(62ch + 2 * var(--gutter)); }

.prose__title {
  padding-block-end: 1.5rem;
  border-block-end: 1px solid var(--gold-line);
}

.prose__body { margin-block-start: 2rem; }
.prose__body > * + * { margin-block-start: 1.5rem; }
.prose__body p { color: var(--ink-900); }
.prose__body ul { display: grid; gap: 0.75rem; }
.prose__body li { padding-inline-start: 1.25rem; position: relative; }
.prose__body li::before {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--lh-body) * 0.5em);
  inset-inline-start: 0;
  width: 0.5rem;
  height: 1px;
  background: var(--gold-600);
}

/* An info page's sections. formatText renders a titled list — a short line
   with its bullets straight under it — as the <p> its <ul> follows, and on a
   content page that line IS the section's heading: the heading face a step
   up, a gold hairline and room above it, the list tucked under it, so a long
   policy reads as sections rather than one column of equal paragraphs.
   Scoped to .prose (the content pages): a product description's sentence
   before its spec list stays a sentence. */
.prose .prose__body p:has(+ ul) {
  margin-block-start: 2.75rem;
  padding-block-start: 1.75rem;
  border-block-start: 1px solid var(--gold-line);
  font-family: var(--font-display);
  font-size: calc(1.5rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-tight);
}
/* Amiri's bold makes a heading by itself, so the Arabic section heading is
   set like the English one — heading face, display weight — only a step
   smaller: at 1.5rem, over the Arabic page's raised body text, it competed
   with the page's own title. */
html[lang="ar"] .prose .prose__body p:has(+ ul) { font-size: calc(1.25rem * var(--fs-head, 1)); }
.prose .prose__body p:has(+ ul) + ul { margin-block-start: 1.125rem; }

.error {
  padding-block: calc(var(--section) * 1.2);
  text-align: center;
}

.error__code {
  font-family: var(--font-display);
  font-size: clamp(4rem, 2rem + 12vw, 8rem);
  line-height: 1;
  color: var(--surface-200);
}

.error__title { margin-block-start: 0.5rem; }

.error__detail {
  margin-block: 1rem 2.5rem;
  margin-inline: auto;
  max-width: 46ch;
  color: var(--muted-600);
}

/* ---------------------------------------------------------------------------
   HOME — hero

   The masthead runs straight on from the header: both are --green-900, so the
   header's gold hairline reads as the hero's own top rule and the page opens
   with one tall dark block rather than a green bar stacked on a green box.
--------------------------------------------------------------------------- */

/* A section's air. Every home section starts with one --section gap, which is
   56px on a phone and 112px on a wide screen. */
.sec { padding-block-start: var(--section); }

.hero {
  background: var(--green-900);
  color: var(--ivory-050);
  border-block-end: 1px solid var(--gold-line);
}

.hero__title {
  font-size: calc(clamp(2.125rem, 1.2rem + 4.4vw, 4rem) * var(--fs-head, 1));
  text-wrap: balance;
}

/* Ivory, not gold. Gold on the deep green measures 3.55:1 and gold over a
   photograph is worse still — under the phase's 4.5:1 floor either way, and
   this is 11px text. The gold stays where it belongs, on the ornament rule
   immediately above it. */
.hero__eyebrow {
  color: var(--ivory-050);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
}

/* Full ivory rather than --ivory-dim: this line only ever sits on a banner
   photograph, where the dim tone fell to ~4.3:1 over a bright highlight. */
.hero__lede {
  margin-block-start: 1.25rem;
  max-width: 44ch;
  color: var(--ivory-050);
  font-size: calc(1.0625rem * var(--fs-text, 1));
}

.hero__cta { margin-block-start: 2.5rem; }

/* The default hero: a centred monogram plate, the store's own tagline set as
   the headline, and one way in. It is what the shop wears until the owner
   uploads a photo, so it has to stand on typography alone. */
.hero--plain .hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-block-size: min(68svh, 34rem);
  padding-block: clamp(3.5rem, 11vw, 7rem);
  text-align: center;
}

.hero--plain .hero__title {
  margin-block-start: 0.85rem;
  max-width: 18ch;
}

.hero--plain .hero__eyebrow { margin-block-start: 1.75rem; }

/* A gold hairline dropped between the monogram and the eyebrow: the page's
   one ornament, and the piece that makes the stack read as a printed card
   rather than three centred lines. */
.hero--plain .hero__eyebrow::before {
  content: "";
  display: block;
  width: 1px;
  height: 3rem;
  margin-inline: auto;
  margin-block-end: 1.25rem;
  background: var(--gold-600);
}

.hero__mark {
  width: 74px;
  height: 74px;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  object-fit: cover;
}

/* The uploaded hero: photo behind, words in the lower corner, a scrim between
   them — the phase's one sanctioned gradient. */
.hero--media {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-block-size: min(76svh, 42rem);
}

.hero--media .hero__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--green-900);
}

/* The scrim reaches full strength by 32% of the way up, not 45%: the whole
   text block — eyebrow, headline, subtitle, button — sits inside the bottom
   third, and at 0.42 the eyebrow was sitting on the bright part of a
   photograph and all but disappearing. */
.hero--media .hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(0, 17, 2, 0.92), rgba(0, 17, 2, 0.8) 32%, rgba(0, 17, 2, 0.34) 72%, rgba(0, 17, 2, 0.12));
}

.hero--media .hero__inner {
  position: relative;
  padding-block: clamp(3rem, 8vw, 5.5rem);
}

.hero--media .hero__title { max-width: 16ch; }
.hero--media .hero__eyebrow { margin-block-end: 1rem; }

@media (min-width: 900px) {
  .hero--plain .hero__inner { min-block-size: min(74svh, 40rem); }
}

/* ---------------------------------------------------------------------------
   HOME — category tiles

   4:5 portraits with the name on a solid plate across the foot: a museum
   label, not a gradient wash. Tiles with no photo keep the plate and show the
   deep-green panel behind it.
--------------------------------------------------------------------------- */

.tiles {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}

.tile__link {
  position: relative;
  display: block;
}

.tile__media {
  display: block;
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--green-900);
}

.tile__name {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: 0.85rem 1rem;
  background: rgba(0, 17, 2, 0.84);
  border-block-start: 1px solid var(--gold-line);
  color: var(--ivory-050);
  font-family: var(--font-display);
  font-size: calc(1rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  line-height: 1.3;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.tile__link:hover .media__img { transform: scale(1.03); }
.tile__link:hover .tile__name { background: var(--green-900); border-color: var(--gold-600); }

@media (min-width: 900px) {
  .tiles { grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
  .tile__name { padding: 1rem 1.15rem; font-size: calc(1.0625rem * var(--fs-head, 1)); }
}

/* ---------------------------------------------------------------------------
   HOME — product rows

   A snapped horizontal rail up to 1100px and a four-column grid above it, all
   in CSS: no JavaScript touches this. The negative inline margin lets the
   rail bleed into the page gutter so cards scroll off the screen edge, while
   scroll-padding keeps the snapped card aligned to the text above it.
--------------------------------------------------------------------------- */

.rail {
  display: flex;
  gap: 1rem;
  margin-inline: calc(var(--gutter) * -1);
  /* 4px block padding so a focused card's ring is not clipped by overflow. */
  padding: 4px var(--gutter);
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: inline mandatory;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

.rail__item {
  flex: 0 0 62%;
  max-width: 17rem;
  scroll-snap-align: start;
}

@media (min-width: 700px) {
  .rail { gap: 1.5rem; }
  .rail__item { flex-basis: 32%; }
}

@media (min-width: 1100px) {
  .rail {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 3rem 1.5rem;
    margin-inline: 0;
    padding: 0;
    overflow: visible;
  }
  .rail__item { max-width: none; }
}

/* ---------------------------------------------------------------------------
   HOME — promo bands and the trust strip
--------------------------------------------------------------------------- */

/* Full-bleed, edge to edge: a band is the one place the 1240px measure gives
   way. The veil is a flat wash rather than a gradient — the deep green is the
   brand's own colour, so it darkens the photo without tinting it. */
.band {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-block-size: min(58svh, 24rem);
  margin-block-start: var(--section);
  background: var(--green-900);
  color: var(--ivory-050);
  border-block: 1px solid var(--gold-line);
}

.band__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.band__media::after {
  content: "";
  position: absolute;
  inset: 0;
  /* 0.7, not 0.6: the owner picks the photo, so the veil has to hold a
     legible band over a bright one too. */
  background: rgba(0, 17, 2, 0.7);
}

.band__inner {
  position: relative;
  padding-block: clamp(2.5rem, 7vw, 4.5rem);
}

.band__title {
  max-width: 18ch;
  font-size: calc(clamp(1.625rem, 1.2rem + 2vw, 2.75rem) * var(--fs-head, 1));
}

.band__lede {
  margin-block-start: 0.9rem;
  max-width: 42ch;
  color: var(--ivory-050);
}

/* A banner whose link was rejected still shows the owner's words — as words,
   never as a button that goes nowhere: the hero's own note, or a band's.
   Ivory for the same reason as the hero's eyebrow: it is small text over a
   photograph. */
.hero__note, .band__note {
  margin-block-start: 1.5rem;
  color: var(--ivory-050);
  font-size: calc(0.8125rem * var(--fs-text, 1));
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.band__cta { margin-block-start: 2rem; }

.trust__list { display: grid; gap: 2.25rem; }

.trust__item {
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--gold-line);
}

.trust__icon {
  width: 26px;
  height: 26px;
  color: var(--gold-600);
}

.trust__title {
  margin-block: 0.9rem 0.45rem;
  font-size: calc(1.125rem * var(--fs-head, 1));
}

.trust__note {
  max-width: 32ch;
  color: var(--muted-600);
  font-size: calc(0.875rem * var(--fs-text, 1));
}

@media (min-width: 700px) {
  .trust__list { grid-template-columns: repeat(3, 1fr); gap: 3rem; }
}

/* ---------------------------------------------------------------------------
   CATEGORY — heading, sort menu, grid, empty state
--------------------------------------------------------------------------- */

.listing { padding-block: 2rem var(--section); }

.listing__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.25rem 2rem;
  margin-block-end: 2.5rem;
  padding-block-end: 1.25rem;
  border-block-end: 1px solid var(--gold-line);
}

.listing__count {
  margin-block-start: 0.6rem;
  color: var(--muted-600);
  font-size: calc(0.75rem * var(--fs-ui, 1));
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.sorter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.sorter__label {
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

/* The native control keeps its own arrow on purpose: it is the one widget the
   browser already mirrors, sizes for a thumb and opens as a sheet on a phone.
   Only its frame is restyled — hairline, 2px radius, the body face.
   The border is --muted-600 (5.65:1 on ivory), not the --gold-line hairline
   the rest of the page uses for ornament: this is the store's only form
   control, and its boundary is the whole of its affordance, which SC 1.4.11
   asks to reach 3:1. The gold hairline measures 1.76:1 — fine for a rule
   between sections, not for the edge that says "this is a control". */
.sorter__select {
  min-height: var(--tap);
  padding-block: 0.5rem;
  padding-inline: 0.85rem;
  border: 1px solid var(--muted-600);
  border-radius: 2px;
  background: transparent;
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  transition: border-color var(--dur) var(--ease);
}
.sorter__select:hover { border-color: var(--gold-600); }

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2.5rem 1rem;
}

@media (min-width: 700px) {
  .grid { grid-template-columns: repeat(3, 1fr); gap: 3rem 1.5rem; }
}
@media (min-width: 1100px) {
  .grid { grid-template-columns: repeat(4, 1fr); }
}

.empty {
  padding-block: calc(var(--section) * 0.8);
  border-block: 1px solid var(--gold-line);
  text-align: center;
}

.empty__text {
  margin-block-end: 2rem;
  color: var(--muted-600);
}

/* ---------------------------------------------------------------------------
   PRODUCT — gallery, details column, the purchase slot, facts, related row

   Two columns from 900px with the gallery on the inline-start side, one
   column below it with the gallery first: a shopper on a phone came to look
   at the watch, and the photograph is what they came for.

   The gallery is a scroll-snap strip, not a JS carousel. Swiping it, dragging
   it on a trackpad and following a thumbnail's #link all work with
   public/js/store/gallery.js blocked — that file only upgrades the swap into
   a smooth one and keeps the current thumbnail marked.
--------------------------------------------------------------------------- */

.product { padding-block: 2rem var(--section); }

.product__grid {
  display: grid;
  gap: 2.5rem;
}

@media (min-width: 900px) {
  .product__grid {
    /* The photograph takes the larger share; the text column is held near 46
       characters, which is where a luxury spec sheet reads as a column
       rather than as a paragraph of running text. */
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: clamp(2.5rem, 4vw, 5rem);
    align-items: start;
  }
}

/* --- Gallery ------------------------------------------------------------ */

/* min-inline-size: 0 on every grid item down to the thumbnail strip's own
   wrapper, or each one's automatic minimum size is its CONTENT's minimum: the
   strip is 4x72px + gaps = 312px, and a four-photo watch pushed its column
   24px past the 288px track it sits in at 320px, which the whole page then
   paid for as horizontal scroll. The strip scrolls inside itself; every box
   around it must be allowed to be narrower than it. */
.gallery, .gallery__nav, .product__detail { min-inline-size: 0; }

.gallery { display: grid; gap: 0.625rem; }

/* The mat around the print: an ivory tray with one gold hairline, so the 4:5
   photograph sits IN the page rather than on it. The strip scrolls inside
   that tray, which is why the padding is repeated as scroll-padding. */
.gallery__stage {
  display: flex;
  gap: 0.5rem;
  padding: 0.5rem;
  border: 1px solid var(--gold-line);
  background: var(--ivory-050);
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: inline mandatory;
  scroll-padding-inline: 0.5rem;
  scrollbar-width: none;
}
.gallery__stage::-webkit-scrollbar { display: none; }

.gallery__slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
}

.gallery__thumbs {
  display: flex;
  /* NOT the default stretch: a stretched flex item with an aspect-ratio has
     its WIDTH recomputed from the line's height, and the migrated catalog's
     two rendition shapes (400x600 and 480x600) then produced two thumbnail
     sizes in one strip. Top-aligned, every box is exactly 4.5rem wide. */
  align-items: flex-start;
  gap: 0.5rem;
  /* 4px so a focused thumbnail's ring is not clipped by the overflow. */
  padding: 4px 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.gallery__thumbs::-webkit-scrollbar { display: none; }

/* Each thumbnail is also a .media box (4:5, deep green), so it only needs to
   become a block and stop shrinking. 4.5rem is 72x90 — over the 44px tap
   minimum with room to spare. */
.gallery__thumb {
  display: block;
  flex: none;
  inline-size: 4.5rem;
}

.gallery__thumb .media__img {
  opacity: 0.6;
  transition: opacity var(--dur) var(--ease);
}
.gallery__thumb:hover .media__img,
.gallery__thumb.is-current .media__img { opacity: 1; }

/* The current-slide marker is a pseudo-element rather than an outline,
   because an element has only one outline and :focus-visible needs it. */
.gallery__thumb.is-current::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--gold-600);
}

/* --- Details ------------------------------------------------------------ */

.product__detail {
  display: grid;
  align-content: start;
  gap: 1.5rem;
}

/* .badges is absolutely positioned over a card's photo. Here it is an ordinary
   row above the heading, so the positioning is taken back off it. */
.product__detail > .badges { position: static; }

.product__name { font-size: calc(clamp(1.75rem, 1.25rem + 2.2vw, 2.75rem) * var(--fs-head, 1)); }

.product__price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem 1rem;
}
.product__price .price { margin-block-start: 0; }
.product__price .price__now { font-size: 1.375rem; }
.product__price .price__was { font-size: 1rem; }

/* What the discount is worth, set like a badge rather than in gold text:
   gold on ivory clears 4.5:1 only barely, and it is an ornament here. */
.price__save {
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  color: var(--ink-900);
  font-size: calc(0.625rem * var(--fs-ui, 1));
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

/* Phase D renders the stepper, the gift card and the add-to-cart form into
   .purchase; this phase ships the slot with the stock line in it. The rules
   below dress the slot itself, so what Phase D adds lands inside a band that
   is already part of the design. */
.purchase {
  display: grid;
  gap: 1.25rem;
  padding-block: 1.25rem;
  border-block: 1px solid var(--gold-line);
}

.stock {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: calc(0.75rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

/* Colour carries the state, the dot carries the colour: the words stay ink on
   ivory, which is the only way this line clears 4.5:1 at 12px. */
.stock::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.stock--in::before { background: var(--green-800); }
.stock--low::before { background: var(--gold-600); }
.stock--out { color: var(--muted-600); }
.stock--out::before { background: var(--surface-200); }

/* .prose__body carries the paragraph and bullet styling; its own top margin
   belongs to a content page, where it follows a rule, and not to a grid
   track that already spaces itself. */
.product__desc { margin-block-start: 0; }

.facts { display: grid; }

/* A grid, not a wrapping flex row: with flex, a short value (a reference
   number) sat beside its term while a sentence-long one wrapped underneath,
   so the same list printed two different shapes. Two columns always, and the
   value wraps inside its own. */
.facts__row {
  display: grid;
  grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr);
  gap: 0.25rem 1.25rem;
  padding-block: 0.85rem;
  border-block-end: 1px solid var(--gold-line);
}
.facts__row:first-child { border-block-start: 1px solid var(--gold-line); }

.facts__term {
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

/* margin: 0 — a <dd>'s 40px UA indent would put the value in a third column.
   overflow-wrap, because a reference number is one unbreakable 22-character
   word and the value column is ~10rem wide on a 320px phone. */
.facts__value {
  margin: 0;
  font-size: calc(0.875rem * var(--fs-text, 1));
  overflow-wrap: anywhere;
}

/* An SKU is an opaque code, and the migrated catalog holds both Latin ones
   ("SAAAAT-ALKAYD2WEJOVD7G9") and mixed ones ("سا-260726001230NVLB").
   `plaintext` takes each code's direction from its own first strong
   character, so a Latin code still reads left to right inside an Arabic page
   while an Arabic-prefixed one is not turned inside out — which is exactly
   what .num's forced `direction: ltr` did to it, printing the digits first. */
.sku {
  unicode-bidi: plaintext;
  font-variant-numeric: tabular-nums;
}

/* Most of this store's conversations finish in WhatsApp, so the question link
   is a full-width control on a phone rather than a line of small print. */
.product__ask {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding-block: 0.9rem;
  padding-inline: 2rem;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}
.product__ask:hover {
  background: var(--green-900);
  border-color: var(--green-900);
  color: var(--ivory-050);
}

@media (min-width: 700px) {
  .product__ask { justify-self: start; }
}

/* ---------------------------------------------------------------------------
   BUYING — notices, the stepper and tick box every cart control shares, the
   product page's buy panel with its gift card, the cart's lines and summary
   (the /cart page and the drawer draw the same markup), the drawer and the
   toast.

   An amount is its figure — .num, an LTR island — and the rial symbol after
   it in the page's direction, so the symbol trails the figure on the reading
   side: right in English, left in Arabic. Its GRID or FLEX parent pushes it
   to the end of its row (justify-self / space-between, which follow the
   page's direction).
--------------------------------------------------------------------------- */

/* A refusal, or a line the stock cut back: ink on a quiet tint, flagged by a
   gold rule at the start — news to read, not an alarm. */
.notice {
  padding-block: 0.8rem;
  padding-inline: 1rem;
  border: 1px solid var(--gold-line);
  border-inline-start: 2px solid var(--gold-600);
  background: rgba(231, 227, 216, 0.35);
  color: var(--ink-900);
  font-size: calc(0.875rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.6);
}

/* The watch a notice is about, when the notice cannot sit on its line (a line
   the stock cut to nothing): set apart by weight alone. */
.notice__name { font-weight: 500; }

.notices { display: grid; gap: 0.75rem; }
.notices:empty { display: none; }

/* --- The stepper --------------------------------------------------------- */

/* One framed control, three cells: − | quantity | +. Every part is placed by
   column, so while the buy panel's buttons are still hidden (purchase.js
   reveals them) their cells stay reserved and nothing moves when they
   appear. The frame is --muted-600 — a control's boundary has to reach 3:1,
   which the gold hairline does not (see .sorter__select). */
.stepper {
  display: inline-grid;
  grid-template-columns: var(--tap) minmax(3.25rem, auto) var(--tap);
  align-items: stretch;
  border: 1px solid var(--muted-600);
  border-radius: 2px;
}

.stepper__btn {
  position: relative;
  grid-row: 1;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-900);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.stepper__btn--down { grid-column: 1; }
.stepper__btn--up { grid-column: 3; }
.stepper__btn:hover:not(:disabled) { background: rgba(231, 227, 216, 0.6); }
.stepper__btn:disabled { color: rgba(107, 101, 87, 0.35); cursor: default; }

/* Hairline glyphs drawn in CSS, so − and + share one weight in every font. */
.stepper__btn::before, .stepper__btn--up::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 12px;
  height: 1px;
  margin: auto;
  background: currentColor;
}
.stepper__btn--up::after { width: 1px; height: 12px; }

.stepper__input, .stepper__value {
  grid-row: 1;
  grid-column: 2;
  display: grid;
  place-items: center;
  min-width: 0;
  color: var(--ink-900);
  font-size: 1rem;
  font-weight: 500;
  text-align: center;
}

.stepper__input {
  width: 3.5rem;
  padding: 0;
  border: 0;
  background: transparent;
  font-family: inherit;
}
.stepper__input:focus-visible { outline-offset: -2px; }
/* Once purchase.js has revealed the buttons, the browser's own spinner is a
   second, smaller stepper inside the first: drop it. Without the script it
   stays, as the only one there is. */
.stepper__btn:not([hidden]) + .stepper__input { appearance: textfield; -moz-appearance: textfield; }
.stepper__btn:not([hidden]) + .stepper__input::-webkit-inner-spin-button,
.stepper__btn:not([hidden]) + .stepper__input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

/* A cart line's stepper is a little tighter, at the 44px floor. */
.stepper--line { grid-template-columns: 44px minmax(2.5rem, auto) 44px; }
.stepper--line .stepper__btn { width: 44px; height: 44px; }
.stepper__value { font-size: 0.9375rem; }

/* --- The tick box -------------------------------------------------------- */

/* The one checkbox look in the store — the gift card's real checkbox and a
   cart line's gift toggle button both wear it. The mark is centred with
   inset + margin rather than an inline offset, so it sits true in RTL too. */
.tick {
  position: relative;
  flex: none;
  width: 20px;
  height: 20px;
  border: 1px solid var(--muted-600);
  border-radius: 2px;
  background: var(--ivory-050);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.tick::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 5px;
  height: 10px;
  margin: auto;
  border: solid var(--ivory-050);
  border-width: 0 1.5px 1.5px 0;
  opacity: 0;
  transform: translateY(-1px) rotate(45deg) scale(0.6);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.gift-card__check:checked + .gift-card__inner .tick,
.gift-toggle[aria-pressed="true"] .tick {
  background: var(--green-900);
  border-color: var(--green-900);
}
.gift-card__check:checked + .gift-card__inner .tick::after,
.gift-toggle[aria-pressed="true"] .tick::after {
  opacity: 1;
  transform: translateY(-1px) rotate(45deg);
}

/* --- The buy panel --------------------------------------------------------- */

.buy { display: grid; gap: 1.25rem; }

.buy__qty {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.buy__label, .buy__row dt {
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

/* The gift card. Two gold rules, 3px apart — a mount around a print, or the
   deckle of a good envelope — so it reads as a considered part of the buy
   decision rather than a checkbox under it. The whole card is the <label>,
   so the whole card is the tap target; ticking it warms the inner field and
   draws the inner rule in full gold. */
.gift-card {
  position: relative;
  display: block;
  padding: 3px;
  border: 1px solid var(--gold-line);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease);
}
.gift-card:hover { border-color: var(--gold-600); }

/* Out of sight, never out of reach: still focusable, still read out. */
.gift-card__check {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

.gift-card__inner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.9rem;
  padding: 1.1rem 1.15rem;
  border: 1px solid var(--gold-line);
  background: var(--ivory-050);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.gift-card__check:checked + .gift-card__inner {
  border-color: var(--gold-600);
  background: rgba(231, 227, 216, 0.4);
}
.gift-card__check:focus-visible + .gift-card__inner {
  outline: 2px solid var(--gold-600);
  outline-offset: 2px;
}
.gift-card .tick { margin-block-start: 0.2rem; }

.gift-card__body { display: grid; gap: 0.35rem; min-inline-size: 0; }

.gift-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
}

.gift-card__title {
  font-family: var(--font-display);
  font-size: calc(1.1875rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  line-height: 1.25;
}

.gift-card__price {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.45rem;
  font-size: 0.9375rem;
  font-weight: 500;
}

.gift-card__per {
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.gift-card__note {
  color: var(--muted-600);
  font-size: calc(0.8125rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.65);
}

.gift-card__calc {
  display: block;
  margin-block-start: 0.45rem;
  padding-block-start: 0.65rem;
  border-block-start: 1px solid var(--gold-line);
  font-size: calc(0.8125rem * var(--fs-text, 1));
  animation: settle var(--dur) var(--ease) both;
}

/* The live summary: label, calculation, amount — then the line total under
   one gold rule, set a size up. */
.buy__sum { display: grid; gap: 0.6rem; margin: 0; }

.buy__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: 1rem;
}
.buy__row dd { margin: 0; }
.buy__row[data-sum-gift] { animation: settle var(--dur) var(--ease) both; }

.buy__calc { color: var(--muted-600); font-size: 0.8125rem; }
/* justify-self puts the box at the row's end in either direction. Inside it
   every amount sits at the right — the box's end in English, its start in
   Arabic — so the figures end in one column (in English the symbol after
   them is the same width on every row) and the decimal points of the rows
   line up in both locales. */
.buy__amount { justify-self: end; min-width: 6.5rem; font-size: 0.9375rem; text-align: end; }
[dir="rtl"] .buy__amount { text-align: start; }

.buy__row--total {
  grid-template-columns: minmax(0, 1fr) auto;
  margin-block-start: 0.2rem;
  padding-block-start: 0.85rem;
  border-block-start: 1px solid var(--gold-line);
}
.buy__row--total dt { color: var(--ink-900); }
.buy__row--total .buy__amount { font-size: 1.25rem; font-weight: 500; }

.buy__add { width: 100%; min-height: 3.25rem; }

/* --- Cart lines (the page and the drawer) ----------------------------------- */

/* align-content: start — in the drawer the list is a flex:1 scroller taller
   than its lines, and a grid's default `stretch` would share that height out
   between the rows, opening a gap under every line. */
.lines { display: grid; align-content: start; }

/* Photo, then everything else: name and line total on one row, the unit
   price and any notice under it, then the controls. Lines are divided by
   gold hairlines, never boxed. */
.line {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: 1rem;
  padding-block: 1.25rem;
}
.line + .line { border-block-start: 1px solid var(--gold-line); }

.line__media { align-self: start; }
.is-unavailable .line__media .media__img { opacity: 0.45; }

.line__body { display: grid; align-content: start; gap: 0.3rem; min-inline-size: 0; }

.line__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.line__name {
  font-family: var(--font-display);
  font-size: calc(1.0625rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  line-height: 1.3;
  transition: color var(--dur) var(--ease);
}
.line__name:hover { color: var(--gold-600); }
.is-unavailable .line__name { color: var(--muted-600); }

.line__total { flex: none; font-size: 0.9375rem; font-weight: 500; }
.line__unit { color: var(--muted-600); font-size: 0.8125rem; }

.line__notice {
  margin-block-start: 0.35rem;
  padding-inline-start: 0.75rem;
  border-inline-start: 2px solid var(--gold-600);
  font-size: calc(0.8125rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.55);
}

.line__controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-block-start: 0.45rem;
}

/* Remove is always the last thing on its row, stepper or not. */
.line__remove { margin-inline-start: auto; }

.line__remove-btn, .summary__onwards, .co-sec__edit {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted-600);
  font-family: var(--font-body);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 5px;
  cursor: pointer;
  transition: color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease);
}
.line__remove-btn:hover, .summary__onwards:hover, .co-sec__edit:hover {
  color: var(--ink-900);
  text-decoration-color: var(--gold-600);
}
/* Remove reads as a word but is a line's destructive control, and «إزالة» on
   its own is 18px wide: it gets a real box, --tap wide at least, with the word
   at the box's inline end, so it lines up with the line total above it
   instead of floating a few pixels in from that edge. */
.line__remove-btn { min-inline-size: var(--tap); justify-content: flex-end; }

/* A line's gift wrapping: a button that toggles (aria-pressed), dressed as
   the store's tick box so it reads as the choice it is. */
.gift-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-900);
  font-family: inherit;
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  text-align: start;
  cursor: pointer;
}
.gift-toggle .tick { width: 18px; height: 18px; }
.gift-toggle:hover .tick { border-color: var(--gold-600); }
.gift-toggle__price { color: var(--muted-600); }

/* --- The summary ----------------------------------------------------------- */

.summary { display: grid; gap: 1.25rem; }

.summary__title { font-size: calc(1.375rem * var(--fs-head, 1)); }

.summary__rows { display: grid; gap: 0.7rem; margin: 0; }

.summary__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: calc(0.875rem * var(--fs-ui, 1));
}
.summary__row dt { color: var(--muted-600); }
.summary__value { margin: 0; }
.summary__value--note { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); }

.summary__row--total {
  margin-block-start: 0.35rem;
  padding-block-start: 1rem;
  border-block-start: 1px solid var(--gold-line);
}
.summary__row--total dt {
  color: var(--ink-900);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}
.summary__row--total .summary__value { font-size: 1.375rem; font-weight: 500; }

.summary__actions { display: grid; gap: 0.5rem; }
.summary__checkout { width: 100%; }
.summary__onwards { justify-self: center; }

/* --- The /cart page ---------------------------------------------------------- */

.cart { padding-block: 2rem var(--section); }

.cart__title {
  margin-block-end: 1.5rem;
  padding-block-end: 1.25rem;
  border-block-end: 1px solid var(--gold-line);
}

.cart-view--page .notices { margin-block-end: 1.5rem; }
/* The title's rule is already the empty state's top edge. */
.cart-view--page .cart-empty { border-block-start: 0; }
.cart-view--page .cart-view__filled { display: grid; gap: 2rem; }

/* The summary as a quiet panel: one hairline, a tint of --surface-200 that
   keeps --muted-600 above 5:1 (the solid token would drop it to ~4.5). */
.cart-view--page .summary {
  padding: 1.75rem 1.5rem;
  border: 1px solid var(--gold-line);
  background: rgba(231, 227, 216, 0.4);
}

@media (min-width: 900px) {
  .cart-view--page .cart-view__filled {
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: clamp(2.5rem, 4vw, 4.5rem);
    align-items: start;
  }
  /* Below the 76px sticky header. */
  .cart-view--page .summary { position: sticky; inset-block-start: calc(76px + 1.5rem); }
  .cart-view--page .line { grid-template-columns: 6rem minmax(0, 1fr); gap: 1.5rem; }
  .cart-view--page .line:first-child { padding-block-start: 0; }
}

/* --- The cart drawer --------------------------------------------------------- */

/* A modal panel from the inline-end side, on its own rung of the ladder
   (--z-cart): unlike the nav drawer it is not inside the header, so it cannot
   borrow that stacking context. `hidden` (set by cart-drawer.js once the
   slide-out has run) takes it out of the page entirely; between the two, a
   closing drawer lets every click through. */
.cart-drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-cart);
}
.cart-drawer:not(.is-open) { pointer-events: none; }

.cart-drawer__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 17, 2, 0.55);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}

.cart-drawer__panel {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  display: flex;
  flex-direction: column;
  width: min(92vw, 27rem);
  background: var(--ivory-050);
  border-inline-start: 1px solid var(--gold-line);
  transform: translateX(100%);
  transition: transform var(--dur-slow) var(--ease);
}
[dir="rtl"] .cart-drawer__panel { transform: translateX(-100%); }
.cart-drawer__panel:focus { outline: none; }

.cart-drawer.is-open .cart-drawer__scrim { opacity: 1; }
.cart-drawer.is-open .cart-drawer__panel { transform: none; }

.cart-drawer__head {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.75rem;
  padding-inline: 1.5rem 0.75rem;
  border-block-end: 1px solid var(--gold-line);
}

.cart-drawer__title { font-size: calc(1.5rem * var(--fs-head, 1)); }

.cart-drawer__close {
  position: relative;
  flex: none;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-900);
  cursor: pointer;
}
.cart-drawer__close::before, .cart-drawer__close::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 18px;
  height: 1px;
  margin: auto;
  background: currentColor;
  transform: rotate(45deg);
  transition: background var(--dur) var(--ease);
}
.cart-drawer__close::after { transform: rotate(-45deg); }
.cart-drawer__close:hover { color: var(--gold-600); }

/* Inside the panel the lines scroll, and the summary stays pinned under
   them — the total and checkout are always one glance away. */
.cart-view--drawer, .cart-view--drawer .cart-view__filled {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}
.cart-view--drawer .notices { flex: none; padding: 1rem 1.5rem 0; }
.cart-view--drawer .lines {
  flex: 1;
  min-height: 0;
  padding-inline: 1.5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.cart-view--drawer .summary {
  flex: none;
  gap: 1rem;
  padding-block: 1.25rem max(1.25rem, env(safe-area-inset-bottom));
  padding-inline: 1.5rem;
  border-block-start: 1px solid var(--gold-line);
}
.cart-view--drawer .summary__rows { gap: 0.5rem; }
.cart-view--drawer .summary__row--total .summary__value { font-size: 1.25rem; }
.cart-view--drawer .summary__onwards { justify-self: stretch; justify-content: center; }
.cart-view--drawer .cart-empty { margin: 1.5rem; padding-block: 3rem; }

/* The drawer is titled already; its summary keeps a heading for a screen
   reader's outline, out of sight. */
.cart-view--drawer .summary__title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Waiting, the toast, and the page held still --------------------------- */

/* A write in flight (aria-busy, cart-drawer.js) dims what it will redraw — a
   beat late, so an answer that comes back at once never flickers. */
.lines, .summary, .buy__add { transition: opacity var(--dur) var(--ease); }
[aria-busy="true"] .lines, [aria-busy="true"] .summary, [aria-busy="true"] .buy__add {
  opacity: 0.55;
  cursor: progress;
  transition-delay: 160ms;
}

/* A refusal, said once at the foot of the screen and above the drawer. */
.toast {
  position: fixed;
  z-index: var(--z-toast);
  inset-inline: 1rem;
  inset-block-end: max(1rem, env(safe-area-inset-bottom));
  max-width: 26rem;
  margin-inline: auto;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  background: var(--green-900);
  color: var(--ivory-050);
  font-size: calc(0.875rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.5);
  opacity: 0;
  transform: translateY(0.75rem);
  pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.toast.is-shown { opacity: 1; transform: none; }

/* A modal drawer is open (public/js/store/focus-trap.js): the page under it
   stays put. The gutter is kept, so the page does not jump sideways by a
   scrollbar's width on a desktop that shows one. */
html.has-modal { overflow: hidden; scrollbar-gutter: stable; }

/* ---------------------------------------------------------------------------
   CHECKOUT AND THE ORDER PAGE — one reading column, numbered sections under
   gold hairlines, fields that say what they need, and the store's double
   gold mount around the figures that matter (the total, a gift's message).
--------------------------------------------------------------------------- */

/* A form reads down: one column, never wider than a comfortable line. */
.checkout, .order {
  max-width: calc(40rem + 2 * var(--gutter));
  padding-block: 2rem var(--section);
}

.checkout__head, .order__head {
  padding-block-end: 1.5rem;
  border-block-end: 1px solid var(--gold-line);
}

.checkout__eyebrow, .order__number {
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
}
.checkout__title, .order__title { margin-block-start: 0.6rem; }

.checkout .notices { margin-block-start: 1.5rem; }

/* Every problem with a submitted form, listed once above it, each a link
   to its field — the notice's quiet panel and gold rule, read out at once. */
.checkout__errors {
  padding-block: 0.9rem;
  padding-inline: 1rem;
  border: 1px solid var(--gold-line);
  border-inline-start: 3px solid var(--gold-600);
  background: rgba(231, 227, 216, 0.35);
  font-size: calc(0.875rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.6);
}
.checkout__errors-title { font-weight: 500; }
.checkout__errors-list { display: grid; gap: 0.35rem; margin-block-start: 0.5rem; }
.checkout__errors-list a {
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-underline-offset: 4px;
}

/* --- Sections ------------------------------------------------------------ */

.co-sec { padding-block: 2.5rem; }
.co-sec + .co-sec { border-block-start: 1px solid var(--gold-line); }

.co-sec__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-block-end: 1.5rem;
}

.co-sec__title {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  font-size: calc(clamp(1.5rem, 1.25rem + 1vw, 1.875rem) * var(--fs-head, 1));
}

/* The section's number: an ornament in gold, beside words set in ink. */
.co-sec__num {
  flex: none;
  color: var(--gold-600);
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
}

.co-sec__body { display: grid; gap: 1.5rem; }

/* --- Fields -------------------------------------------------------------- */

.field { display: grid; gap: 0.5rem; }

.field__label {
  font-size: calc(0.75rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}
/* Arabic small text sets smaller than Latin at one size, and here it is
   read, not glanced at. */
html[lang="ar"] .field__label { font-size: calc(0.875rem * var(--fs-ui, 1)); }

/* The frame is --muted-600, like the sort menu's: a control's edge must
   reach 3:1, which the gold hairline does not. 16px text, or iOS zooms the
   page into every field it focuses. */
.field__control {
  width: 100%;
  min-height: var(--tap);
  padding-block: 0.7rem;
  padding-inline: 0.9rem;
  border: 1px solid var(--muted-600);
  border-radius: 2px;
  background: var(--ivory-050);
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: calc(1rem * var(--fs-ui, 1));
  line-height: 1.4;
  transition: border-color var(--dur) var(--ease);
}
.field__control:hover { border-color: var(--gold-600); }
.field__control:focus-visible { border-color: var(--ink-900); outline-offset: 2px; }
.field__control--area { min-height: 6.5rem; resize: vertical; line-height: var(--lh-copy, 1.6); }

.field__hint { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); line-height: var(--lh-copy, 1.55); }

/* A field that failed: a heavier gold edge at its start, and the words
   under it — in ink, after a gold dash, never in colour alone. */
.field__control[aria-invalid="true"] {
  border-color: var(--gold-600);
  border-inline-start-width: 3px;
}
/* A phone or an email is typed left to right even on an Arabic page. It
   still lines up with the page's other fields, and its error edge sits on
   the page's start side like theirs — its OWN start would be the left. */
[dir="rtl"] .field__control[dir="ltr"] { text-align: end; }
[dir="rtl"] .field__control[dir="ltr"][aria-invalid="true"] {
  border-inline-start-width: 1px;
  border-inline-end-width: 3px;
}
.field__error {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  font-size: calc(0.8125rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.55);
}
.field__error::before {
  content: "";
  flex: none;
  width: 0.75rem;
  height: 1px;
  background: var(--gold-600);
  transform: translateY(-0.3em);
}

/* --- The gift: the product page's tick card, and what it opens ------------ */

/* The recipient's fields open under the ticked box, and the address heading
   turns to the recipient's — by :has(), so it all works with every script
   blocked. A browser without :has() shows the fields always (the server
   asks for them only for a gift) and keeps the plain heading. */
.co-gift__fields { display: grid; gap: 1.5rem; animation: settle var(--dur) var(--ease) both; }
.checkout:has(.co-gift-check:not(:checked)) .co-gift__fields { display: none; }

.co-when-gift { display: none; }
.checkout:has(.co-gift-check:checked) .co-when-gift { display: inline; }
.checkout:has(.co-gift-check:checked) .co-when-plain { display: none; }

/* --- Consent: the store's tick box on a real, visually hidden checkbox ----- */

.co-check {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 0.85rem;
  min-height: 44px;
  padding-block: 0.55rem;
  cursor: pointer;
}
.co-check__box {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}
.co-check .tick { margin-block-start: 0.2rem; }
.co-check__box:checked + .tick { background: var(--green-900); border-color: var(--green-900); }
.co-check__box:checked + .tick::after { opacity: 1; transform: translateY(-1px) rotate(45deg); }
.co-check__box:focus-visible + .tick { outline: 2px solid var(--gold-600); outline-offset: 2px; }
.co-check__box[aria-invalid="true"] + .tick { border: 2px solid var(--gold-600); }
.co-check__text { font-size: calc(0.875rem * var(--fs-text, 1)); line-height: var(--lh-copy, 1.6); }
.co-check__text a {
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-underline-offset: 4px;
}

/* --- Items and totals (checkout's review, and the order page) ------------- */

.item-rows { display: grid; }

.item-row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto;
  align-items: start;
  gap: 1rem;
  padding-block: 1rem;
}
.item-row + .item-row { border-block-start: 1px solid var(--gold-line); }
.item-row:first-child { padding-block-start: 0; }

.item-row__body { display: grid; gap: 0.2rem; min-inline-size: 0; }
.item-row__name {
  font-family: var(--font-display);
  font-size: calc(1.0625rem * var(--fs-head, 1));
  font-weight: var(--wt-display);
  line-height: 1.3;
}
.item-row__meta { justify-self: start; color: var(--muted-600); font-size: 0.8125rem; }
/* A small gold lozenge marks a wrapped line: the one ornament a line gets. */
.item-row__gift { font-size: calc(0.8125rem * var(--fs-text, 1)); }
.item-row__gift::before {
  content: "";
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  margin-inline-end: 0.5rem;
  border: 1px solid var(--gold-600);
  transform: translateY(-0.1em) rotate(45deg);
}
.item-row__total { font-size: 0.9375rem; font-weight: 500; }

/* The figures in the store's mount — two gold rules 3px apart, the gift
   card's frame — so the total reads as the page's one framed object. The
   second rule is an outline: it takes no room, hence the 4px margin. */
.tally {
  margin: 4px;
  padding: 1.25rem 1.25rem 1.1rem;
  border: 1px solid var(--gold-line);
  outline: 1px solid var(--gold-line);
  outline-offset: 3px;
  background: rgba(231, 227, 216, 0.4);
}
.tally__rows { display: grid; gap: 0.7rem; margin: 0; }
.tally__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: calc(0.875rem * var(--fs-ui, 1));
}
.tally__row dt { color: var(--muted-600); }
.tally__row dd { margin: 0; }
.tally__eta::before { content: " · "; }
.tally__pending { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); text-align: end; }
.tally__row--total {
  margin-block-start: 0.35rem;
  padding-block-start: 0.9rem;
  border-block-start: 1px solid var(--gold-line);
}
.tally__row--total dt {
  color: var(--ink-900);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}
.tally__row--total dd { font-size: 1.5rem; font-weight: 500; }

/* --- Paying --------------------------------------------------------------- */

.co-pay { display: grid; gap: 0.85rem; }
.checkout__pay, .order__pay-btn, .checkout__wa { width: 100%; }
.checkout__pay, .order__pay-btn { min-height: 3.5rem; font-size: calc(0.875rem * var(--fs-ui, 1)); }
.co-pay__note { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); text-align: center; }

/* --- The order page --------------------------------------------------------- */

.order__notice { margin-block-end: 1.5rem; }
.order__lede { margin-block-start: 1rem; max-width: 46ch; font-size: calc(1.0625rem * var(--fs-text, 1)); }
.order__date { margin-block-start: 0.75rem; color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); }

/* Four steps on one hairline: a reached step's dot is filled, the line
   behind it drawn in gold, the current step ringed. Logical insets, so the
   line runs toward the next step in either direction. */
.progress {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-block-start: 2rem;
}
.progress__step {
  position: relative;
  padding-block-start: 1.35rem;
  color: var(--muted-600);
  font-size: calc(0.75rem * var(--fs-ui, 1));
  text-align: center;
}
html[lang="ar"] .progress__step { font-size: calc(0.8125rem * var(--fs-ui, 1)); }
.progress__step::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset-block-start: 0;
  inset-inline-start: 50%;
  width: 9px;
  height: 9px;
  margin-inline-start: -4.5px;
  border: 1px solid var(--muted-600);
  border-radius: 50%;
  background: var(--ivory-050);
}
.progress__step:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-block-start: 4px;
  inset-inline-start: 50%;
  width: 100%;
  height: 1px;
  background: var(--gold-line);
}
.progress__step.is-done { color: var(--ink-900); }
.progress__step.is-done::before { border-color: var(--green-900); background: var(--green-900); }
.progress__step.is-done:not([aria-current])::after { background: var(--gold-600); }
.progress__step[aria-current="step"]::before { outline: 1px solid var(--gold-600); outline-offset: 2px; }

.order__pay { margin-block-start: 2rem; }

.order__sec {
  margin-block-start: 2.5rem;
  padding-block-start: 2.5rem;
  border-block-start: 1px solid var(--gold-line);
}
/* A cancelled or refunded order shows no progress, so its first section
   would follow the header straight away — two gold hairlines 40px apart
   with nothing between them. The header's own rule already divides them. */
.order__head + .order__sec { padding-block-start: 0; border-block-start: 0; }
.order__sec-title { margin-block-end: 1.25rem; font-size: calc(clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem) * var(--fs-head, 1)); }
/* On the order page the tally follows the item list directly (checkout's
   grid gap does this job there). */
.order .tally { margin-block-start: calc(1.5rem + 4px); }

/* A gift's message, in the same double mount as the total: the card that
   travels with the watch. Its lines are the sender's own. */
.gift-note {
  margin: 4px;
  padding: 1.35rem 1.5rem 1.5rem;
  border: 1px solid var(--gold-line);
  outline: 1px solid var(--gold-line);
  outline-offset: 3px;
  background: rgba(231, 227, 216, 0.25);
}
.gift-note__text {
  margin: 0;
  font-family: var(--font-display);
  font-size: calc(1.25rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.6);
  white-space: pre-line;
  overflow-wrap: anywhere;
}
.gift-note__by {
  margin-block-start: 0.85rem;
  color: var(--muted-600);
  font-size: calc(0.6875rem * var(--fs-ui, 1));
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: var(--caps);
}

.order__address { display: grid; gap: 0.2rem; font-style: normal; line-height: var(--lh-copy, 1.6); overflow-wrap: anywhere; }
.order__address-name { font-weight: 500; }
.order__address-notes { color: var(--muted-600); font-size: calc(0.875rem * var(--fs-text, 1)); }

.order__foot {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
  margin-block-start: 2.5rem;
  padding-block-start: 2rem;
  border-block-start: 1px solid var(--gold-line);
  text-align: center;
}
.order__help { font-size: calc(0.875rem * var(--fs-text, 1)); }
.order__help a {
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-underline-offset: 4px;
}

@media (min-width: 700px) {
  .co-sec { padding-block: 3.25rem; }
  .item-row { grid-template-columns: 4.25rem minmax(0, 1fr) auto; gap: 1.25rem; }
}

/* ---------------------------------------------------------------------------
   SIGNING IN AND THE ACCOUNT — one calm column. The sign-in pages are one
   panel in the store's double gold mount (the tally's and the gift note's
   frame); the account page is checkout's reading column: a greeting, the
   orders, then quiet forms under gold hairlines.
--------------------------------------------------------------------------- */

.auth {
  max-width: calc(30rem + 2 * var(--gutter));
  padding-block: 2.5rem var(--section);
}

.auth__mount {
  margin: 4px;
  border: 1px solid var(--gold-line);
  outline: 1px solid var(--gold-line);
  outline-offset: 3px;
  background: rgba(231, 227, 216, 0.22);
  animation: settle var(--dur-slow) var(--ease) both;
}
.auth__panel { padding: 2rem 1.25rem 2.25rem; }

.auth__head {
  padding-block-end: 1.5rem;
  border-block-end: 1px solid var(--gold-line);
  text-align: center;
}
/* Nothing under the header: no rule dividing the lede from an empty panel. */
.auth__panel--bare .auth__head { padding-block-end: 0; border-block-end: 0; }
.auth__eyebrow { color: var(--muted-600); font-size: calc(0.6875rem * var(--fs-ui, 1)); font-weight: 500; }
.auth__title { margin-block-start: 0.6rem; }
.auth__lede {
  max-width: 38ch;
  margin-block-start: 0.85rem;
  margin-inline: auto;
  color: var(--muted-600);
  font-size: calc(0.9375rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.65);
}

.auth .notices { margin-block-start: 1.25rem; }
.auth__form { display: grid; gap: 1.35rem; margin-block-start: 1.75rem; }
.auth__submit { width: 100%; min-height: 3.5rem; margin-block-start: 0.35rem; font-size: calc(0.875rem * var(--fs-ui, 1)); }
.auth__ready { margin-block-start: 1.75rem; font-size: calc(0.9375rem * var(--fs-text, 1)); line-height: var(--lh-copy, 1.6); text-align: center; }
.auth__wa { margin-block-start: 1.25rem; }
.auth__note {
  margin-block-start: 1.5rem;
  color: var(--muted-600);
  font-size: calc(0.8125rem * var(--fs-text, 1));
  line-height: var(--lh-copy, 1.6);
  text-align: center;
}

/* A field's label row: the label, and at its end one quiet link (forgot
   password). The link's tap target is 44px tall without making the row so:
   its padding reaches out, its negative margin takes the room back. */
.field__top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.field__aside {
  display: inline-flex;
  align-items: center;
  padding-block: 0.75rem;
  margin-block: -0.75rem;
  font-size: calc(0.8125rem * var(--fs-ui, 1));
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-underline-offset: 4px;
}

.auth__onwards { margin-block-start: 1.75rem; font-size: calc(0.9375rem * var(--fs-text, 1)); text-align: center; }
.auth__onwards a, .acct-order__no {
  text-decoration: underline;
  text-decoration-color: var(--gold-600);
  text-underline-offset: 4px;
}
/* The way onwards can be one short word («دخول» is 35px wide in Amiri), so
   its box is --tap wide at least, the word centred in it. */
.auth__onwards a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-inline-size: var(--tap);
  font-weight: 500;
}

@media (min-width: 700px) {
  .auth { padding-block-start: 4rem; }
  .auth__panel { padding: 2.75rem 2.75rem 3rem; }
}

/* --- The account page ------------------------------------------------------- */

.acct {
  max-width: calc(40rem + 2 * var(--gutter));
  padding-block: 2rem var(--section);
}
.acct__head { padding-block-end: 1.5rem; border-block-end: 1px solid var(--gold-line); }
.acct__eyebrow { color: var(--muted-600); font-size: calc(0.6875rem * var(--fs-ui, 1)); font-weight: 500; }
.acct__title { margin-block-start: 0.6rem; overflow-wrap: anywhere; }
.acct .notices { margin-block-start: 1.5rem; }

.acct__sec { padding-block: 2.5rem; }
.acct__sec + .acct__sec { border-block-start: 1px solid var(--gold-line); }
.acct__sec-head { margin-block-end: 1.5rem; }
.acct__sec-title { font-size: calc(clamp(1.5rem, 1.25rem + 1vw, 1.875rem) * var(--fs-head, 1)); }
.acct__sec-lede { margin-block-start: 0.5rem; color: var(--muted-600); font-size: calc(0.875rem * var(--fs-text, 1)); line-height: var(--lh-copy, 1.6); }
.acct__empty { color: var(--muted-600); }

.acct__form { display: grid; gap: 1.5rem; }
.acct__save { width: 100%; }
/* The email is the account's name, not a field: shown, not edited. */
.acct__static {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: 0.9rem;
  background: rgba(231, 227, 216, 0.35);
  color: var(--muted-600);
  overflow-wrap: anywhere;
}
[dir="rtl"] .acct__static[dir="ltr"] { justify-content: flex-end; }

/* An order: one link, a row under a gold hairline — number and total on
   the first line, status and date under them. */
.acct-orders { display: grid; border-block-start: 1px solid var(--gold-line); }
.acct-order {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.4rem 1rem;
  align-items: baseline;
  min-height: var(--tap);
  padding-block: 1.1rem;
  padding-inline: 0.25rem;
  border-block-end: 1px solid var(--gold-line);
  transition: background var(--dur) var(--ease);
}
.acct-order:hover { background: rgba(231, 227, 216, 0.35); }
.acct-order__no { font-weight: 500; letter-spacing: 0.02em; }
.acct-order__total { font-weight: 500; text-align: end; }
.acct-order__date { color: var(--muted-600); font-size: calc(0.8125rem * var(--fs-text, 1)); text-align: end; }
/* The status in words, after a dot that carries its colour: gold while
   payment is due, green once paid, muted when it left the path. */
.acct-order__status { display: inline-flex; align-items: center; gap: 0.5rem; font-size: calc(0.8125rem * var(--fs-ui, 1)); }
.acct-order__status::before {
  content: "";
  flex: none;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--gold-600);
}
.acct-order__status--paid::before, .acct-order__status--shipped::before,
.acct-order__status--delivered::before { background: var(--green-800); }
.acct-order__status--cancelled::before, .acct-order__status--refunded::before { background: var(--muted-600); }

.acct__logout { padding-block-start: 2rem; border-block-start: 1px solid var(--gold-line); }
.acct__logout-btn { width: 100%; }

@media (min-width: 700px) {
  .acct__sec { padding-block: 3.25rem; }
  .acct__save, .acct__logout-btn { width: auto; justify-self: start; }
}

/* ---------------------------------------------------------------------------
   Motion — transform/opacity only, and off entirely when asked.
--------------------------------------------------------------------------- */

/* Reveal-on-scroll. Both classes are added by public/js/store/reveal.js and
   neither is ever written by the server: a section is visible unless script
   has explicitly armed it, so a page with JavaScript off — or blocked — is a
   page with every section on it. `reveal-armed` is only applied to elements
   that are below the fold when the script runs, which is why there is no
   transition on it: nothing the visitor can see ever changes state. */
.reveal-armed { opacity: 0; }
.reveal-in { animation: reveal var(--dur-slow) var(--ease) both; }

@keyframes reveal {
  from { opacity: 0; transform: translateY(1.75rem); }
  to { opacity: 1; transform: none; }
}

@keyframes scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes drawer-in { from { transform: translateX(-100%); } to { transform: translateX(0); } }
@keyframes drawer-in-rtl { from { transform: translateX(100%); } to { transform: translateX(0); } }
/* A part the buy panel reveals (the gift line, its summary row) settles into place. */
@keyframes settle { from { opacity: 0; transform: translateY(-0.35rem); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
