/* ==========================================================================
   Hiwa Saeed Yasin — BASE
   Reset, fonts, typography, and the handful of primitives every page uses.
   ========================================================================== */

/* ---- Fonts ----------------------------------------------------------------
   Self-hosted, never a Google Fonts <link>. The site has to work when it is
   opened straight off a USB stick with no internet, and a CDN stylesheet is
   the one thing that would stop it.

   If assets/fonts/ is empty the @font-face rules simply do not resolve and the
   fallbacks in tokens.css take over. That is a supported state, not a bug —
   see README.md for the four files and where to get them.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Karla";
  src: url("../fonts/karla-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Karla";
  src: url("../fonts/karla-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}


/* ---- Reset ---------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body,
h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol {
  margin: 0;
}

ul[role="list"], ol[role="list"] {
  list-style: none;
  padding: 0;
}

body {
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
}

/* The rule above is why this one has to exist and has to shout.
   [hidden] is set by the browser's own stylesheet, and an author rule beats a
   browser rule no matter how specific the browser's was. So "img { display:
   block }" silently un-hides every hidden image on the site — which showed up
   as a broken-image frame on exactly the products that have no photograph yet.
   This puts it back. */
[hidden] { display: none !important; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button { cursor: pointer; }

/* Wrapping rules that matter on a phone: an Erbil street address and a long
   product name both break badly at 360px without these. */
h1, h2, h3 { text-wrap: balance; }
p          { text-wrap: pretty; }


/* ---- Typography ----------------------------------------------------------- */

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-display);
  color: var(--fg);
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 {
  font-size: var(--fs-h3);
  letter-spacing: 0;
}

a {
  color: inherit;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 0.2em;
  transition: color var(--t-fast) var(--ease),
              text-decoration-color var(--t-fast) var(--ease);
}

a:hover { text-decoration-color: currentColor; }

strong, b { font-weight: 700; }

::selection {
  background: var(--brass);
  color: var(--espresso);
}


/* The small tracked-out label above a heading. It names the section; it never
   repeats the heading underneath it. */
.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--accent-text);
  margin-block-end: var(--s-3);
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--fg-soft);
  max-width: var(--measure);
}

/* Long-form body copy — About page, product descriptions. */
.prose {
  max-width: var(--measure);
  color: var(--fg-soft);
}
.prose > * + * { margin-block-start: var(--s-4); }
.prose h2 { margin-block-start: var(--s-7); color: var(--fg); }
.prose h3 { margin-block-start: var(--s-6); color: var(--fg); }
.prose strong { color: var(--fg); }

/* Reference codes: HSY-BLK-001. Monospace so a column of them lines up, and
   so a 0 can never be read as an O over WhatsApp. */
.code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  letter-spacing: var(--tracking-mono);
  font-variant-numeric: tabular-nums;
}


/* ---- Focus ----------------------------------------------------------------
   Applied on :focus-visible only, so a mouse click on a card does not leave a
   ring behind, but a Tab key always does.
   -------------------------------------------------------------------------- */

:focus { outline: none; }

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-md);
}


/* ---- Skip link ------------------------------------------------------------ */

.skip-link {
  position: absolute;
  inset-inline-start: var(--s-4);
  inset-block-start: -100%;
  z-index: var(--z-skip);
  padding: var(--s-3) var(--s-5);
  background: var(--espresso);
  color: var(--cream);
  font-size: var(--fs-small);
  font-weight: 700;
  text-decoration: none;
  border-radius: var(--r-md);
}

.skip-link:focus-visible { inset-block-start: var(--s-4); }


/* ---- Screen-reader only --------------------------------------------------- */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ---- .media ---------------------------------------------------------------
   The wrapper around every photograph on the site.

   A product with no photograph yet is a DESIGNED state, not a broken one. The
   wrapper always carries the woven-square watermark as a background, so when
   catalog.js leaves the <img> out the mark shows through at exactly the same
   size the photo would have been. No broken-image icon, no grey flash, and
   crucially no layout shift when the real photo is finally dropped in.
   -------------------------------------------------------------------------- */

.media {
  display: block;
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--ratio-product);
  background-color: var(--cream-sink);
  background-image: url("../img/brand/placeholder.svg");
  background-repeat: no-repeat;
  background-position: center;
  /* A fixed size, not a percentage. As a percentage the mark was enormous in
     the wide hero box and merely large in a card, and a page of products with
     no photographs yet read as a wall of symbols rather than as a shop
     waiting for its pictures. At 56px it is a watermark in every box on the
     site, whatever shape that box is. */
  background-size: 56px;
  border-radius: var(--r-md);
  /* A hairline rather than a border, so it costs no layout and sits over a
     photograph as a crisp edge. It also has to be here: the empty state is
     tinted --cream-sink, and on a --band--sink section that is the same colour
     as the page, so without this the frame vanished and a card with no photo
     read as a watermark floating in mid-air. */
  box-shadow: inset 0 0 0 1px var(--rule);
}

