/* ==========================================================================
   GHAFWA — styles.css
   Order: Tokens → Reset/Base → Typography → Layout → Components →
          Sections → Motion → Media queries → Reduced-motion
   ========================================================================== */


/* ==========================================================================
   TOKENS
   ========================================================================== */

:root {

  /* -- Colour -------------------------------------------------------------- */
  --ink:        #1B1812;  /* night / rest sections — warm near-black */
  --ecru:       #F3ECDE;  /* day / provenance sections — raw cotton */
  --brass:      #B08D57;  /* the needle, the thread, the accent stroke */
  --ink-soft:   #2B2620;  /* borders / dividers on ink */
  --ecru-soft:  #E4D9C3;  /* borders / dividers on ecru */

  /* semantic aliases — components read these, never the raw colours */
  --text-dark:  var(--ink);
  --text-light: var(--ecru);

  /* -- Type scale (fluid, 320px → 1440px) ---------------------------------- */
  --text-xs:   clamp(0.75rem,   0.71rem + 0.2vw,  0.8125rem);
  --text-sm:   clamp(0.875rem,  0.82rem + 0.25vw, 0.9375rem);
  --text-base: clamp(1rem,      0.94rem + 0.3vw,  1.125rem);
  --text-md:   clamp(1.1875rem, 1.05rem + 0.65vw, 1.375rem);
  --text-lg:   clamp(1.5rem,    1.25rem + 1.2vw,  2rem);
  --text-xl:   clamp(2rem,      1.55rem + 2.2vw,  3rem);
  --text-2xl:  clamp(2.5rem,    1.75rem + 3.6vw,  4.25rem);
  --text-3xl:  clamp(3rem,      1.9rem + 5.4vw,   5.5rem);

  /* -- Spacing scale (fluid) ------------------------------------------------ */
  --space-3xs: clamp(0.25rem, 0.23rem + 0.1vw,  0.3125rem);
  --space-2xs: clamp(0.5rem,  0.46rem + 0.2vw,  0.625rem);
  --space-xs:  clamp(0.75rem, 0.68rem + 0.35vw, 0.9375rem);
  --space-sm:  clamp(1rem,    0.9rem + 0.5vw,   1.25rem);
  --space-md:  clamp(1.5rem,  1.3rem + 1vw,     2rem);
  --space-lg:  clamp(2.5rem,  2rem + 2.5vw,     3.5rem);
  --space-xl:  clamp(4rem,    3rem + 5vw,       6rem);
  --space-2xl: clamp(6rem,    4.3rem + 8.5vw,   9.5rem);

  /* -- Layout --------------------------------------------------------------- */
  --content-max: 70rem;

  /* -- Type roles (family) ---------------------------------------------------
     Spectral   → display   (headings, the wordmark's Latin half)
     Hanken Grotesk → body  (paragraphs, controls, the CTA label)
     Space Mono → utility/data (eyebrows, data lines, price)
     Amiri      → Arabic wordmark only
  --------------------------------------------------------------------------- */
  --font-display: 'Spectral', Georgia, serif;
  --font-body:    'Hanken Grotesk', -apple-system, sans-serif;
  --font-mono:    'Space Mono', ui-monospace, monospace;
  --font-arabic:  'Amiri', 'Times New Roman', serif;

  /* -- Weight ---------------------------------------------------------------- */
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  /* -- Line-height ------------------------------------------------------------ */
  --leading-tight:   1.08;
  --leading-snug:    1.25;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;

  /* -- Letter-spacing ---------------------------------------------------------- */
  --tracking-tighter: -0.02em;
  --tracking-tight:   -0.01em;
  --tracking-normal:   0;
  --tracking-wide:     0.02em;
  --tracking-wider:    0.08em;

  /* -- Motion (referenced once the Motion banner below grows) ------------------ */
  --duration-fast: 150ms;
  --duration-base: 300ms;
  --duration-slow: 600ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
}


/* ==========================================================================
   RESET / BASE
   ========================================================================== */

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

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

body,
h1, h2, h3,
p, figure, blockquote, dl, dd,
ol, ul {
  margin: 0;
}

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

img, picture, svg {
  max-width: 100%;
  display: block;
}

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

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

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

body {
  background: var(--ecru);
  color: var(--text-dark);
  overflow-x: hidden;
  min-height: 100vh;
  opacity: 0;
  transition: opacity 400ms ease;
}

body.is-loaded {
  opacity: 1;
}


