/* Piala — woven menu
   Tokens first. Everything downstream reads from these, so a brand correction
   is a one-line edit here. */

:root {
  /* ── The palette ────────────────────────────────────────────────────────
     Piala's five named inks, at the values printed on the identity spec
     (`piala-presentation 13.jpeg`). These are measured, not sampled — do not
     eyeball a replacement.

       شاي داكن     dark tea     #4A120C   --ink-deep
       خمري داكن    dark wine    #642524   --ink
       أحمر قرميدي  brick red    #912E20   --terracotta
       شاي بحليب    tea w/ milk  #EAD1A7   --cream
       نومي حامض    dried lime   #D17441   --noomi

     Each colour that needs an alpha elsewhere also carries a channel triple,
     so a scrim or a rule can take transparency without restating the value.
     That is what keeps a palette move a one-line edit. */
  --cream:          #EAD1A7;
  --cream-rgb:      234 209 167;
  --cream-lift:     #F3E5CC;   /* the ground lifted 42% toward white */
  --cream-lift-rgb: 243 229 204;

  --ink:            #642524;
  --ink-rgb:        100 37 36;
  --ink-deep:       #4A120C;
  --ink-deep-rgb:   74 18 12;
  --ink-soft:       #7A3934;   /* 5.8:1 on cream — secondary text, never grey */
  --terracotta:     #912E20;
  --noomi:          #D17441;   /* 2.3:1 on cream: accent only, never text */

  /* the seven square dots in the wordmark; the SVG reads this by name */
  --logo-dot:       var(--terracotta);

  --rule:         rgb(var(--ink-rgb) / 0.22);
  --rule-faint:   rgb(var(--ink-rgb) / 0.12);

  /* Type */
  --la:  'Jost', system-ui, sans-serif;
  --ar:  'Tajawal', system-ui, sans-serif;
  --cal: 'Aref Ruqaa', 'Tajawal', serif;

  /* Rhythm */
  --gut: clamp(1.25rem, 4.5vw, 3.5rem);
  --stack: clamp(3.5rem, 9vh, 6.5rem);
}

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

html {
  background: var(--cream);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--ar);
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.125rem);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Browser surfaces belong to the design too. */
::selection { background: var(--ink); color: var(--cream); }
:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 3px;
  border-radius: 2px;
}
html { scrollbar-color: var(--ink-soft) var(--cream); scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--cream); }
::-webkit-scrollbar-thumb {
  background: var(--ink-soft);
  border: 3px solid var(--cream);
  border-radius: 99px;
}

.skip {
  position: absolute;
  inset-inline-start: -9999px;
  top: 0;
  z-index: 50;
  padding: 0.75rem 1.25rem;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--ar);
  text-decoration: none;
}
.skip:focus { inset-inline-start: 0; }

/* ───────────────────────────── hero: the loom ───────────────────────────── */

.hero {
  position: relative;
  height: 260vh;                 /* scroll runway for the pull-back */
  background: var(--cream);
}

.hero__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: grid;
  place-items: center;
}

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Directional scrim, heaviest where the wordmark sits. Keeps the calligraphy
   legible over the densest part of the weave without a backing panel. */
.hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 48% 30% at 50% 47%,
      rgb(var(--cream-rgb) / 0.72) 0%,
      rgb(var(--cream-rgb) / 0.34) 46%,
      rgb(var(--cream-rgb) / 0) 78%),
    linear-gradient(to bottom,
      rgb(var(--cream-rgb) / 0.34) 0%,
      rgb(var(--cream-rgb) / 0) 24%,
      rgb(var(--cream-rgb) / 0) 76%,
      rgb(var(--cream-rgb) / 0.88) 100%);
}

.hero__mark {
  position: relative;
  z-index: 2;
  text-align: center;
  will-change: transform, opacity;
  transform: scale(var(--mark-scale, 1));
  opacity: var(--mark-opacity, 1);
}

/* a quiet field the wordmark can sit in, tight to the lettering rather than a
   panel — the dot grid keeps running underneath it */
.hero__mark::before {
  content: "";
  position: absolute;
  inset: -30% -18%;
  z-index: -1;
  background: radial-gradient(ellipse 46% 46% at 50% 54%,
    rgb(var(--cream-lift-rgb) / 0.97) 0%,
    rgb(var(--cream-lift-rgb) / 0.93) 38%,
    rgb(var(--cream-lift-rgb) / 0.6) 66%,
    rgb(var(--cream-rgb) / 0) 100%);
}