.media--wide { aspect-ratio: var(--ratio-wide); }

/* PRODUCT PHOTOGRAPHS ARE NEVER CROPPED.

   contain, not cover: the whole photograph is always shown, scaled down until
   it fits inside the frame. Whatever shape it is — portrait, landscape,
   square, straight off a phone — nothing is cut off.

   The frames all stay the same size, so the grid stays a tidy grid; a photo
   that is not 4:5 simply sits inside its frame with a little clean space above
   and below, or at the sides. That space is why .has-photo below repaints the
   background: the woven watermark would otherwise show through it. */
.media > img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform var(--t-slow) var(--ease-out);
}

/* THE PHOTOGRAPH FITS ITS FRAME EXACTLY.

   Nothing cropped and no empty space around it. Those two things together can
   only be true if the frame takes the shape of the photograph rather than the
   other way round — so once a real photo arrives the fixed 4:5 is dropped and
   the frame becomes whatever shape that photo is.

   The 4:5 above is still doing a job: it is the shape of the EMPTY frame, so
   a catalogue with no photographs yet is still an even grid.

   The trade-off, and it is worth knowing before you shoot: photographs of
   different shapes make cards of different heights, so the rows will not line
   up. Crop everything to the same shape and you get both an exact fit and a
   perfectly even grid. 4:5 upright is the shape this site is built around.

   .has-photo is added by ui.js as the photo goes in, and taken away again by
   boot.js if the file turns out to be missing. */
.media.has-photo {
  background-image: none;
  background-color: transparent;
}

.media.has-photo:not(.media--cover) { aspect-ratio: auto; }

.media.has-photo:not(.media--cover) > img {
  height: auto;
  object-fit: fill;   /* nothing to fit: the box is now the picture's own shape */
}

/* OPT-IN: crop this one to fill its frame instead.

   Nothing on the site uses this by default — the hero and the category tiles
   fit their photographs exactly like everything else. It is here for the case
   where a particular picture has to hold an exact shape: a tile that must
   line up with its neighbours, or a hero that must not go tall on a phone.
   Add media--cover to that one .media and it fills and crops; data-focus then
   says which edge of the picture to keep. */
.media--cover > img { object-fit: cover; }

.media--cover > img[data-focus="top"]    { object-position: 50% 0%; }
.media--cover > img[data-focus="bottom"] { object-position: 50% 100%; }
.media--cover > img[data-focus="left"]   { object-position: 0% 50%; }
.media--cover > img[data-focus="right"]  { object-position: 100% 50%; }

/* Written by boot.js when a photograph 404s, so a wrong filename is visible
   on the page rather than only in the console. */
.media__pending {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  padding: var(--s-2) var(--s-3);
  background: rgba(42, 33, 28, 0.72);
  color: var(--cream);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  text-align: center;
}


/* ---- Woven texture --------------------------------------------------------
   A warp-and-weft grid at very low contrast. It is the one piece of ornament
   on the site and it is the subject itself: this is what a plain weave looks
   like from very close up. Used only on espresso bands, where it reads as
   cloth catching the light rather than as a pattern.
   -------------------------------------------------------------------------- */

.weave { position: relative; isolation: isolate; }

.weave::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg,
      rgba(176, 133, 66, 0.07) 0 1px,
      transparent 1px 7px),
    repeating-linear-gradient(0deg,
      rgba(250, 246, 240, 0.05) 0 1px,
      transparent 1px 7px);
}


/* ---- Scroll reveal --------------------------------------------------------
   .reveal is VISIBLE by default. ui.js only ever adds the hide-then-animate
   behaviour, and only when IntersectionObserver exists and motion is welcome.
   A JavaScript failure therefore leaves a fully readable page, never a blank
   one — which is the whole reason the default is this way round.
   -------------------------------------------------------------------------- */

.reveal { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  html.is-loaded .reveal[data-observed] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--t-slow) var(--ease-out),
                transform var(--t-slow) var(--ease-out);
    /* Set by ui.js from the element's position in its grid, so a row of cards
       arrives as a ripple from left to right rather than as one block. The
       delay is capped there — a twelve-card grid must not take a second and a
       half to finish appearing. */
    transition-delay: var(--reveal-delay, 0ms);
  }
  html.is-loaded .reveal[data-observed].is-in {
    opacity: 1;
    transform: none;
  }
}


/* ---- Keyframes ------------------------------------------------------------
   Two, used everywhere. Anything that needs a third is probably decoration
   that should be cut instead.
   -------------------------------------------------------------------------- */

@keyframes rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* draw-thread animated the warmth scale's threads. Kept because it costs
   nothing and reads as part of the loom idea; nothing uses it today. */
@keyframes draw-thread {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

@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;
  }
}