/* ==========================================================================
   TYPOGRAPHY
   ========================================================================== */

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  line-height: var(--leading-relaxed);
}

h1, h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h1 em, h2 em {
  font-style: italic;
  font-weight: inherit;
}

.hero h1 em {
  color: var(--brass);
}

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

h1 {
  font-size: var(--text-3xl);
  letter-spacing: var(--tracking-tighter);
}

h2 {
  font-size: var(--text-xl);
}

p {
  max-width: 38em; /* keeps prose from stretching past a comfortable line length */
}

.sub {
  font-size: var(--text-md);
  line-height: var(--leading-snug);
}

/* utility / data role — eyebrows, data lines, price. Colour comes from --fg,
   set per-section below, so it flips correctly on ink vs ecru backgrounds. */
.eyebrow,
.data-line,
.price {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--fg, var(--text-dark));
}

/* Eyebrows are navigation tags; data-line/price are evidentiary claims —
   the hairline marks them as a measured readout, not just another label. */
.data-line,
.price {
  padding-top: var(--space-3xs);
  border-top: 1px solid var(--border-soft);
}

/* GHAFWA sits as a small, precise mono caption beneath the Arabic mark —
   a lab label under the dominant glyph, not a second logo. */
.wordmark__lat {
  font-family: var(--font-mono);
  font-weight: var(--weight-regular);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.wordmark__ar {
  font-family: var(--font-arabic);
  font-weight: var(--weight-bold);
  font-size: var(--text-2xl);
  line-height: 1;
}

.wordmark--quiet {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  opacity: 0.7;
}


/* ==========================================================================
   LAYOUT
   ========================================================================== */

main {
  display: block;
  width: 100%;
}

/* Sections stay full-width so their opaque ink/ecru backgrounds bleed to the
   viewport edge — capping width here is what made each section read as a
   centred box. The padding-inline calc keeps the readable content column at
   --content-max on wide screens without clipping the background. */
section {
  position: relative; /* establishes nothing above 0 — no z-index here, so
    the thread layer (z-index: 5, added next) still paints above every
    section's opaque background */
  width: 100%;
  padding-inline: max(var(--space-md), calc((100% - var(--content-max)) / 2));
  padding-block: var(--space-lg);
}

/* One vertical-rhythm mechanism for the whole page: every section's direct
   children space themselves out the same way, so .section and component
   selectors never need to fight over margin. */
section > * + * {
  margin-top: var(--space-sm);
}


/* ==========================================================================
   COMPONENTS
   ========================================================================== */

:focus-visible {
  outline: 2px solid var(--fg, var(--ink));
  outline-offset: 3px;
}

.wordmark {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3xs);
}

/* Brass keeps its own fixed fill/text pairing regardless of section colour —
   brass text directly on ecru fails contrast, so the CTA carries its own
   surface instead of inheriting --fg for its fill. */
.cta {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  font-size: var(--text-base);
  letter-spacing: var(--tracking-wide);
  padding: var(--space-2xs) var(--space-md);
  border: 1px solid var(--fg, var(--ink));
  background-color: var(--brass);
  color: var(--ink);
  transition: letter-spacing var(--duration-base) var(--ease-standard),
              border-color var(--duration-base) var(--ease-standard);
}

.cta:hover {
  letter-spacing: var(--tracking-wider);
  box-shadow: 0 0 0 2px var(--fg, var(--ink)); /* a ring, not a border-colour
    swap — swapping to a fixed colour would vanish on ink-background
    instances (the hero CTA), since --fg already tracks each section */
}

/* -- Reserve form. Reserve is locked as the ecru section (the brass CTA
   reads as the only warm light on the page), so this is designed for
   brass-as-accent-only on a light surface, not brass as primary text/fill —
   brass directly on ecru is ~2.6:1, below AA, so it's reserved for the
   focus moment and the status accent stripe, never for body-readable text. -- */
.reserve-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  max-width: 32rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.field label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--ink-soft);
  border-radius: 0;
  padding: var(--space-2xs) var(--space-2xs);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.2; /* without this, <select> computes a taller intrinsic
    box than <input> in most browsers (extra UA space for the dropdown
    arrow), so .field-row's align-items: flex-end aligns their outer boxes
    but the visible underlines end up at different heights */
  transition: border-color var(--duration-base) var(--ease-standard);
}

.field textarea {
  min-height: 4rem;
  resize: vertical;
}