.wordmark {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: clamp(0.5rem, 1.4vh, 1rem);
}

/* The logotype is artwork, not type: font-size survives only as the unit the
   logo is measured in, so the mark keeps the wordmark's responsive curve. */
.wordmark__ar {
  font-size: clamp(5.5rem, 26vw, 15rem);
  line-height: 0;
  color: var(--ink-deep);
}

.wordmark__ar > svg {
  display: block;
  width: 1.85em;
  max-width: 84vw;
  height: auto;
  margin-inline: auto;
}

/* Fallback only — used if the traced logotype is ever swapped back out for
   live text. Kept so the hero still holds without the SVG. */
.wordmark__ar:not(:has(> svg)) {
  font-family: var(--cal);
  font-weight: 700;
  line-height: 0.86;
  letter-spacing: 0;
  text-shadow: 0 1px 0 rgb(var(--cream-lift-rgb) / 0.55);
}

.wordmark__la {
  font-family: var(--la);
  font-weight: 400;
  font-size: clamp(0.8125rem, 2.1vw, 1.125rem);
  letter-spacing: 0.58em;
  text-indent: 0.58em;         /* balances the trailing tracking */
  text-transform: lowercase;
  color: var(--ink);
}

.hero__cue {
  position: absolute;
  z-index: 2;
  bottom: max(1.75rem, env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 0.7rem;
  opacity: var(--cue-opacity, 1);
}
/* Hinted only while the cue is actually fading. A permanent will-change holds a
   compositor layer for the life of the page, which on a tablet that sits on the
   bar all day is a layer nobody ever looks at again. */
.hero__cue:not(.is-spent) { will-change: opacity; }

/* the cue lands wherever the weave happens to be dense, so it carries its own
   quiet field — the same device the wordmark uses, at cue scale */
.hero__cue::before {
  content: "";
  position: absolute;
  inset: -55% -180%;
  z-index: -1;
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    rgb(var(--cream-rgb) / 0.95) 0%,
    rgb(var(--cream-rgb) / 0.78) 45%,
    rgb(var(--cream-rgb) / 0) 100%);
}

.hero__cue-text {
  font-family: var(--ar);
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  color: var(--ink-soft);
}

.hero__cue-rule {
  width: 2px;
  height: 46px;
  overflow: visible;
}
.hero__cue-rule line {
  stroke: var(--ink-soft);
  stroke-width: 1.4;
  stroke-dasharray: 3 7;
  stroke-linecap: round;
  animation: thread 2.4s cubic-bezier(0.22, 1, 0.36, 1) infinite;
}
/* The dashed thread is the only endless animation on this page. Fading the cue
   out does not stop it — it would keep ticking behind opacity 0 for a whole
   trading day — so it is paused outright the moment the cue is spent. */
.hero__cue.is-spent .hero__cue-rule line { animation-play-state: paused; }
@keyframes thread {
  0%   { stroke-dashoffset: 0;   opacity: 0.25; }
  45%  { opacity: 0.95; }
  100% { stroke-dashoffset: -40; opacity: 0.2; }
}

/* ──────────────────────────── sheet: the menu ──────────────────────────── */

.sheet {
  position: relative;
  z-index: 3;
  background: var(--cream);
  padding-bottom: 0;
  /* the sheet lifts off the carpet as it arrives */
  box-shadow: 0 -28px 60px -30px rgb(var(--ink-deep-rgb) / 0.45);
}

.sheet__seam {
  display: grid;
  place-items: center;
  padding-block: clamp(2.25rem, 5vh, 3.5rem) 0;
  color: var(--ink);
}

.rosette {
  width: clamp(30px, 4.5vw, 42px);
  height: auto;
  opacity: 0.7;
}

.sheet__head {
  padding-inline: var(--gut);
  padding-block: clamp(1.5rem, 4vh, 2.5rem) var(--stack);
  text-align: center;
  /* The head is a pair now: the pourer, then the title he pours toward. Centred
     as a unit rather than each half centred on its own, so the composition reads
     as one object and the stream lands on the words. */
  display: flex;
  align-items: center;
  justify-content: center;
  /* The floor matters more than the ceiling here: the pair only exists above
     30rem, and at the bottom of that range 3vw put just 15px between the note
     and the figure, so the Arabic ran into the pourer. A 1.25rem floor keeps
     them two objects instead of one crowded one. */
  gap: clamp(1.25rem, 4vw, 2.5rem);
}
.sheet__head-text { flex: 0 1 auto; }

