/* ============================================================================
   E-Menu design system.

   This file is the whole visual language of the customer-facing menu, and it
   is deliberately shared with nothing: the dashboard's stylesheets, the legacy
   qr-menu layouts (assets/css/menu-style.css) and Bootstrap are all absent
   here. Editing this file cannot reach any other screen in the application,
   and no other stylesheet can reach the menu.

   Structure:
     1. @font-face      - Alexandria, self-hosted
     2. :root           - design tokens (light)
     3. dark theme      - structural tokens only; brand colors do not flip
     4. base            - reset and typography
     5. components      - the menu's visual language

   The nine tokens the merchant configures carry defaults here, so the menu
   renders correctly with no theme row at all. The page then overrides only
   what the merchant actually set, in a small <style> block the head partial
   prints.

   A component rule derives its colors from a token; a literal hex in one is
   a bug, because the dark theme and the merchant's palette both stop
   reaching it. There are exactly two deliberate exceptions, and both are
   surfaces that must look the same in either theme: the out-of-stock badge
   (a fixed neutral, since a merchant whose brand is grey still needs it to
   read as disabled) and the toast, which is dark in both themes and so
   carries the brighter on-dark variants of the status colors rather than the
   --em-success / --em-danger / --em-warning meant for light surfaces.
   ========================================================================= */

/* ---------- 1. Font ---------------------------------------------------- */
/* Self-hosted rather than Google Fonts: ad blockers and stricter CSP policies
   drop the Google request, and the menu then renders in a system serif
   mid-paint. Split by unicode-range so a Latin page never downloads the
   Arabic subset and vice versa. */
@font-face {
    font-family: 'Alexandria';
    src: url('../fonts/alexandria/alexandria-arabic.woff2') format('woff2');
    font-weight: 400 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-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;
}

@font-face {
    font-family: 'Alexandria';
    src: url('../fonts/alexandria/alexandria-latin.woff2') format('woff2');
    font-weight: 400 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+20AC, U+2122;
}

/* ---------- 2. Tokens -------------------------------------------------- */
:root {
    /* Merchant-configurable. The head partial overrides these per tenant. */
    --em-primary: #e0562c;
    --em-secondary: #1c1a2e;
    --em-accent: #f5a623;
    --em-bg: #faf9f7;
    --em-text: #1c1a2e;
    --em-footer: #1c1a2e;
    --em-card-radius: 18px;
    --em-btn-radius: 99px;
    /* The fallback chain covers Arabic and Latin on every major OS, so text
       never lands in an unstyled serif if the webfont fails. */
    --em-font: 'Alexandria', 'Segoe UI', Tahoma, system-ui, sans-serif;

    /* Derived surfaces. Everything traces back to the tokens above. */
    --em-surface: #fff;
    --em-surface-2: color-mix(in srgb, var(--em-bg) 92%, var(--em-text) 8%);
    --em-border: color-mix(in srgb, var(--em-text) 10%, transparent);
    --em-muted: color-mix(in srgb, var(--em-text) 55%, transparent);
    --em-primary-weak: color-mix(in srgb, var(--em-primary) 12%, white);
    --em-shadow: 0 2px 8px rgba(20, 20, 30, .04), 0 16px 40px -20px rgba(20, 20, 30, .18);
    --em-shadow-lg: 0 24px 64px -24px rgba(20, 20, 30, .28);

    /* Type scale */
    --em-text-xs: 11.2px;
    --em-text-sm: 12.6px;
    --em-text-base: 14px;
    --em-text-lg: 15.8px;
    --em-text-xl: 18.6px;
    --em-text-2xl: clamp(20.5px, 2.8vw, 26px);
    --em-text-3xl: clamp(26px, 4.2vw, 35.3px);
    --em-text-4xl: clamp(29.8px, 5.6vw, 48.4px);
    --em-lh-tight: 1.2;
    --em-lh-normal: 1.5;
    --em-lh-relaxed: 1.7;
    --em-tracking-tight: -0.02em;

    /* Status colors are fixed constants, not brand colors: a merchant whose
       primary is green must still get a red "out of stock" badge. */
    --em-success: #1f9d57;
    --em-success-weak: #e3f5ec;
    --em-danger: #e0392c;
    --em-danger-weak: #fde5e2;
    --em-warning: #9a6b10;
    --em-warning-weak: #fdf0d5;
    --em-info: #6d34d6;
    --em-info-weak: #e9e6fc;
    --em-star: #e0a020;

    /* Spacing scale */
    --em-space-1: 4px;
    --em-space-2: 8px;
    --em-space-3: 12px;
    --em-space-4: 16px;
    --em-space-5: 24px;
    --em-space-6: 32px;
}

/* ---------- 3. Dark theme ---------------------------------------------- */
/* Only the structural surface and text tokens flip. The merchant's primary,
   secondary, accent and footer colors are identical in both themes, so their
   palette still reads as their own brand at night rather than being replaced
   by a generic dark scheme. Switched by data-theme="dark" on <html>, which
   the head partial sets before first paint so there is no flash. */