.field select {
  background: var(--bg);
  color: var(--fg);
}

.field select option {
  background: var(--bg);
  color: var(--fg);
}

.field-row {
  display: flex;
  align-items: flex-end;
  gap: var(--space-sm);
}

.field-row > .field {
  flex: 1;
}

.field-row > .field.field--code {
  flex: 0 0 20%;
}

.field--code select {
  width: auto;
}


/* The brand accent shows up exactly at the moment of interaction — idle
   fields stay quiet (ink-soft hairline); the global :focus-visible outline
   still fires too, so brass is decoration on top of an already-accessible
   focus state, not the only signal. */
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  border-bottom-color: var(--brass);
}

.reserve-form .cta {
  width: 100%; /* a small, precise tap target isn't comfortable one-handed —
    the submit button (unlike the hero's CTA) spans the field column */
  text-align: center;
}

.form-status {
  margin-top: var(--space-xs);
  padding: var(--space-3xs) var(--space-sm);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  border-left: 3px solid var(--ink-soft);
}

.form-status:empty {
  display: none;
}

/* No red/green — the palette stays to ink/ecru/brass, so success and error
   are told apart by weight and the accent stripe, not by hue. */
.form-status--success {
  border-left-color: var(--brass);
}

.form-status--error {
  border-left-color: var(--ink);
  font-weight: var(--weight-semibold);
}


/* ==========================================================================
   SECTIONS
   ========================================================================== */

/* Alternation in page order: hero(1) ink, provenance(2) ecru, the-set(3) ink,
   the-feel(4) ecru, how-it-works(5) ink, reserve(6) ecru — so the page never
   reads as one flat cream field. --fg/--bg/--border-soft are set here and
   read by components above (.cta, .eyebrow/.data-line/.price, :focus-visible,
   .steps) so colour flips correctly without per-section overrides. */
main > section {
  --fg: var(--text-dark);
  --bg: var(--ecru);
  --border-soft: var(--ecru-soft);
  background: var(--bg);
  color: var(--fg);
}

main > section:nth-of-type(odd) {
  --fg: var(--text-light);
  --bg: var(--ink);
  --border-soft: var(--ink-soft);
}

.site-footer {
  --fg: var(--text-light);
  --bg: var(--ink);
  background: var(--bg);
  color: var(--fg);
  padding-inline: max(var(--space-md), calc((100% - var(--content-max)) / 2));
  padding-block: var(--space-md);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.footer-links {
  display: flex;
  gap: var(--space-md);
}

.footer-links a {
  position: relative;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.footer-links a::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 1px;
  background: currentColor;
  transition: width var(--duration-base) var(--ease-standard);
}

.footer-links a:hover::after {
  width: 100%;
}

/* -- Hero: the thesis. Pushed into the lower portion of a near-full-height
   block so the page opens on negative space, not a centred title card. -- */
.hero {
  min-height: 92vh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-sm);
  padding-block: var(--space-2xl) var(--space-xl);
}

.hero > * + * {
  margin-top: 0; /* the flex gap above already spaces these children —
    without this, the global `section > * + *` rhythm rule would add a
    second, conflicting margin on top of the gap */
}

.hero h1 {
  max-width: 22ch; /* holds the headline to an editorial column, leaving the
    asymmetric right-hand whitespace at wide viewports */
}

.hero .sub {
  max-width: 32ch;
}

/* -- The set: 3 colour photos in one slot, switched by a CSS-only radio
   picker (no JS — required to keep working with scripting disabled). The
   photo frame keeps the tonal placeholder background so the box never
   collapses or shows a broken-image icon while a photo loads. -- */
.the-set .image-slot {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  width: 100%;
  max-width: 28rem;
}

.photo-frame {
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--ecru-soft);
}

.colour-photo {
  display: none;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.colour-photo[data-colour="taupe"] {
  display: block; /* safe default if :has() is ever unsupported */
}

.colour-name {
  display: none;
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--fg);
}

.colour-picker {
  display: flex;
  gap: var(--space-2xs);
}