.sheet__title {
  margin: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
}
.sheet__title-ar {
  font-family: var(--cal);
  font-weight: 700;
  font-size: clamp(2.5rem, 7vw, 4.5rem);
  line-height: 1;
  color: var(--ink-deep);
}

.sheet__note {
  margin: 1.25rem auto 0;
  max-width: 44ch;
  font-size: 0.9375rem;
  color: var(--ink-soft);
  line-height: 1.7;
}

.sheet__grid {
  padding-inline: var(--gut);
  display: grid;
  gap: var(--stack) clamp(2.5rem, 7vw, 6rem);
  max-width: 78rem;
  margin-inline: auto;
}

/* a tablet standing on the bar is the likeliest screen here, so it earns two
   columns rather than a single sparse ribbon the guest has to scroll */
@media (min-width: 46rem) {
  .sheet__grid { grid-template-columns: 1fr 1fr; }
}

/* قهوة is shorter than شاي beside it, so آيس تي rides in the same cell under it
   instead of opening a row of its own — the gap beside شاي fills, and the small
   courses below come out even. Same row gap as .sheet__minor. */
.sheet__stack {
  display: grid;
  align-content: start;
  gap: clamp(2.25rem, 5vh, 3.25rem);
}

/* The four small courses share one cell spanning both columns, as a grid of
   their own: same column split and column gap as the sheet, so they sit under
   قهوة and شاي exactly, but a tighter row gap — the full --stack between two
   three-line courses read as the menu having ended. */
.sheet__minor {
  display: grid;
  gap: clamp(2.25rem, 5vh, 3.25rem) clamp(2.5rem, 7vw, 6rem);
}
@media (min-width: 46rem) {
  .sheet__minor { grid-column: 1 / -1; grid-template-columns: 1fr 1fr; }
}

/* Below this the title and the figure are fighting over the same line, and the
   Arabic is what gives way first. Stack them instead — the figure keeps its
   place at the head, just above the words rather than beside them. */
@media (max-width: 30rem) {
  .sheet__head { flex-direction: column; gap: clamp(0.75rem, 3vw, 1.25rem); }
}

/* ── course ── */

.course {
  /* one authored move, played forwards on the way down the page and
     backwards on the way up — see the observer in dither.js */
  transition:
    opacity 900ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* The menu is visible by default and only agrees to hide itself once the script
   that reveals it is running — see the `js-reveal` gate in dither.js. A script
   that never arrives, on a bar's wifi, must cost this page its animation and
   never its content. */
.js-reveal .course { opacity: 0; transform: translateY(18px); }
.js-reveal .course.is-woven { opacity: 1; transform: none; }

.course__title {
  margin: 0 0 clamp(1.5rem, 3.5vh, 2.25rem);
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;              /* the mark drops below rather than off the edge */
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.course__ar {
  font-family: var(--cal);
  font-weight: 700;
  font-size: clamp(1.75rem, 4.4vw, 2.5rem);
  line-height: 1;
  color: var(--ink-deep);
}

/* Category marks. The brand's pencil elements arrive as grey artwork, which this
   palette has no room for, so each one ships as an alpha mask and is painted with
   the page's own ink — the shading survives, the grey does not, and they follow
   the token if the palette moves.

   Sized by area rather than height: these range from a wide portafilter (3:1) to a
   square jug, and matching their heights alone would let the wide one dominate the row. */
.course__mark { display: none; }

@supports ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .course__mark {
    display: block;
    flex: none;
    align-self: center;
    height: calc(clamp(2.1rem, 5vw, 2.8rem) * var(--mark-h, 1));
    aspect-ratio: var(--mark-ar, 1);
    background-color: var(--ink);
    opacity: 0.88;
    -webkit-mask: var(--mark) center / contain no-repeat;
    mask: var(--mark) center / contain no-repeat;
    /* The gloss used to hold the far end of the rule and an auto margin here
       pushed it there. With the menu Arabic-only the mark inherits that end
       itself, via the title's space-between — the rule stays anchored at both
       ends instead of trailing off empty. */
  }
}

.course__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.1rem, 2.4vh, 1.6rem);
}