:root[data-theme="dark"] {
    --em-bg: #15131c;
    --em-text: #f1eef6;
    --em-surface: #201d29;
    --em-surface-2: color-mix(in srgb, var(--em-bg) 80%, #fff 20%);
    --em-border: color-mix(in srgb, #fff 12%, transparent);
    --em-muted: color-mix(in srgb, #fff 58%, transparent);
    --em-primary-weak: color-mix(in srgb, var(--em-primary) 22%, var(--em-surface));
    --em-shadow: 0 2px 8px rgba(0, 0, 0, .25), 0 16px 40px -20px rgba(0, 0, 0, .55);
    --em-shadow-lg: 0 24px 64px -24px rgba(0, 0, 0, .7);
}

/* The shop name in the navbar is painted in the merchant's secondary colour,
   and secondary does not flip between themes - which on the dark navbar left
   it as near-black text on a near-black bar, invisible. Brand colours staying
   fixed is the right rule; a brand colour used as *text on a surface* is the
   exception to it, so here it falls back to the theme's text colour. */
:root[data-theme="dark"] .em-brand {
    color: var(--em-text);
}

/* The currency symbol is an image, not a character: `settings.currency_sample_ar`
   holds a file and every screen in the application prints it as
   <img src="storage/...">. The glyphs shipped per country are drawn with
   fill="currentColor", and inside an <img> that resolves against the image's own
   document rather than the page - always black - so at night the price ended in a
   smudge nobody could read.

   brightness(0) flattens whatever was uploaded to black, invert(1) turns it white:
   a silhouette that matches the text beside it. A merchant whose currency mark is
   coloured loses those colours on the dark theme only, which is the same trade the
   brand colour above makes, and for the same reason. */
:root[data-theme="dark"] .em-currency img {
    filter: brightness(0) invert(1);
}

/* والرمز جزءٌ من السطر لا سطرٌ بذاته.
 *
 * الإعادة العامة أسفل هذا الملف تجعل كل صورة `display:block` - وهي صحيحة للصور
 * التي تملأ حاويتها - فكان رمز العملة يكسر السطر وينزل تحت السعر. والأسوأ أنه
 * ينزل بعرض الكتلة كلها: الكتلة عنصرٌ مرن يتقاس بأوسع سطرٍ فيه، ولما صار الرقم
 * والرمز سطرين صار عرضها عرض الرقم وحده - فبدا السعر رقمًا يتيمًا ورمزًا معلقًا
 * تحته في بطاقة عرضها مئتا بكسل.
 *
 * التصميم المنقول لم يقع في هذا لأن عملته نصٌّ يُطبع مع السعر، أما هنا فالعملة
 * صورةٌ يرفعها التاجر - ومن ثمَّ فالإعادة العامة تنطبق عليها. */
.em-currency img {
    display: inline-block;
    vertical-align: -3px;
}

/* ---------- 4. Base ---------------------------------------------------- */
/* Direction is set on <html>. Component rules use logical properties
   (margin-inline, inset-inline, border-inline-end) and never left/right, so
   the Arabic layout does not break when a merchant switches language. */
* {
    box-sizing: border-box;
}

html{scroll-behavior:smooth}
body{
    margin:0; font-family:var(--em-font); background:var(--em-bg); color:var(--em-text);
    -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
    font-size:var(--em-text-base); line-height:var(--em-lh-relaxed);
    /* Sticky footer: on short pages (Offers/Branches with few items) the
       footer must stay pinned to the viewport bottom instead of riding up
       right under a half-empty page. `main` absorbs all the extra space. */
    display:flex; flex-direction:column; min-height:100vh;
}
main{ flex:1 0 auto }
.em-footer{ flex-shrink:0 }
@media (max-width:899px){
    body{ padding-bottom:calc(78px + env(safe-area-inset-bottom)); } /* room for the floating mobile bottom bar */
}
img{max-width:100%; display:block}
a{color:inherit; text-decoration:none}
/* `background:none` and `border:0` are not cosmetic here. A <button> with no
   background of its own falls back to the UA's `buttonface`, a light grey
   that does not follow the theme - so a button styled only by a class that
   forgets a background renders light-grey-on-near-white text in dark mode and
   is unreadable. Resetting it at the base means every button starts from
   nothing and shows exactly what its own class gives it.
   `color:inherit` matters for the same reason: browsers do not inherit text
   colour into a button, so anything nested inside one - a branch card's title,
   for instance, since those cards are buttons - keeps a fixed near-black
   regardless of theme. */
button{font-family:inherit; cursor:pointer; color:inherit; background:none; border:0}
input, textarea, select{
    font-family:inherit; background:var(--em-surface); color:var(--em-text);
    accent-color:var(--em-primary); border-color:var(--em-border);
}
input::placeholder, textarea::placeholder{ color:var(--em-muted); opacity:1 }
::selection{background:var(--em-primary-weak)}

h1,h2,h3,h4{ font-family:var(--em-font); font-weight:800; line-height:var(--em-lh-tight); letter-spacing:var(--em-tracking-tight); margin:0 }
p{ line-height:var(--em-lh-relaxed) }
:focus-visible{ outline:2px solid var(--em-primary); outline-offset:2px; border-radius:6px }

.em-container{max-width:1180px; margin-inline:auto; padding-inline:18px}
@media (min-width:768px){ .em-container{padding-inline:32px} }

/* ---------- 5. Components ---------------------------------------------- */
/* Everything below is the menu's visual language. No rule here may hardcode
   a colour: derive from a token, or the dark theme and the merchant's
   palette both stop applying to it. */

/* ---------- Navbar ---------- */
.em-nav{
    position:sticky; top:0; z-index:60; background:color-mix(in srgb, var(--em-surface) 72%, transparent);
    backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
    border-bottom:1px solid var(--em-border); transition:box-shadow .2s;
}
.em-nav.scrolled{ box-shadow:0 6px 24px -12px rgba(20,20,30,.15) }
.em-nav-inner{display:flex; align-items:center; justify-content:space-between; height:68px}
.em-brand{display:flex; align-items:center; gap:10px; font-weight:800; font-size:17.7px; color:var(--em-secondary)}
.em-brand img{height:36px; width:36px; border-radius:10px; object-fit:cover}
.em-brand .dot{width:36px; height:36px; border-radius:10px; background:linear-gradient(135deg, var(--em-primary), var(--em-accent))}
.em-nav-links{display:none; align-items:center; gap:28px; font-weight:700; font-size:13.5px; color:var(--em-muted)}
.em-nav-links a:hover{color:var(--em-primary)}
@media (min-width:900px){ .em-nav-links{display:flex} }
.em-nav-actions{display:flex; align-items:center; gap:10px}
.em-theme-icon-sun{ display:none }
.em-theme-icon-moon{ display:block }
[data-theme="dark"] .em-theme-icon-sun{ display:block }
[data-theme="dark"] .em-theme-icon-moon{ display:none }

/* ---------- Buttons ---------- */
.em-btn{
    display:inline-flex; align-items:center; justify-content:center; gap:8px;
    padding:12px 22px; border-radius:var(--em-btn-radius); border:1px solid var(--em-border);
    background:var(--em-surface); color:var(--em-text); font-weight:700; font-size:var(--em-text-sm);
    transition:transform .15s ease, box-shadow .15s ease, background .15s ease; white-space:nowrap;
}
.em-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 20px -10px rgba(20,20,30,.25) }
.em-btn:active{ transform:translateY(0) scale(.98) }
.em-btn-primary{
    background:linear-gradient(135deg, var(--em-primary), color-mix(in srgb, var(--em-primary) 70%, var(--em-accent)));
    color:#fff; border:none; box-shadow:0 10px 24px -10px color-mix(in srgb, var(--em-primary) 70%, transparent);
}
.em-btn-ghost{ background:transparent; border:1px solid var(--em-border) }
.em-btn-sm{ padding:8px 14px; font-size:12.1px }
.em-btn-icon{ width:44px; height:44px; padding:0; border-radius:50% }
.em-btn:disabled{ opacity:.5; pointer-events:none }
/* Completes the button family to match .em-badge's semantic set
   (design-system.md §2) — previously only ghost/primary existed here. */
.em-btn-danger{ background:var(--em-danger-weak); border-color:transparent; color:var(--em-danger) }
.em-btn-outline{ background:transparent; border:1.5px solid var(--em-primary); color:var(--em-primary) }
.em-btn.is-loading{ position:relative; color:transparent!important; pointer-events:none }
.em-btn.is-loading::after{
    content:""; position:absolute; inset-inline-start:50%; top:50%; margin-inline-start:-8px; margin-top:-8px;
    width:16px; height:16px; border-radius:50%; border:2px solid currentColor; border-inline-end-color:transparent;
    color:var(--em-text); animation:sfBtnSpin .6s linear infinite;
}
.em-btn-primary.is-loading::after{ color:#fff }
@keyframes sfBtnSpin{ to{ transform:rotate(360deg) } }

/* ---------- Hero slider ---------- */
.em-hero{
    position:relative; border-radius:0 0 32px 32px; overflow:hidden; background:var(--em-secondary);
    margin:10px 10px 0; box-shadow:var(--em-shadow-lg);
}
@media (min-width:768px){ .em-hero{ margin:16px 16px 0; border-radius:28px } }
.em-hero-viewport{ position:relative; overflow:hidden; touch-action:pan-y; }
.em-hero-track{ display:flex; transition:transform .55s cubic-bezier(.22,.68,.36,1) }
.em-hero-slide{
    flex:0 0 100%; height:52vh; min-height:320px; max-height:560px; position:relative;
    background:var(--em-surface-2);
}
.em-hero-slide img{
    position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center;
    opacity:1; transition:opacity .4s ease;
}
.em-hero-slide.loading img{ opacity:0 }
.em-hero-skeleton{
    position:absolute; inset:0; opacity:0; transition:opacity .3s ease;
    background:linear-gradient(90deg, var(--em-surface-2) 25%, color-mix(in srgb, var(--em-surface-2) 60%, #fff) 37%, var(--em-surface-2) 63%);
    background-size:400% 100%; animation:sfShimmer2 1.4s ease infinite;
}
.em-hero-slide.loading .em-hero-skeleton{ opacity:1 }
@keyframes sfShimmer2{ 0%{background-position:100% 0} 100%{background-position:0 0} }
.em-hero-slide::after{
    content:""; position:absolute; inset:0; z-index:1;
    /* Mobile/tablet: content is bottom-anchored (see .em-hero-content below),
       so the scrim only needs to darken the bottom third for readability. */
    background:linear-gradient(0deg, rgba(0,0,0,.62), rgba(0,0,0,.06) 55%);
}
/* Full-bleed overlay (matches the background edge-to-edge); .em-hero-inner
   is the shared .em-container, so .em-hero-content's actual text column lines
   up with every other section's content regardless of viewport width —
   see the requirement that the hero background stays full width while its
   content follows the site's standard container/grid system. */
.em-hero-overlay{
    position:absolute; inset:0; z-index:2; pointer-events:none;
    display:flex; align-items:flex-end; /* mobile/tablet: bottom-anchored */
}
.em-hero-inner{ width:100% }
.em-hero-content{
    pointer-events:none; color:#fff; padding-block:26px 36px;
}
.em-hero-content > *{ pointer-events:auto }
.em-hero-eyebrow{
    display:inline-block; font-size:var(--em-text-xs); font-weight:800; letter-spacing:.08em; text-transform:uppercase;
    background:rgba(255,255,255,.16); backdrop-filter:blur(8px); border:1px solid rgba(255,255,255,.3);
    padding:5px 12px; border-radius:99px; margin-bottom:14px;
}
.em-hero-content h1{ font-size:var(--em-text-4xl); font-weight:900; margin:0 0 12px; letter-spacing:var(--em-tracking-tight); text-shadow:0 2px 16px rgba(0,0,0,.3) }
.em-hero-content p{ font-size:var(--em-text-base); opacity:.95; margin:0 0 24px; max-width:540px; line-height:var(--em-lh-relaxed) }

/* ---------- Desktop: content moves into a vertically-centered column
   instead of hugging the bottom edge — a full-width bottom band reads
   cramped against a tall hero and competes with the image's own focal
   point. A directional scrim (strong on the content side, fading to clear
   over the image) replaces the flat top-to-bottom one so the food photo
   stays vivid on the far side while text keeps full contrast. Content sits
   on the reading-start side (right in RTL, left in LTR) — the [dir] pair
   below is only for the *gradient angle*, since `linear-gradient(to left/
   right, …)` has no logical-property equivalent, same pattern already used
   for the cart drawer's transform elsewhere in this file. ---------- */
@media (min-width:900px){
    .em-hero-slide{ min-height:520px; max-height:680px }
    .em-hero-slide::after{
        background:linear-gradient(to left, rgba(8,6,12,.8) 0%, rgba(8,6,12,.55) 30%, rgba(8,6,12,.12) 58%, transparent 82%);
    }
    [dir=ltr] .em-hero-slide::after{
        background:linear-gradient(to right, rgba(8,6,12,.8) 0%, rgba(8,6,12,.55) 30%, rgba(8,6,12,.12) 58%, transparent 82%);
    }
    .em-hero-overlay{ align-items:center }
    .em-hero-content{ max-width:600px; padding-block:0 }
    .em-hero-content p{ font-size:var(--em-text-lg) }
}

.em-hero-arrow{
    position:absolute; top:50%; translate:0 -50%; z-index:4; width:42px; height:42px; border-radius:50%;
    background:rgba(255,255,255,.16); backdrop-filter:blur(10px); border:1px solid rgba(255,255,255,.3); color:#fff;
    font-size:20.5px; display:flex; align-items:center; justify-content:center; transition:.2s; line-height:1;
}
.em-hero-arrow:hover{ background:rgba(255,255,255,.3); transform:translateY(-50%) scale(1.06) }
.em-hero-arrow.prev{ inset-inline-start:16px }
.em-hero-arrow.next{ inset-inline-end:16px }
[dir=rtl] .em-hero-arrow.prev{ transform:scaleX(-1) }
[dir=rtl] .em-hero-arrow.next{ transform:scaleX(-1) }
@media (max-width:640px){ .em-hero-arrow{ display:none } }
/* Desktop: content is now vertically centered, so a vertically-centered
   arrow on the content side would sit on top of the title/button — drop
   both arrows to a footer row instead, still on their correct RTL/LTR side. */
@media (min-width:900px){
    .em-hero-arrow{ top:auto; bottom:26px; translate:none }
    .em-hero-arrow:hover{ transform:scale(1.06) }
    [dir=rtl] .em-hero-arrow.prev:hover{ transform:scaleX(-1) scale(1.06) }
    [dir=rtl] .em-hero-arrow.next:hover{ transform:scaleX(-1) scale(1.06) }
}

.em-hero-dots{ position:absolute; bottom:18px; inset-inline-end:22px; display:flex; gap:7px; z-index:3 }
.em-hero-dots button{ width:8px; height:8px; border-radius:99px; background:rgba(255,255,255,.5); border:none; padding:0; transition:.25s }
.em-hero-dots button.active{ width:24px; background:#fff }
@media (min-width:900px){ .em-hero-dots{ bottom:84px; inset-inline-end:30px } } /* stacked above the arrow row so they never overlap */

/* ---------- Category page hero (cover image banner) ---------- */
.em-category-hero{
    position:relative; height:190px; border-radius:0 0 28px 28px; overflow:hidden; margin:10px 10px 0;
    display:flex; align-items:flex-end; background:var(--em-secondary); box-shadow:var(--em-shadow-lg);
}
@media (min-width:768px){ .em-category-hero{ margin:16px 16px 0; border-radius:24px; height:260px } }
.em-category-hero img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover }
.em-category-hero-default{ position:absolute; inset:0; background:linear-gradient(135deg, var(--em-secondary), var(--em-primary)) }
.em-category-hero-overlay{ position:absolute; inset:0; background:linear-gradient(0deg, rgba(0,0,0,.6), rgba(0,0,0,.05) 60%) }
.em-category-hero h1{
    position:relative; z-index:2; color:#fff; margin:0; padding:22px 20px; font-size:var(--em-text-3xl);
    font-weight:900; text-shadow:0 2px 14px rgba(0,0,0,.3);
}

/* ---------- Section heading ---------- */
.em-section{ padding-block:36px }
.em-section-head{ display:flex; align-items:flex-end; justify-content:space-between; margin-bottom:18px; gap:12px }
.em-section-head h2{ font-size:var(--em-text-2xl); font-weight:800; margin:0; letter-spacing:var(--em-tracking-tight) }
.em-section-head p{ margin:4px 0 0; color:var(--em-muted); font-size:var(--em-text-sm) }
.em-section-head a{ font-weight:700; font-size:var(--em-text-sm); color:var(--em-primary); white-space:nowrap }

/* ---------- Cards (generic) ---------- */
.em-card{
    background:var(--em-surface); border:1px solid var(--em-border); border-radius:var(--em-card-radius);
    box-shadow:var(--em-shadow); transition:transform .2s ease, box-shadow .2s ease;
}
.em-card:hover{ transform:translateY(-3px); box-shadow:var(--em-shadow-lg) }

/* ---------- Branch cards ---------- */
.em-branch-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:16px }
.em-branch-card{ padding:20px; cursor:pointer; position:relative }
.em-branch-card.nearest::before{
    content:"⭐ Nearest"; position:absolute; top:-10px; inset-inline-start:16px; background:var(--em-accent);
    color:#fff; font-size:10.2px; font-weight:800; padding:4px 10px; border-radius:99px;
}
.em-branch-card h3{ margin:0 0 6px; font-size:14.9px; font-weight:800 }
.em-branch-card .muted{ color:var(--em-muted); font-size:12.1px }
.em-branch-card .dist{ margin-top:10px; font-size:11.6px; font-weight:700; color:var(--em-primary) }
.em-branch-card.selected{ outline:2px solid var(--em-primary); outline-offset:2px }

/* ---------- Search bar ---------------------------------------------------
   حقلٌ واحد ممتد أسفل الشريط، بحوافّ الأزرار نفسها (99px) وخلفية السطح - فهو
   من عائلة الشريط الذي فوقه لا صندوقٌ غريبٌ هبط بينه وبين التصنيفات. */
.em-search-bar{ margin-block:14px }
.em-search-input{
    width:100%; padding:13px 18px; border-radius:var(--em-btn-radius);
    border:1px solid var(--em-border); background:var(--em-surface); color:var(--em-text);
    font-family:inherit; font-size:13.5px; outline:none;
    transition:border-color .15s ease, box-shadow .15s ease;
}
.em-search-input::placeholder{ color:var(--em-muted) }
.em-search-input:focus{ border-color:var(--em-primary); box-shadow:0 0 0 3px var(--em-primary-weak) }

/* ---------- Category navigation row (one line, horizontally scrollable) ---------- */
.em-cats{
    position:sticky; top:68px; z-index:50; background:var(--em-bg); padding-block:14px;
    border-bottom:1px solid var(--em-border);
}
.em-cats-static{ position:static; border-bottom:none; padding-block:0 }
.em-cats-row{
    display:flex; flex-wrap:nowrap; gap:10px; overflow-x:auto; scroll-behavior:smooth;
    scrollbar-width:none; -webkit-overflow-scrolling:touch;
}
.em-cats-row::-webkit-scrollbar{ display:none }
.em-cat-chip{
    flex:0 0 auto; display:flex; flex-direction:column; align-items:center; gap:6px; white-space:nowrap;
    padding:10px 16px 12px; border-radius:18px; border:1px solid var(--em-border); min-width:76px;
    background:var(--em-surface); font-weight:700; font-size:var(--em-text-xs); color:var(--em-muted); text-align:center;
    transition:background .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease, transform .15s ease;
}
.em-cat-chip-icon{
    width:40px; height:40px; border-radius:50%; background:var(--em-surface-2); display:flex; align-items:center;
    justify-content:center; overflow:hidden; flex-shrink:0; transition:background .18s ease, color .18s ease;
}
.em-cat-chip-icon img{ width:100%; height:100%; object-fit:cover }
.em-cat-chip-label{ line-height:1.3 }
.em-cat-chip:hover{ color:var(--em-text); transform:translateY(-2px) }
.em-cat-chip.active{
    background:var(--em-primary-weak); color:var(--em-primary); border-color:color-mix(in srgb, var(--em-primary) 35%, var(--em-border));
    box-shadow:0 8px 20px -10px color-mix(in srgb, var(--em-primary) 70%, transparent);
}
.em-cat-chip.active .em-cat-chip-icon{ background:var(--em-primary); color:#fff }

/* ---------- Product cards ---------- */
.em-product-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:18px }
/* عمودان على الهاتف الكبير.
   حدّ الـ 220 أعلاه يعني أن عمودين لا يظهران قبل 476 بكسل، فهاتفٌ عرضه 430 كان
   يعرض بطاقةً واحدة بعرض 394 بصورةٍ بارتفاعها - صنفٌ واحد يملأ الشاشة ويُمرَّر
   القارئ عشر مرات ليرى عشرة أصناف. القاعدة محصورة بين 420 و 639 فقط، وعند 640
   يستأنف الحدّ الأعلى عمله وهو يعطي عمودين أيضًا - فلا قفزة عند الحدّ. */
@media (min-width:420px) and (max-width:639px){
    .em-product-grid{ grid-template-columns:repeat(2,1fr) }
}
.em-product-card{ overflow:hidden; display:flex; flex-direction:column }
.em-product-media{ position:relative; aspect-ratio:4/3; overflow:hidden; background:var(--em-surface-2) }
.em-product-media img{ width:100%; height:100%; object-fit:cover; transition:transform .35s ease }
.em-product-card:hover .em-product-media img{ transform:scale(1.06) }
.em-badges{ position:absolute; top:10px; inset-inline-start:10px; display:flex; flex-direction:column; gap:6px; z-index:2 }
.em-badge{ font-size:10.2px; font-weight:800; padding:4px 9px; border-radius:99px; color:#fff }
.em-badge-discount{ background:var(--em-danger) }
.em-badge-new{ background:var(--em-accent) }
.em-badge-out{ background:#8b899c }
/* Soft/pill semantic variants (design-system.md §2) — used for status pills
   across the storefront + Portal (order status, coupon "active", etc.)
   instead of the ~8 places that previously repeated
   style="background:var(--em-primary-weak);color:var(--em-primary)" inline. */
.em-badge-soft{ font-weight:700; padding:4px 12px }
.em-badge-primary{ background:var(--em-primary-weak); color:var(--em-primary) }
.em-badge-success{ background:var(--em-success-weak); color:var(--em-success) }
.em-badge-danger-soft{ background:var(--em-danger-weak); color:var(--em-danger) }
.em-badge-warning{ background:var(--em-warning-weak); color:var(--em-warning) }
.em-badge-info{ background:var(--em-info-weak); color:var(--em-info) }
.em-product-body{ padding:14px 16px 16px; display:flex; flex-direction:column; gap:6px; flex:1 }
.em-product-body h3{ margin:0; font-size:14px; font-weight:800; line-height:1.3 }
.em-product-body .desc{ color:var(--em-muted); font-size:11.6px; line-height:1.5; overflow:hidden; text-overflow:ellipsis; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical }
.em-price-row{ display:flex; align-items:center; justify-content:space-between; margin-top:auto; padding-top:8px }
.em-price{ font-weight:800; font-size:14.9px; font-variant-numeric:tabular-nums }
.em-price-original{ color:var(--em-muted); text-decoration:line-through; font-size:11.6px; margin-inline-end:6px; font-weight:500 }
.em-add-btn{
    width:38px; height:38px; border-radius:50%; border:none; background:var(--em-primary); color:#fff;
    font-size:18.6px; line-height:1; display:flex; align-items:center; justify-content:center; transition:transform .15s;
}
.em-add-btn:hover{ transform:scale(1.08) }
.em-add-btn.added{ animation:sfPop .35s ease }
@keyframes sfPop{ 0%{transform:scale(1)} 40%{transform:scale(1.35)} 100%{transform:scale(1)} }

/* ---------- Product option rows (size / addon selection) ---------- */
.em-select-row{
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    padding:12px 14px; border:1.5px solid var(--em-border); border-radius:14px;
    margin-bottom:8px; cursor:pointer; transition:border-color .15s ease, background .15s ease;
}
.em-select-row:last-child{ margin-bottom:0 }
.em-select-row:hover{ border-color:color-mix(in srgb, var(--em-primary) 45%, var(--em-border)) }
.em-select-row:has(input:checked){ border-color:var(--em-primary); background:var(--em-primary-weak) }
.em-select-row:has(input:disabled){ opacity:.5; cursor:not-allowed }
.em-select-row.is-disabled{ opacity:.5; cursor:not-allowed }
.em-select-row input{ accent-color:var(--em-primary); width:17px; height:17px; margin-inline-end:8px; vertical-align:-3px }

/* ---------- Offers page --------------------------------------------------
   بطاقة العرض تُقرأ من أعلاها: شارةٌ ثم اسمٌ ثم ما يعنيه العرض بالضبط، ثم على
   ماذا يسري. لا صورة لها لأن العرض ليس صنفًا - قد يسري على قسمٍ كامل. */
.em-offer-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:18px }
.em-offer-card{ padding:var(--em-space-5); display:flex; flex-direction:column; gap:var(--em-space-3) }
.em-offer-head{ display:flex; align-items:center; gap:10px }
.em-offer-head h3{ margin:0; font-size:var(--em-text-lg); font-weight:800 }
.em-offer-badge{ flex-shrink:0 }
.em-offer-line{ margin:0; font-weight:700; color:var(--em-primary) }
.em-offer-desc{ margin:0; color:var(--em-muted); font-size:var(--em-text-sm); line-height:1.6 }
.em-offer-items{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; font-size:var(--em-text-sm) }
.em-chip{
    display:inline-block; padding:3px 10px; border-radius:99px;
    background:var(--em-surface-2); border:1px solid var(--em-border); font-size:11.6px; font-weight:600;
}
/* شارة الطاولة في الشريط: تُقرأ ولا تُزاحم، وتبقى على الجوال لأن الجوال هو
   الجهاز الذي مسح الرمز - فإن ضاق الشريط بها أخفت أيقونتها لا نصَّها. */
.em-table-chip{
    display:inline-flex; align-items:center; gap:6px; max-width:38vw;
    background:var(--em-primary-weak); border-color:transparent; color:var(--em-primary);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.em-table-chip > span{ overflow:hidden; text-overflow:ellipsis }
@media (max-width:420px){ .em-table-chip > svg{ display:none } }

.em-offer-until{ margin-top:auto; padding-top:var(--em-space-3); border-top:1px solid var(--em-border); font-size:11.6px; color:var(--em-muted) }

/* ---------- Skeleton loading ---------- */
.em-skeleton{ position:relative; overflow:hidden; background:var(--em-surface-2); border-radius:var(--em-card-radius) }
.em-skeleton::after{
    content:""; position:absolute; inset:0; transform:translateX(-100%);
    background:linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
    animation:sfShimmer 1.4s infinite;
}
@keyframes sfShimmer{ 100%{ transform:translateX(100%) } }

/* ---------- Fade-in on scroll ---------- */
.em-fade{ opacity:0; transform:translateY(16px); transition:opacity .5s ease, transform .5s ease }
.em-fade.in{ opacity:1; transform:none; }

/* ---------- Sticky / floating cart ---------- */
.em-cart-fab{
    position:fixed; bottom:20px; inset-inline-end:20px; z-index:70; display:flex; align-items:center; gap:10px;
    background:var(--em-secondary); color:#fff; padding:14px 20px; border-radius:99px; box-shadow:var(--em-shadow-lg);
    font-weight:800; font-size:13px; transition:transform .2s;
}
.em-cart-fab:hover{ transform:translateY(-2px) }
.em-cart-fab .count{
    background:var(--em-primary); min-width:22px; height:22px; border-radius:50%; display:flex; align-items:center;
    justify-content:center; font-size:11.2px;
}
.em-cart-fab.hidden{ display:none }

/* ---------- Cart icon + badge (navbar / mobile bar) ---------- */
.em-cart-trigger{ position:relative; transition:transform .2s ease }
.em-cart-trigger:hover{ transform:translateY(-2px) rotate(-4deg) }
.em-cart-badge{
    position:absolute; top:-7px; inset-inline-end:-7px; min-width:19px; height:19px; padding:0 5px;
    border-radius:99px; background:var(--em-accent); color:#fff; font-size:10.2px; font-weight:800;
    display:flex; align-items:center; justify-content:center;
    /* Fixed white ring (not var(--em-surface)) on purpose — a theme-matched
       border blends into whatever surface the badge happens to sit on in
       dark mode, which was the actual visibility complaint. A constant
       white ring plus a real shadow separates the badge from ANY
       background, light or dark, regardless of tenant accent color. */
    border:2px solid #fff; box-shadow:0 2px 8px rgba(0,0,0,.35);
}
.em-cart-badge[hidden]{ display:none } /* higher specificity than the UA [hidden] rule needs this explicit override */

/* ---------- Mobile bottom navigation (floating pill, mobile only) ---------- */
.em-mobile-bar{
    display:none; /* shown only below 900px, see media query — desktop never sees this bar */
}
@media (max-width:899px){
    .em-mobile-bar{
        position:fixed; z-index:65; left:12px; right:12px; bottom:calc(12px + env(safe-area-inset-bottom));
        display:flex; align-items:stretch; gap:2px; padding:6px;
        background:color-mix(in srgb, var(--em-surface) 88%, transparent); backdrop-filter:blur(18px); -webkit-backdrop-filter:blur(18px);
        border:1px solid var(--em-border); border-radius:22px; box-shadow:var(--em-shadow-lg);
    }
}
.em-mbar-item{
    flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
    padding:9px 4px; border-radius:16px; border:none; background:transparent; color:var(--em-muted);
    font-size:9.8px; font-weight:700; transition:background .2s ease, color .2s ease; min-height:52px;
}
.em-mbar-item svg{ transition:transform .2s ease }
.em-mbar-item:active svg{ transform:scale(.88) }
.em-mbar-item.active{ color:var(--em-primary); background:var(--em-primary-weak) }
.em-mbar-cart{ position:relative }
.em-mbar-cart .em-cart-badge{ top:2px; inset-inline-end:14px }

/* ---------- Cart drawer ---------- */
.em-drawer-overlay{ position:fixed; inset:0; background:rgba(20,16,25,.5); z-index:80; opacity:0; visibility:hidden; transition:.25s }
.em-drawer-overlay.show{ opacity:1; visibility:visible }
.em-drawer{
    position:fixed; top:0; bottom:0; inset-inline-end:0; width:min(420px,100vw); background:var(--em-surface);
    z-index:81; transition:transform .3s cubic-bezier(.22,.68,.36,1); display:flex; flex-direction:column;
    box-shadow:-16px 0 48px rgba(20,20,30,.18);
    /* inset-inline-end:0 anchors this to the LEFT in RTL (the default/primary
       locale here) and to the RIGHT in LTR — the hidden-state transform must
       push it further in that SAME physical direction, which is opposite for
       each direction since translateX() operates in physical pixels, not
       logical ones. Got this backwards once already; verified against a real
       screenshot the second time. */
    transform:translateX(-100%);
}
[dir=ltr] .em-drawer{ transform:translateX(100%) }
.em-drawer.open{ transform:translateX(0) }

/* ---------- Cart lines (drawer + full cart page) ---------- */
#em-cart-body{ position:relative; transition:opacity .15s ease }
#em-cart-body.is-loading{ opacity:.45; pointer-events:none }
#em-cart-body.is-loading::after{
    content:""; position:absolute; top:20px; inset-inline-end:calc(50% - 12px); width:24px; height:24px;
    border-radius:50%; border:3px solid var(--em-border); border-top-color:var(--em-primary);
    animation:sfSpin .6s linear infinite; z-index:5;
}
@keyframes sfSpin{ to{ transform:rotate(360deg) } }

.em-cart-list{ display:flex; flex-direction:column; gap:16px }
.em-cart-line{
    display:flex; gap:12px; align-items:flex-start; padding-bottom:16px; border-bottom:1px solid var(--em-border);
}
.em-cart-line-media{
    flex:0 0 auto; width:56px; height:56px; border-radius:14px; background:var(--em-surface-2); overflow:hidden;
    display:flex; align-items:center; justify-content:center; font-size:20.5px;
}
.em-cart-line-media img{ width:100%; height:100%; object-fit:cover }
.em-cart-line-body{ flex:1; min-width:0 }
.em-cart-line-title{ display:block; font-size:13px; font-weight:700; line-height:1.4 }
.em-cart-line-meta{ color:var(--em-muted); font-size:11.2px; margin:4px 0 0; line-height:1.5 }
.em-cart-line-warning{ color:var(--em-primary); font-size:11.2px; font-weight:700; margin:4px 0 0 }
.em-cart-line-footer{ display:flex; align-items:center; gap:10px; margin-top:10px; flex-wrap:wrap }
.em-cart-line-price{ flex:0 0 auto; white-space:nowrap; font-size:13px; font-weight:800; font-variant-numeric:tabular-nums }

.em-qty-stepper{
    display:flex; align-items:center; gap:2px; border:1px solid var(--em-border); border-radius:99px; padding:2px;
}
.em-qty-btn{
    width:26px; height:26px; border-radius:50%; border:none; background:transparent; color:var(--em-text);
    font-size:14px; font-weight:700; display:flex; align-items:center; justify-content:center; transition:.15s;
}
.em-qty-btn:hover{ background:var(--em-primary-weak); color:var(--em-primary) }
.em-qty-value{
    /* An actual chip (not bare text) so the quantity reads as a distinct
       badge against the stepper's border in both themes, instead of relying
       on text color alone for definition. */
    min-width:24px; height:24px; display:flex; align-items:center; justify-content:center;
    text-align:center; font-weight:800; font-size:12.1px; border-radius:99px;
    background:var(--em-primary-weak); color:var(--em-primary);
}
/* سلةٌ حمراء لا × رمادية: الحذف فعلٌ لا رجعة فيه، ولونه يقوله قبل الضغط. والمساحة
   36×36 لأنها تُضغط بإبهامٍ على هاتف، لا بمؤشّر. */
.em-cart-remove-btn{
    display:inline-flex; align-items:center; justify-content:center;
    width:36px; height:36px; padding:0;
    border:1px solid transparent; border-radius:var(--em-btn-radius, 10px);
    background:transparent; color:var(--em-danger); cursor:pointer;
    transition:background .15s, border-color .15s;
}
.em-cart-remove-btn:hover,
.em-cart-remove-btn:focus-visible{ background:var(--em-danger-weak); border-color:var(--em-danger) }

.em-coupon-form{ display:flex; gap:8px }
.em-coupon-form input[type=text]{
    flex:1; padding:10px 14px; border-radius:99px; border:1px solid var(--em-border); background:var(--em-surface);
    font-family:inherit; font-size:12.1px;
}
.em-coupon-applied{
    flex:1; background:var(--em-primary-weak); color:var(--em-primary); display:flex; align-items:center;
    padding:0 14px; border-radius:99px; font-size:11.6px; font-weight:700;
}

.em-cart-totals{ display:flex; flex-direction:column; gap:8px; font-size:12.6px; padding-top:8px }
.em-cart-totals-row{ display:flex; justify-content:space-between }
.em-cart-totals-discount{ color:var(--em-primary); font-weight:700 }
/* سطر العرض في الحساب: المحقَّق بلون البراند لأنه نقصٌ في المبلغ، والذي لم
   يُبلَغ بعدُ باهتٌ لأنه خبرٌ لا حساب. */
.em-cart-offer{ color:var(--em-primary); font-weight:700 }
.em-cart-offer-hint{ color:var(--em-muted); font-size:11.6px }
.em-cart-totals-grand{
    font-weight:800; font-size:15.8px; border-top:1px dashed var(--em-border); padding-top:10px; margin-top:2px;
}
.em-cart-checkout-btn{ width:100%; justify-content:center; padding:15px; font-size:14px; margin-top:4px }

/* ---------- Promotional banner (top/bottom, every public page) ----------
   Deliberately full-bleed (no .em-container, no border-radius) — spans the
   true viewport edge to edge regardless of where .em-promo-banner-wrap sits
   in the DOM. `width:100%` on a block-level div already equals the viewport
   width here since nothing upstream constrains it; aspect-ratio (rather than
   a fixed max-height) is what keeps the image ratio stable across every
   breakpoint without layout shift while it loads. No hover motion — kept
   static/stable per design decision. */
/* مسافةٌ فوقه: الشريط الترويجي يلي الشريط المتحرك مباشرةً في صفحة المنيو، وهذا
   بلا هامشٍ أسفله - فكانت الصورتان تتلامسان عند البكسل نفسه، صورةٌ كبيرة فوق
   صورةٍ كبيرة بحافّتين مستديرتين متلاصقتين، تُقرأ كخللٍ في العرض لا كترتيب.
   ما تحته لا يحتاج شيئًا: القسم التالي يحمل حشوته، والتذييل يحمل هامشه. */
.em-promo-banner-wrap{ overflow-x:hidden; justify-items:center; margin-block-start:var(--em-space-6) }
.em-promo-banner{
    position:relative; display:block; overflow:hidden; background:var(--em-surface-2); width:80%;border-radius: 15px;
}
.em-promo-banner picture, .em-promo-banner img{
    display:block; width:100%; height:100%; object-fit:cover; aspect-ratio:16/5;border-radius: 15px;
}
@media (max-width:640px){ .em-promo-banner picture, .em-promo-banner img{ aspect-ratio:4/3 } }
.em-promo-banner-content{
    position:absolute; inset:0; display:flex; flex-direction:column; justify-content:center; gap:6px;
    padding:20px 5vw; background:linear-gradient(90deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.15) 60%, transparent 100%); color:#fff;align-items: center;
}
[dir=ltr] .em-promo-banner-content{ background:linear-gradient(-90deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.15) 60%, transparent 100%) }
.em-promo-banner-eyebrow{ font-size:var(--em-text-xs); font-weight:800; letter-spacing:.06em; text-transform:uppercase; opacity:.9 }
.em-promo-banner-title{ font-size:var(--em-text-xl); font-weight:900 }
.em-promo-banner-desc{ font-size:var(--em-text-sm); opacity:.92; margin:0; max-width:440px }
.em-promo-banner-content .em-btn{ width:fit-content; margin-top:6px }

/* ---------- Checkout address map picker ---------- */
.em-map-picker{
    width:100%; height:240px; border-radius:14px; margin-top:10px; border:1px solid var(--em-border);
    background:var(--em-surface-2); overflow:hidden;
}

/* ---------- Footer ---------- */
.em-footer{ background:var(--em-footer); color:#fff; margin-top:60px; padding-block:48px 28px }
.em-footer h4{ font-size:13px; font-weight:800; margin:0 0 14px; opacity:.9 }
.em-footer a{ color:rgba(255,255,255,.72); font-size:12.6px; display:block; padding:5px 0 }
.em-footer a:hover{ color:#fff }
/* auto-fill لا auto-fit، وهو الفرق الوحيد عن التصميم المنقول في هذا السطر.
   auto-fit يطوي المسارات الفارغة ويوزّع عرضها على الموجود، وتذييل ذاك المتجر
   أربعة أعمدة دائمًا فلم يظهر أثره. أما أعمدتنا فمن بيانات التاجر: من لم يكتب
   هاتفًا لا يُرسم له عمود تواصل - فعمودان على شاشة عريضة كانا يتمدّدان إلى 544
   بكسل لكلٍّ منهما ويتباعدان حتى يبدو التذييل مفكوكًا. بـ auto-fill يبقى العمود
   بعرضه الطبيعي ويقف إلى جانب أخيه، والفراغ يبقى فراغًا. */
.em-footer .cols{ display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:28px }
.em-footer-social{ display:flex; gap:10px; margin-top:32px }
.em-footer-social a{
    display:flex; align-items:center; justify-content:center; width:36px; height:36px; border-radius:50%;
    background:rgba(255,255,255,.1); color:#fff; padding:0; transition:background .2s ease, transform .2s ease;
}
.em-footer-social a:hover{ background:var(--em-primary); transform:translateY(-2px) }
.em-footer .bottom{ border-top:1px solid rgba(255,255,255,.12); margin-top:32px; padding-top:20px; font-size:11.6px; color:rgba(255,255,255,.6); display:flex; justify-content:space-between; flex-wrap:wrap; gap:10px }

/* ---------- Toast / snackbar ---------- */
.em-toast-root{
    position:fixed; z-index:90; left:0; right:0; bottom:calc(16px + env(safe-area-inset-bottom));
    display:flex; flex-direction:column; align-items:center; gap:8px; pointer-events:none;
}
@media (max-width:899px){ .em-toast-root{ bottom:calc(90px + env(safe-area-inset-bottom)) } } /* clear the floating mobile bar */
.em-toast{
    /* Fixed dark neutral (not var(--em-secondary)) on purpose: a tenant can
       set their secondary brand color to anything, including something
       pale — white toast text would then fail in EITHER theme. A constant
       near-black surface guarantees the white text always has real
       contrast, in both light and dark mode, regardless of tenant palette. */
    pointer-events:auto; display:flex; align-items:center; gap:10px; max-width:min(380px,92vw);
    background:#211f2b; color:#fff; padding:13px 18px 13px 16px; border-radius:14px; box-shadow:0 12px 32px -8px rgba(0,0,0,.5);
    border-inline-start:4px solid #22c55e; /* success (default) */
    font-weight:700; font-size:12.6px; line-height:1.5; opacity:0; transform:translateY(12px) scale(.96);
    transition:opacity .25s ease, transform .25s ease;
}
.em-toast.show{ opacity:1; transform:translateY(0) scale(1) }
.em-toast svg{ flex-shrink:0; color:#4ade80 }
.em-toast.is-error{ border-inline-start-color:#ef4444 }
.em-toast.is-error svg{ color:#f87171 }
.em-toast.is-warning{ border-inline-start-color:#f59e0b }
.em-toast.is-warning svg{ color:#fbbf24 }

/* ---------- Empty states ---------- */
.em-empty{ text-align:center; padding:60px 20px; color:var(--em-muted) }
.em-empty .icon{ font-size:40.9px; margin-bottom:12px }

/* ---------- Glass surface (used on hero CTA card / branch picker modal) ---------- */
.em-glass{ background:rgba(255,255,255,.14); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px); border:1px solid rgba(255,255,255,.25) }

@media (max-width:640px){
    .em-section{ padding-block:26px }
    .em-cats{ top:60px }
}

/* ---------- Modal ------------------------------------------------------
   The delivered design had no modal: its product, cart and checkout were
   each a page of their own, and the one dialog it did show (the branch
   picker) borrowed Bootstrap's. This menu is a single screen - the customer
   scanned a code at a table and must not lose their place - so the same
   steps are dialogs here, and this is that component, built from the same
   tokens as everything else rather than by loading Bootstrap for it.

   Driven by emenuModal in emenu.js: [data-em-modal="<id>"] plus .is-open. */
.em-modal{
    position:fixed; inset:0; z-index:85; display:flex; align-items:center; justify-content:center;
    padding:var(--em-space-4); opacity:0; visibility:hidden; transition:opacity .2s ease, visibility .2s ease;
}
.em-modal.is-open{ opacity:1; visibility:visible }
.em-modal-overlay{ position:absolute; inset:0; background:rgba(20,16,25,.55); backdrop-filter:blur(2px) }
.em-modal-dialog{
    position:relative; z-index:1; width:min(640px,100%); max-height:min(86vh,860px); overflow:hidden;
    display:flex; flex-direction:column; background:var(--em-surface); color:var(--em-text);
    border-radius:var(--em-card-radius); box-shadow:var(--em-shadow-lg);
    transform:translateY(12px) scale(.98); transition:transform .22s cubic-bezier(.22,.68,.36,1);
}
.em-modal.is-open .em-modal-dialog{ transform:none }
.em-modal-dialog.is-wide{ width:min(860px,100%) }
.em-modal-head{
    display:flex; align-items:center; justify-content:space-between; gap:var(--em-space-3);
    padding:var(--em-space-4) var(--em-space-5); border-bottom:1px solid var(--em-border); flex-shrink:0;
}
.em-modal-head h2{ font-size:var(--em-text-lg); font-weight:800; margin:0 }
.em-modal-body{ padding:var(--em-space-5); overflow-y:auto; flex:1 }
.em-modal-foot{
    padding:var(--em-space-4) var(--em-space-5); border-top:1px solid var(--em-border); flex-shrink:0;
    display:flex; gap:var(--em-space-3); align-items:center;
}
.em-modal-close{
    width:36px; height:36px; border-radius:50%; display:flex; align-items:center; justify-content:center;
    font-size:20.5px; line-height:1; color:var(--em-muted); flex-shrink:0;
}
.em-modal-close:hover{ background:var(--em-surface-2); color:var(--em-text) }
/* A dialog that is mostly a list - categories, search results - reads better
   from the bottom on a phone, where the thumb is. */
@media (max-width:640px){
    .em-modal{ align-items:flex-end; padding:0 }
    .em-modal-dialog{ width:100%; max-height:90vh; border-end-start-radius:0; border-end-end-radius:0 }
}

/* Body scroll lock while a dialog or the drawer is open. Without it the page
   behind keeps scrolling under the customer's finger on iOS. */
body.em-scroll-locked{ overflow:hidden }

/* Vue mounts on #app; until it does, the raw mustaches must not flash. */
[v-cloak]{ display:none }

/* ---------- Menu page ---------------------------------------------------
   A handful of rules the delivered design did not need, because there the
   menu, the product and the cart were three separate pages. Here they are
   one screen, so the product dialog's size rows and the cart's table need
   shapes of their own. */
.em-size-row{
    display:flex; align-items:center; justify-content:space-between; gap:var(--em-space-3);
    padding:var(--em-space-3) var(--em-space-4); border:1px solid var(--em-border);
    border-radius:calc(var(--em-card-radius) / 1.5); margin-bottom:var(--em-space-2);
}
.em-size-row strong{ font-weight:800 }
.em-size-row .em-size-price{ margin-inline-start:auto; font-weight:800; font-variant-numeric:tabular-nums }

/* الوصف في النافذة: نفس نص البطاقة كاملًا بلا قصٍّ عند سطرين. */
.em-product-desc{ color:var(--em-muted); font-size:var(--em-text-sm); line-height:1.6; margin:0 0 var(--em-space-4) }
/* "يبدأ من" تسبق السعر، وهي تعليقٌ عليه لا جزءٌ منه - فبوزنٍ وحجمٍ أقل. */
.em-price-from{ color:var(--em-muted); font-size:11.6px; font-weight:600; margin-inline-end:4px }
.em-modal-total{
    display:flex; align-items:center; justify-content:space-between;
    margin-top:var(--em-space-5); padding-top:var(--em-space-4); border-top:1px solid var(--em-border);
}
.em-modal-total-value{ font-size:var(--em-text-xl); font-weight:900; font-variant-numeric:tabular-nums }
.em-modal-buy{ display:flex; align-items:center; gap:var(--em-space-4); margin-top:var(--em-space-4) }
.em-modal-buy .em-modal-add{ flex:1 }
.em-addon-row{
    display:flex; align-items:center; gap:var(--em-space-3); padding:var(--em-space-2) 0;
    border-bottom:1px solid var(--em-border);
}
.em-addon-row:last-child{ border-bottom:none }
.em-addon-row label{ flex:1; cursor:pointer }
.em-addon-row input[type=checkbox]{ width:20px; height:20px; flex-shrink:0 }
.em-cart-table{ width:100%; border-collapse:collapse }
.em-cart-table th{ text-align:start; font-size:var(--em-text-xs); color:var(--em-muted); font-weight:700; padding-bottom:var(--em-space-2) }
.em-cart-table td{ padding:var(--em-space-3) var(--em-space-2); border-top:1px solid var(--em-border); vertical-align:middle }
.em-cart-table .em-cart-product{ display:flex; align-items:center; gap:var(--em-space-3) }
/* صورة الصنف في سطر السلة، وهي ابنٌ مباشر - والمباشرة هنا ليست تجميلًا.
   سطر السلة عندنا لا يحمل صورة أصلًا، فلم تكن هذه القاعدة تصيب إلا صورةً واحدة:
   رمز العملة داخل السطر. فتفرض عليه 48×48، ويقصُّه max-width عند 18 عرضًا، فيخرج
   الرمز ممدودًا مشوّهًا - وهو ما رآه التاجر. بالابن المباشر تنتظر القاعدةُ صورةً
   تُضاف يومًا ولا تمسّ ما بداخل السطر. */
.em-cart-table .em-cart-product > img{ width:48px; height:48px; border-radius:calc(var(--em-card-radius) / 2); object-fit:cover; flex-shrink:0 }
.em-form-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:var(--em-space-4) }
.em-field label{ display:block; font-size:var(--em-text-sm); font-weight:700; margin-bottom:var(--em-space-2) }
.em-field input, .em-field select{
    width:100%; padding:11px var(--em-space-4); border:1px solid var(--em-border);
    border-radius:calc(var(--em-btn-radius) / 4); font-size:var(--em-text-sm);
}
.em-field input:focus, .em-field select:focus{ outline:2px solid var(--em-primary); outline-offset:1px }
/* The "send me offers on WhatsApp" box under the phone field. Spans the whole form row. */
.em-consent{ grid-column:1 / -1; display:flex; align-items:flex-start; gap:var(--em-space-2); font-size:var(--em-text-sm); color:var(--em-muted); line-height:1.5; cursor:pointer }
.em-consent input{ flex:none; width:16px; height:16px; margin-top:3px; accent-color:var(--em-primary) }
/* حقلٌ يُقرأ ولا يُملأ - بقياس الحقول حوله لئلا يقفز الشبك، وبلونٍ يقول إنه خبرٌ لا سؤال. */
.em-field-static{
    padding:11px var(--em-space-4); border:1px solid transparent;
    border-radius:calc(var(--em-btn-radius) / 4); font-size:var(--em-text-sm); font-weight:700;
    background:var(--em-primary-weak); color:var(--em-primary);
}
.em-branch-list{ display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:var(--em-space-4) }
.em-done{ text-align:center; padding:var(--em-space-6) var(--em-space-5) }
.em-done-mark{
    width:72px; height:72px; margin:0 auto var(--em-space-4); border-radius:50%;
    background:var(--em-success-weak); color:var(--em-success);
    display:flex; align-items:center; justify-content:center; font-size:31.6px;
}

/* In a card the product image fills a fixed ratio; in the dialog it must not
   push the sizes and the additions below the fold on a phone. */
.em-modal-body > .em-product-media{ max-height:220px }
.em-modal-body > .em-product-media img{ height:220px; object-fit:cover }

/* ---------- Reservation ------------------------------------------------
   Day chips, time slots and the 12/24 switch. The delivered design has no
   booking screen at all, so these are built here from its tokens rather
   than ported: the shapes echo the category chip and the size row so the
   dialog reads as part of the same menu. */
.em-booking{ display:grid; grid-template-columns:1.1fr .9fr; gap:var(--em-space-5) }
@media (max-width:640px){ .em-booking{ grid-template-columns:1fr } }
.em-booking-month{ font-weight:800; margin-bottom:var(--em-space-3) }
.em-days{ display:flex; gap:var(--em-space-2); overflow-x:auto; scrollbar-width:none; padding-bottom:var(--em-space-2) }
.em-days::-webkit-scrollbar{ display:none }
.em-day-chip{
    flex:0 0 auto; min-width:64px; padding:10px 12px; border:1px solid var(--em-border);
    border-radius:calc(var(--em-card-radius) / 1.5); background:var(--em-surface);
    display:flex; flex-direction:column; align-items:center; gap:2px; font-weight:800;
    transition:background .18s ease, color .18s ease, border-color .18s ease;
}
.em-day-chip .em-day-name{ font-size:var(--em-text-xs); font-weight:600; color:var(--em-muted) }
.em-day-chip.active{
    background:var(--em-primary-weak); color:var(--em-primary);
    border-color:color-mix(in srgb, var(--em-primary) 35%, var(--em-border));
}
.em-day-chip.active .em-day-name{ color:inherit }
.em-format-switch{ display:flex; gap:var(--em-space-2); margin-bottom:var(--em-space-3) }
.em-time-period{ font-size:var(--em-text-sm); font-weight:800; color:var(--em-muted); margin:var(--em-space-3) 0 var(--em-space-2) }
.em-times{ display:flex; flex-wrap:wrap; gap:var(--em-space-2) }
.em-time-btn{
    padding:8px 14px; border:1px solid var(--em-border); border-radius:var(--em-btn-radius);
    background:var(--em-surface); font-size:var(--em-text-sm); font-weight:700;
    font-variant-numeric:tabular-nums; transition:background .18s ease, color .18s ease, border-color .18s ease;
}
.em-time-btn:hover{ border-color:var(--em-primary) }
.em-time-btn.active{ background:var(--em-primary); color:#fff; border-color:transparent }
.em-booking-hint{ color:var(--em-danger); font-size:var(--em-text-sm) }

/* A grid column is sized by its content's minimum width unless told
   otherwise, and .em-days is a horizontally scrollable row of chips - so
   without this the booking grid grows as wide as all five days laid out,
   pushing the dialog's own fields off the edge instead of letting the day
   row scroll inside it. */
.em-booking > *{ min-width:0 }

/* No text overlay means no reason to darken the image under it. The scrim
   comes back with the hero settings in the appearance screen. */
.em-hero.is-plain .em-hero-slide::after{ display:none }

/* The arrows and dots are white on a translucent pane, which works over the
   food photography the design assumed and disappears over a light banner -
   and with the scrim off, nothing darkens the image underneath them. Give
   them their own dark pane in plain mode so they stay visible on whatever
   the merchant uploaded. */
.em-hero.is-plain .em-hero-arrow{ background:rgba(0,0,0,.42); border-color:rgba(255,255,255,.35) }
.em-hero.is-plain .em-hero-arrow:hover{ background:rgba(0,0,0,.6) }
.em-hero.is-plain .em-hero-dots{
    background:rgba(0,0,0,.42); padding:7px 10px; border-radius:99px; backdrop-filter:blur(6px);
}

/* ---------- Navbar on a phone -------------------------------------------
   Below 900px the floating bar at the bottom already carries the cart, the
   categories and search, so repeating two of them in the navbar only
   crowded it - on a 375px screen the shop name was left wrapping onto three
   lines. What stays up there is what the bottom bar does not have: the
   language and the theme. */
@media (max-width:899px){
    .em-nav-actions .em-cart-trigger,
    .em-nav-actions [data-em-modal-open="search"]{ display:none }
    .em-brand{ font-size:14.9px; min-width:0 }
    .em-brand span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
}