.colour-radio {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.colour-radio:focus-visible {
  outline: none; /* the swatch ring below is the real focus indicator —
    without this, the global :focus-visible rule also draws a near-invisible
    1px outline around the hidden radio itself */
}

.swatch {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  cursor: pointer;
  display: inline-block;
  background: var(--swatch);
  border: 1px solid var(--border-soft);
}

.colour-radio:checked + .swatch,
.colour-radio:focus-visible + .swatch {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
}

.image-slot:has(#colour-navy:checked) .colour-photo[data-colour="taupe"] { display: none; }
.image-slot:has(#colour-navy:checked) .colour-photo[data-colour="navy"] { display: block; }
.image-slot:has(#colour-ecru:checked) .colour-photo[data-colour="taupe"] { display: none; }
.image-slot:has(#colour-ecru:checked) .colour-photo[data-colour="ecru"] { display: block; }

.image-slot:has(#colour-taupe:checked) .colour-name[data-colour="taupe"] { display: block; }
.image-slot:has(#colour-navy:checked) .colour-name[data-colour="navy"] { display: block; }
.image-slot:has(#colour-ecru:checked) .colour-name[data-colour="ecru"] { display: block; }

/* -- How it works: three quiet points, not cards -- */
.steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  counter-reset: step;
}

.steps li {
  position: relative;
  padding-left: 2.5em;
  counter-increment: step;
}

.steps li + li {
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border-soft);
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  color: var(--fg);
}



/* ==========================================================================
   MOTION
   ========================================================================== */

html {
  scroll-behavior: smooth;
}

/* One-time "iris wipe" intro. The element itself is a growing, transparent
   ellipse; its giant box-shadow (not the element) paints solid black
   everywhere else — so as width/height grow, the black recedes outward
   from the centre and the page reads as opening like an eye. This avoids
   animating a gradient mask: cross-browser gradient interpolation in
   @keyframes isn't reliably smooth (it tends to snap rather than widen),
   whereas plain width/height are universally smooth to animate. z-index:
   100 deliberately beats the thread layer's z-index: 5, so it covers the
   thread during the reveal regardless of the thread's own load timing.
   Pure CSS — no JS involved, so it still plays with JavaScript disabled. */
.intro-overlay {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 100vmax var(--ink);
  transform: translate(-50%, -50%);
  z-index: 100;
  pointer-events: none;
  animation: iris-open 4s ease-out forwards;
}

@keyframes iris-open {
  from {
    width: 0;
    height: 0;
  }
  to {
    width: 600vmax;
    height: 100vmax; /* shorter than width, so border-radius: 50% stretches
      this into an eye-like ellipse rather than a plain circle */
  }
}

.thread-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 5; /* MUST sit above the opaque section blocks */
  overflow: visible;
}

.thread-base {
  fill: none;
  stroke: var(--brass);
  stroke-width: 1.5px;
  stroke-linecap: round;
  opacity: 0.22;
}

.thread-active {
  fill: none;
  stroke: var(--brass);
  stroke-width: 1.5px;
  stroke-linecap: round;
  opacity: 1;
}

.needle-body {
  fill: var(--brass); /* the eye is a real see-through cutout via fill-rule: evenodd */
}

/* .reveal is only ever added by script.js, and only when motion is allowed —
   so with JS disabled, or motion reduced, content simply never gets this
   class and stays at its normal opacity. CSS alone never hides content. */
.reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--duration-slow) var(--ease-standard),
              transform var(--duration-slow) var(--ease-standard);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}


/* ==========================================================================
   MEDIA QUERIES
   ========================================================================== */

/* The type and spacing scales above are fluid via clamp(), so no breakpoints
   are needed for sizing. Structural breakpoints (column/grid changes) arrive
   once individual sections are built. */

/* Below 640px, thread.js switches to a tighter weave confined to the left
   10%–20% of the viewport width (see buildPath()'s `narrow` branch) instead
   of swinging across the full width. The default --space-md gutter (~24px
   at 320px, ~7.5%) sits well inside that band, so body text would otherwise
   run directly under the thread. Widening the left inset here — without
   touching thread.js or any thread CSS value — reserves that band as a true
   margin. The right side keeps the normal gutter; the mobile thread never
   travels there. */
@media (max-width: 39.9375em) {
  section,
  .site-footer {
    padding-inline-start: max(25%, var(--space-md));
  }
}


/* ==========================================================================
   REDUCED MOTION
   ========================================================================== */

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

  body {
    opacity: 1;
    transition: none;
  }

  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .intro-overlay {
    display: none;
  }

  /* thread.js never calls placeNeedle() on this path, so the needle's
     transform is never set and it would otherwise sit at the SVG's raw
     origin — hiding it here is the only way to get "no needle" without
     touching thread.js. */
  .needle {
    display: none;
  }
}