.item {
  display: flex;
  align-items: baseline;
  /* A row that cannot fit its name, leader and price on one line drops the
     price to a second line rather than pushing it out of the row. Without this
     the flex default of min-width:auto holds the name at its content width, the
     price is forced past the inline edge, and `overflow-x: hidden` on the body
     clips it away — at 200% text every price on the menu vanished. */
  flex-wrap: wrap;
  column-gap: 0.75rem;
  row-gap: 0.15rem;
  /* Staggered inside the course's entrance. The delay lives on the woven
     state, not here, so it applies only on the way in: leaving, the rows go at
     once. A staggered exit reads as lag, because the course is already past the
     edge of the screen by the time the last row starts to fade. */
  transition:
    opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: 0s;
}
.js-reveal .item { opacity: 0; transform: translateY(10px); }
.js-reveal .item.is-woven {
  opacity: 1;
  transform: none;
  /* A light stagger still, for the case where several rows cross the edge in the
     same frame — a course that arrives whole on a tall screen. Where they cross
     one at a time the reader's own scrolling is already the stagger, so this is
     kept short: at 55ms plus a base delay a row entering alone read as lag. */
  transition-delay: calc(var(--i, 0) * 40ms);
}

/* min-width:0 is what lets a long Arabic name shrink and wrap; a flex item
   defaults to min-width:auto and refuses to go below its own content. */
.item__name { display: grid; min-width: 0; }
/* sized to be read from across the counter, not from a phone in the hand */
.item__ar {
  font-family: var(--ar);
  font-weight: 500;
  font-size: clamp(1.1875rem, 2.6vw, 1.5rem);
  line-height: 1.25;
  color: var(--ink);
}

/* The options a drink comes in — the flavours, the spice, with or without.
   It is the row's last flex child at full basis, so it always takes a line of
   its own under the name, leader and price. It must not live inside
   .item__name: there its width set the name's, and a long note (لاتيه's four
   syrups) pushed the price off the name line on a portrait tablet. */
.item__note {
  flex-basis: 100%;
  font-family: var(--ar);
  font-weight: 400;
  font-size: clamp(0.9375rem, 1.9vw, 1.0625rem);
  line-height: 1.5;
  color: var(--ink-soft);
  margin-top: 0.15rem;
}

/* A price that is quoted, not printed — the V60 is priced by the crop. Arabic
   words, so the Arabic face and the quieter ink of the currency mark: it stands
   where a number would and should not shout louder than one. */
.item__price.item__price--ask {   /* doubled: .item__price is declared later at equal weight */
  font-family: var(--ar);
  font-size: clamp(0.9375rem, 1.9vw, 1.0625rem);
  letter-spacing: 0;
  color: var(--ink-soft);
}

/* The small courses: two or three drinks each, so a full-size title and mark
   would outweigh the list they head. Both step down; the rule and rhythm stay.
   Their marks are drawn SVG rather than the scanned pencil of the big four, so
   they carry their own tone as alpha and are painted with the same ink. */
.course--small .course__title { margin-bottom: clamp(1rem, 2.4vh, 1.5rem); padding-bottom: 0.7rem; }
.course--small .course__ar { font-size: clamp(1.4rem, 3.4vw, 1.9rem); }
.course--small .course__mark { height: calc(clamp(1.9rem, 4.4vw, 2.5rem) * var(--mark-h, 1)); }

/* the leader is the weave again, at reading scale */
.item__lead {
  flex: 1 1 auto;
  align-self: baseline;
  height: 3px;
  min-width: 1.5rem;
  transform: translateY(-0.28em);
  background-image: radial-gradient(circle at 1.5px 1.5px, var(--rule) 1.5px, transparent 1.6px);
  background-size: 9px 3px;
  background-repeat: repeat-x;
}

/* The currency. The bilingual note used to carry it ("Prices in IQD") and the
   Arabic note still says الأسعار بالدينار العراقي, but a reader who has neither
   language was left with a bare 2,000 — so the price now says which money it is.
   Arabic script, so it takes the Arabic face; Jost has no د.ع. Set quieter than
   the numeral it qualifies: the number is the information, the mark only names
   the unit. Bidi lays it to the left of the digits inside this RTL row, which is
   the order Arabic writes a price in. It sits inside .item__price, so nowrap
   keeps the two together and the pair drops to its own line as one. */
.item__cur {
  font-family: var(--ar);
  font-weight: 500;
  font-size: 0.8em;
  color: var(--ink-soft);
}

.item__price {
  font-family: var(--la);
  font-weight: 400;
  font-size: clamp(1rem, 2.1vw, 1.1875rem);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.02em;
  color: var(--ink-deep);
  white-space: nowrap;
  /* holds the end of the row, and the end of its own line once it wraps */
  margin-inline-start: auto;
}

/* ── the pour ──
   Piala's own line drawing of the dallah, brought in exactly the way every other
   piece of artwork in this system arrives: darkness carried as alpha, painted
   with the page's ink. The source is a sticker on a brown ground with a die-cut
   border and a drop shadow — none of which this palette has room for — so the
   matte is cut from the artwork itself and the ground, border and shadow never
   reach the page. The figure re-tints itself if the palette moves.

   Its 48 frames live in one 8x6 sheet. `mask-size: 800% 600%` makes a single
   cell exactly the size of the element, so advancing a frame is nothing but a
   mask-position — no canvas, no compositing work, and the sheet decodes once.
   That is the hero's idea at the scale of a single mark. */
.pour { display: none; }

@supports ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .pour {
    display: block;
    /* Sized against the head it shares, not the viewport it sits in: big enough
       to be the first thing seen on entering the menu, small enough that the
       title still leads. The floor keeps it present on a phone without pushing
       the first course below the fold. */
    width: clamp(7rem, 26vw, 20rem);
    flex: 0 0 auto;
    aspect-ratio: 481 / 561;      /* the artwork's own bounds, not the video's */
    background-color: var(--ink);
    opacity: 0.9;
    -webkit-mask-image: url(assets/pour.webp);
            mask-image: url(assets/pour.webp);
    -webkit-mask-size: 800% 600%;
            mask-size: 800% 600%;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    /* frame 0 until the script steps it, so a failed script leaves the drawing
       whole rather than blank */
    -webkit-mask-position: var(--pour-x, 0%) var(--pour-y, 0%);
            mask-position: var(--pour-x, 0%) var(--pour-y, 0%);
  }
}

/* ── close ── */

.close {
  margin-top: var(--stack);
  position: relative;
}

.close__band {
  display: block;
  width: 100%;
  height: clamp(88px, 13vh, 132px);
}

.close__handle {
  margin: 0;
  padding-block: clamp(1.5rem, 4vh, 2.25rem) max(1.5rem, env(safe-area-inset-bottom));
  text-align: center;
  font-family: var(--la);
  font-weight: 300;
  font-size: 0.8125rem;
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  color: var(--ink-soft);
}
/* The handle is one of the three ways guests reach this menu, so it is a place
   you can go rather than a string you have to retype. Padding carries the tap
   target past 44px; the matching negative margin keeps the foot's rhythm. */
.close__link {
  display: inline-block;
  color: inherit;
  text-decoration: none;
  padding: 0.9rem 1.1rem;
  margin: -0.9rem -1.1rem;
  transition: color 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.close__link:hover { color: var(--ink); }

/* ─────────────────────────────── reduced motion ─────────────────────────── */

/* Reduced motion asks for fewer and gentler animations, not for none. The rise
   is the part that can unsettle; the fade is not, and it is what tells a reader
   the course has arrived. So the travel goes and the fade stays, unstaggered. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero { height: 100svh; }
  .hero__mark { transform: none; opacity: 1; }
  .js-reveal .course, .js-reveal .item { transform: none; }
  .course, .item { transition: opacity 320ms ease; }
  /* The row stagger is set at (0,3,0) on the woven state, so the shorthand above
     cannot reset its delay — it loses on specificity and the cascade survives
     into reduced motion, where the whole point is that rows do not arrive in
     sequence. Restate it at matching weight. */
  .js-reveal .item.is-woven { transition-delay: 0s; }
  /* The cue keeps its words. Hiding it here removed the only thing telling a
     reader the menu is below a hero that fills the screen — and the rule under
     it already stops the animation, so hiding bought no reduction at all. */
  .hero__cue-rule line { animation: none; }
  .hero__cue { will-change: auto; }
}

/* No JS, or dither.js failed to load (index.html adds .no-js on error): the canvas
   never paints, so the hero must still hold on its own. The class is never set
   speculatively and cleared later — that flip moved the whole sheet. */
.no-js .hero { height: 100svh; }
.no-js .hero__cue { display: none; }
