/* ============================================================
   AL FAN — Design System Tokens & Storefront Components
   Ported from the approved design prototype (Prototype/shared/tokens.css
   + customer/customer.css), which implements 04_Design_System.docx.

   IMPORTANT — why the component layer is scoped under `.af`:
   the storefront's existing pages each carry their own <style> block and
   define generic names (.btn, .card, .badge, .grid, .state, .row, .input)
   with different rules per page, and none of them were authored against a
   reset. A global component layer would collide with all of them. Scoping
   under `.af` means a page opts in by adding the class to its root element,
   and every page that has not been migrated is completely unaffected.

   The :root tokens below are global and purely additive - any page can
   start consuming them immediately without opting in.
   ============================================================ */

:root {
    /* Brand core */
    --red: #A6192E;
    --red-dark: #7A1220;
    --red-tint: #FBEFF1;
    --grey: #3B3B3B;
    --grey-mid: #6E6E6E;
    --grey-light: #E9E7E5;
    --grey-pale: #F4F3F1;
    --white: #FFFFFF;
    --black: #1A1A1A;

    /* Semantic */
    --success: #2E7D32;
    --success-tint: #EAF4EB;
    --warning: #8A6508;
    --warning-tint: #FAF3E0;
    --error: #A6192E;
    --info: #2E5C8A;
    --info-tint: #EAF0F6;

    /* Spacing scale
       -----------------------------------------------------------------------
       EVERY SPACING VALUE IS A MULTIPLE OF 4. The tokens below are the named
       steps; a value that is not one of them still has to sit on the grid.

       The rule that got the file here, recorded so the next person applies the
       same one: round to the nearest multiple of 4, and on an exact tie round
       up. The single exception is 18 -> 16 rather than 20, because 18 was
       almost always the horizontal partner of a 14 that was becoming 16 - the
       order summary padded 14px 18px, the modal head 16px 18px - and 16/16 is
       the point.

       1px and 2px are left alone. They are hairlines and optical nudges, not
       rhythm, the same way the placeholder glyphs are exempt from the type
       scale.

       This applies to padding, margin and gap. Widths, heights, radii and
       positions are sizes, not rhythm, and set their own values. */
    --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
    --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

    /* Type
       -----------------------------------------------------------------------
       THE SYSTEM FONT FIRST, whichever system that is. Segoe UI used to lead
       both stacks, which reads as "the Windows font, then fallbacks" - but
       Segoe UI does not exist on a Mac or an iPhone, so on every Apple device
       the browser fell past it and landed on whatever `sans-serif` happens to
       be, rather than on San Francisco. -apple-system (with BlinkMacSystemFont
       for Chrome's sake) resolves to nothing at all off Apple hardware, so
       Windows still gets Segoe UI and nothing about the office machines
       changes.

       --font-ar is ordered the same way and for the same reason: the Apple
       system font resolves per script, so Arabic text gets SF Arabic rather
       than falling through to Noto. */
    --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', system-ui, sans-serif;
    --font-ar: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Kufi Arabic', 'IBM Plex Sans Arabic', sans-serif;

    /* Corner radii
       -----------------------------------------------------------------------
       FOUR STEPS, and they mean different kinds of thing rather than different
       amounts of roundness:

           6px    small controls - inputs, chips, small buttons, thumbnails
          10px    cards, panels, media boxes, notices
          16px    large surfaces - bands, modals, the tall panels
         999px    pills, and count badges that used to say "half my own height"

       50% stays for true circles: that is a shape, not a step.

       There were eighteen distinct values before this, including 2, 3, 4, 5, 8,
       12, 14, 20, 99 and 100 - which is not four kinds of corner, it is
       whatever each component's author reached for. A 99px radius and a 999px
       radius are the same pill; they just look like a decision when they are
       not.

       Exempt, for the same reason 1px spacing is: a 14px drag handle, where a
       6px radius would make it a blob. */
    --radius: 10px;
    --radius-sm: 6px;
    --shadow-1: 0 1px 3px rgba(26, 26, 26, .08);
    --shadow-2: 0 4px 16px rgba(26, 26, 26, .12);
    --shadow-3: 0 12px 40px rgba(26, 26, 26, .18);
    --maxw: 1240px;
    /* ONE CURVE. cubic-bezier(.4, 0, .2, 1) was here - Material Design's
       standard easing, symmetrical, which reads as slightly mechanical because
       the motion accelerates as much as it decelerates. The drawer, the modal
       and the scroll reveal were already using (.2, .8, .3, 1): fast out, slow
       in, so a thing arrives quickly and settles. That is the house curve, and
       now everything shares it instead of three quarters of the file. */
    --ease: cubic-bezier(.2, .8, .3, 1);
    --trans: 200ms var(--ease);
}

/* ---------- the typeface, once, for the whole document ----------
   Set on body rather than only on .af, because most of the storefront's pages
   predate the component layer and never take that class. Each of them was
   declaring its own font-family instead, which is how nine pages ended up
   pinned to a Windows-only stack while the header, footer, cart drawer and
   checkout used the token. Two typefaces on one screen.

   Inherited, so a page that says nothing gets it right - including pages not
   written yet. The .adm and .afcrop layers still declare a font of their own,
   because they have to win over anything a page sets - but they now point at
   this same token, so the stack is written down in exactly one place. */
/* LEADING, ONCE. 83% of the text on this site (374 of 449 elements that hold
   their own text) had no line-height of its own and fell to the browser's
   default of about 1.2 - fine on one line, cramped the moment anything wraps,
   which is how the footer's legal note ended up at 12px/14px.

   Measured before changing it: pages grow 15-50px, the tallest single change is
   a button going 44px to 47px. Components that set their own leading - icons,
   counters, anything on line-height: 1 - are untouched. */
body { font-family: var(--font); font-size: 15px; line-height: 1.5; }
html[dir="rtl"] body { font-family: var(--font-ar); }

/* Form controls are the one thing that does NOT inherit the document font - the
   browser hands them its own instead. Most of the storefront's inputs said
   `font-family: inherit` and a few never did, so a card number at checkout and a
   delivery address were typed in the browser's font on a page set in ours. */
button, input, select, textarea { font-family: inherit; font-size: inherit; }

/* ---------- scoped reset (opt-in) ---------- */
.af, .af *, .af *::before, .af *::after { box-sizing: border-box; }
.af h1, .af h2, .af h3, .af h4, .af h5, .af p { margin: 0; }
.af img { max-width: 100%; display: block; }
.af a { color: inherit; text-decoration: none; }
.af button { font-family: inherit; cursor: pointer; }
.af { font-family: var(--font); color: var(--black); }
html[dir="rtl"] .af { font-family: var(--font-ar); }

/* ---------- type scale ----------
   NINE SIZES. THERE IS NO TENTH.

       32   page title, once per page at most
       26   h1
       22   h2, section heading, the grand total figure
       17   h3, price, card heading
       15   body copy, buttons, form controls, line-item names
       13   secondary text, dense rows, metadata
       12   uppercase labels, captions
       11   badges, the smallest thing that is still a sentence
       10   floor - nothing legible goes below this

   This existed before and was ignored: the classes below were used 39 times
   across the whole storefront while 240 hand-written font-sizes went their own
   way, reaching 32 different values including seven half-pixel ones. A size
   ending in .5 does not hint, so it renders a pixel of blur on every display
   that is not Retina - which is most of the ones this shop is read on.

   The gap between 13 and 15 is deliberate and comes from Apple's macOS text
   styles, which this scale follows. 14 is not a size here. If something needs
   to sit between body and secondary, it is body.

   FLUID HEADLINES ARE THE ONE PLACE A SIZE LANDS BETWEEN STEPS
   The banner headlines use clamp(), so between their two endpoints they
   interpolate - at 1100px wide the mosaic caption is 19.8px, which is not a
   step and cannot be. Both ENDPOINTS are steps, which is what keeps the top and
   bottom of the page in the system; the travel between them is the point of
   using clamp at all. Four elements on the home page do this.

   THREE THINGS ARE DELIBERATELY EXEMPT
   - .afbrand-name (15/19/26): a wordmark is a logo, not UI text. Its
     proportions are a brand decision, not a typographic one. The sub-line is
     not exempt - it was 8.5px, below every platform's legibility floor.
   - .ph placeholder letters (40px): artwork standing in for a missing photo.
   - .loyal-band::before (300px): a background graphic that happens to be a
     glyph.
   ---------------------------------------------------------------------- */
.af .t-display { font-size: 32px; line-height: 40px; font-weight: 700; }
.af .t-h1 { font-size: 26px; line-height: 32px; font-weight: 700; }
.af .t-h2 { font-size: 22px; line-height: 28px; font-weight: 600; }
.af .t-h3 { font-size: 17px; line-height: 24px; font-weight: 600; }
.af .t-body { font-size: 15px; line-height: 22px; }
.af .t-small { font-size: 13px; line-height: 18px; color: var(--grey-mid); }
.af .t-price { font-size: 17px; line-height: 24px; font-weight: 700; }
.af .t-label { font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.af .muted { color: var(--grey-mid); }

/* ---------- buttons ---------- */
.af .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    border: none; border-radius: var(--radius-sm); cursor: pointer;
    font-family: inherit; font-size: 15px; font-weight: 700;
    padding: 12px 24px; transition: background var(--trans), transform var(--trans);
}
.af .btn-primary { background: var(--red); color: #fff; }
.af .btn-primary:hover { background: var(--red-dark); }
.af .btn-secondary { background: #fff; color: var(--black); border: 1.5px solid var(--grey-light); }
.af .btn-secondary:hover { border-color: var(--red); color: var(--red); }
.af .btn-dark { background: var(--grey); color: #fff; }
.af .btn-sm { padding: 8px 16px; font-size: 13px; }
.af .btn:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* ---------- badges ---------- */
.af .badge {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 11px; font-weight: 700; letter-spacing: .04em;
    padding: 4px 8px; border-radius: 999px; text-transform: uppercase;
}
.af .badge-sale { background: var(--red); color: #fff; }
.af .badge-new { background: var(--black); color: #fff; }
.af .badge-loyalty { background: linear-gradient(90deg, #F0C040, #DBA514); color: #4A3600; }
.af .badge-oos { background: var(--grey-mid); color: #fff; }
.af .badge-success { background: var(--success-tint); color: var(--success); }

/* ---------- section heading ---------- */
.af .sec-head { display: flex; align-items: baseline; justify-content: space-between; margin: var(--s5) 0 var(--s3); gap: var(--s3); }
.af .sec-head a { font-size: 13px; font-weight: 600; color: var(--red); }
.af .sec-head a:hover { text-decoration: underline; }

/* ---------- product card ---------- */
.af .pcard { position: relative; }
.af .pcard .imgbox { position: relative; border-radius: var(--radius); overflow: hidden; background: var(--grey-pale); }
.af .pcard img { aspect-ratio: 1/1; width: 100%; object-fit: cover; transition: transform 280ms var(--ease); }
.af .pcard:hover img { transform: scale(1.04); }
.af .pcard .imgbox .ph { aspect-ratio: 1/1; display: grid; place-items: center; font-size: 40px; font-weight: 800; color: var(--grey-light); }
.af .pcard .badge { position: absolute; top: 10px; inset-inline-start: 10px; z-index: 1; }
/* No horizontal padding: the card has no border, so the text should start where
   the image above it starts. 2px was neither an inset nor an alignment. */
.af .pcard .binfo { padding: 12px 0 0; }
.af .pcard .bname { font-size: 12px; color: var(--grey-mid); font-weight: 600; text-transform: uppercase; letter-spacing: .05em; }
.af .pcard .pname { font-size: 13px; margin: 4px 0 4px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.af .pcard .prices { display: flex; gap: 8px; align-items: baseline; font-weight: 700; font-size: 15px; }
.af .pcard .prices .was { text-decoration: line-through; color: var(--grey-mid); font-weight: 400; font-size: 12px; }
.af .pcard .prices .now.sale { color: var(--red); }
.af .pcard .pts { font-size: 11px; color: var(--warning); font-weight: 600; margin-top: 4px;
                  display: flex; align-items: center; gap: 4px; }
.af .pcard .pts .ico { flex: none; }
.af .pcard .stars { font-size: 12px; color: var(--warning); letter-spacing: .04em; margin: 4px 0; }
.af .pcard .stars .muted { color: var(--grey-mid); font-size: 11px; }
.af .pcard .lowstock { font-size: 11px; color: var(--red); font-weight: 600; margin-top: 4px; }
/* Sold-out items stay legible but visibly de-emphasised, rather than being hidden. */
.af .pcard .oos-cover { position: absolute; inset: 0; background: rgba(255, 255, 255, .55); pointer-events: none; }

/* ---------- horizontal carousel ---------- */
.af .hwrap { position: relative; }
.af .hscroll {
    /* Track width is a fraction of the row, NOT 1fr. With 1fr a three-item carousel
       stretched each card to ~400px and read as three billboards; with a fixed cap it
       left most of the row empty. Sizing by --cols keeps cards card-sized whether the
       carousel holds three items or thirty, and still scrolls once it overflows. */
    --cols: 5;
    display: grid; grid-auto-flow: column;
    grid-auto-columns: calc((100% - (var(--cols) - 1) * var(--s4)) / var(--cols));
    justify-content: start;
    gap: var(--s4); overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; padding-bottom: 4px;
}
@media (max-width: 1100px) { .af .hscroll { --cols: 4; } }
@media (max-width: 860px)  { .af .hscroll { --cols: 3; } }
@media (max-width: 620px)  { .af .hscroll { --cols: 2.2; } }
.af .hscroll::-webkit-scrollbar { display: none; }
.af .hscroll .pcard { scroll-snap-align: start; }
.af .hwrap .harr {
    position: absolute; top: 34%; z-index: 2; width: 38px; height: 38px;
    border-radius: 50%; border: 1px solid var(--grey-light); background: #fff;
    font-size: 22px; line-height: 1; color: var(--grey);
    display: grid; place-items: center; box-shadow: var(--shadow-1);
    transition: transform var(--trans), color var(--trans);
}
.af .hwrap .harr:hover { transform: scale(1.1); color: var(--red); }
.af .hwrap .harr.prev { inset-inline-start: -12px; }
.af .hwrap .harr.next { inset-inline-end: -12px; }
@media (max-width: 700px) { .af .hwrap .harr { display: none; } }

/* ---------- hero slider ---------- */
.af .slider { position: relative; margin-top: var(--s5); }
.af .slides {
    display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
    overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    border-radius: 16px;
}
.af .slides::-webkit-scrollbar { display: none; }
.af .slide { position: relative; scroll-snap-align: start; cursor: pointer; }
.af .slide img { width: 100%; aspect-ratio: 1280/440; object-fit: cover; }
.af .slide .ph { width: 100%; aspect-ratio: 1280/440; background: var(--grey-pale); }
.af .hero-ov {
    position: absolute; inset-inline-start: 0; bottom: 0; width: 100%;
    padding: clamp(16px, 4vw, 44px);
    background: linear-gradient(0deg, rgba(0, 0, 0, .62), transparent);
    color: #fff;
}
.af .hero-ov h2 { font-size: clamp(22px, 3.4vw, 32px); font-weight: 800; margin-bottom: 12px; text-shadow: 0 2px 12px rgba(0, 0, 0, .35); }
.af .slider .arr {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
    width: 42px; height: 42px; border-radius: 50%; border: none;
    background: rgba(255, 255, 255, .82); color: var(--black);
    font-size: 22px; line-height: 1; display: grid; place-items: center;
    box-shadow: var(--shadow-2); transition: transform var(--trans), background var(--trans);
}
.af .slider .arr:hover { background: #fff; transform: translateY(-50%) scale(1.08); }
.af .slider .arr.prev { inset-inline-start: 14px; }
.af .slider .arr.next { inset-inline-end: 14px; }
.af .dots { position: absolute; bottom: 14px; inset-inline: 0; display: flex; gap: 8px; justify-content: center; z-index: 2; }
.af .dots i {
    width: 8px; height: 8px; border-radius: 50%;
    background: rgba(255, 255, 255, .55);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .38), 0 1px 3px rgba(0, 0, 0, .45);
    transition: background var(--trans), width var(--trans), border-radius var(--trans);
    cursor: pointer;
}
.af .dots i.on { background: #fff; width: 22px; border-radius: 999px; }

/* ---------- category story circles ---------- */
.af .stories { display: flex; gap: clamp(12px, 2.5vw, 28px); overflow-x: auto; padding: var(--s5) 2px var(--s4); scrollbar-width: none; justify-content: center; }
.af .stories::-webkit-scrollbar { display: none; }
.af .story { flex: 0 0 auto; text-align: center; width: 86px; }
.af .story .ring {
    width: 78px; height: 78px; border-radius: 50%; padding: 4px; margin: 0 auto 8px;
    background: linear-gradient(135deg, var(--red), #E86A7C);
    transition: transform var(--trans);
}
.af .story:hover .ring { transform: scale(1.08) rotate(3deg); }
.af .story .ring img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; border: 3px solid #fff; }
.af .story .ring .ph { width: 100%; height: 100%; border-radius: 50%; border: 3px solid #fff; background: var(--grey-pale); display: grid; place-items: center; font-weight: 800; color: var(--grey-mid); }
.af .story span { font-size: 12px; font-weight: 600; color: var(--grey); display: block; }

/* ---------- flash sale strip ---------- */
.af .flash {
    margin-top: var(--s5); border-radius: 16px; overflow: hidden; position: relative;
    background: linear-gradient(120deg, #2A2A2A, #4A1420);
    color: #fff; padding: clamp(16px, 3vw, 28px);
    display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap;
}
.af .flash::before, .af .flash::after { content: ""; position: absolute; border-radius: 50%; }
.af .flash::before { width: 240px; height: 240px; background: var(--red); top: -120px; inset-inline-end: 8%; opacity: .35; }
.af .flash::after { width: 180px; height: 180px; background: #ffffff22; bottom: -90px; inset-inline-start: 20%; }
.af .flash h3 { font-size: clamp(17px, 2.4vw, 22px); font-weight: 800; z-index: 1; position: relative;
                display: inline-flex; align-items: center; gap: 12px; }
.af .flash h3 .ico { flex: none; }
.af .flash .sub { color: rgba(255, 255, 255, .75); font-size: 13px; margin-top: 4px; z-index: 1; position: relative; }
.af .timer { display: flex; gap: 8px; align-items: center; z-index: 1; }
.af .timer .cell { background: rgba(255, 255, 255, .12); border-radius: 6px; padding: 8px 12px; text-align: center; min-width: 56px; }
.af .timer .cell b { display: block; font-size: 22px; font-variant-numeric: tabular-nums; }
.af .timer .cell span { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: rgba(255, 255, 255, .65); }
.af .timer .sep { font-size: 22px; font-weight: 800; opacity: .5; }

/* ---------- mosaic ---------- */
.af .mosaic { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); gap: var(--s4); margin-top: var(--s4); }
.af .mosaic .cell { position: relative; border-radius: 16px; overflow: hidden; }
.af .mosaic .cell img { width: 100%; height: 100%; object-fit: cover; transition: transform 280ms var(--ease); }
.af .mosaic .cell:hover img { transform: scale(1.04); }
.af .mosaic .tall { grid-row: span 2; }
.af .mosaic .tall img { aspect-ratio: 3/4; }
.af .mosaic .wide img { aspect-ratio: 16/6.4; }
.af .mosaic .cell .cap {
    position: absolute; inset-inline-start: 0; bottom: 0; width: 100%; padding: 16px;
    background: linear-gradient(0deg, rgba(0, 0, 0, .55), transparent); color: #fff;
}
.af .mosaic .cell .cap h3 { font-size: clamp(15px, 1.8vw, 22px); font-weight: 800; text-shadow: 0 1px 8px rgba(0, 0, 0, .4); }
.af .mosaic .cell .cap span { font-size: 12px; color: rgba(255, 255, 255, .85); }
@media (max-width: 800px) { .af .mosaic { grid-template-columns: 1fr; } .af .mosaic .tall { grid-row: auto; } }

/* ---------- loyalty band ---------- */
.af .loyal-band {
    margin-top: var(--s5); border-radius: 16px; position: relative; overflow: hidden;
    background: linear-gradient(120deg, #241F1F, #4A1420);
    color: #fff; padding: clamp(24px, 4vw, 44px);
    display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--s5); align-items: center;
}
.af .loyal-band::before { content: "★"; position: absolute; font-size: 300px; inset-inline-end: -50px; top: -80px; opacity: .06; line-height: 1; }
.af .loyal-band h2 { font-size: clamp(22px, 3vw, 32px); font-weight: 800; line-height: 1.2; }
.af .loyal-band p { color: rgba(255, 255, 255, .72); margin-top: 8px; font-size: 15px; }
.af .loyal-band .glass {
    background: rgba(255, 255, 255, .09); border: 1px solid rgba(255, 255, 255, .16);
    border-radius: 16px; padding: 24px; backdrop-filter: blur(6px); text-align: center;
}
.af .loyal-band .pts {
    font-size: clamp(22px, 2.4vw, 32px); font-weight: 800;
    background: linear-gradient(90deg, #F0C040, #DBA514);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    margin-bottom: 4px;
}
@media (max-width: 800px) { .af .loyal-band { grid-template-columns: 1fr; } }

/* ---------- two-up strip ---------- */
.af .strip2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); margin-top: var(--s4); }
.af .strip2 .cell { position: relative; border-radius: 16px; overflow: hidden; }
.af .strip2 .cell img { width: 100%; aspect-ratio: 4/3; object-fit: cover; object-position: top; }
@media (max-width: 700px) { .af .strip2 { grid-template-columns: 1fr; } }

/* ---------- product grid ---------- */
.af .pgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s5) var(--s4); }
@media (max-width: 980px) { .af .pgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 700px) { .af .pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------- site header ---------- */
.af.sitehd { max-width: var(--maxw); margin: 0 auto; padding: 16px 20px 0; }
.af .hdmain { display: flex; align-items: center; gap: var(--s5); }

.af .hdsearch { flex: 1; max-width: 460px; position: relative; display: flex; align-items: center; }
.af .hdsearch .ic { position: absolute; inset-inline-start: 12px; color: var(--grey-mid); display: flex; pointer-events: none; }
.af .hdsearch .sinput {
    width: 100%; font-family: inherit; font-size: 13px;
    padding: 8px 16px 8px 40px; border: 1.5px solid var(--grey-light);
    border-radius: 999px; background: var(--grey-pale); color: var(--black);
}
html[dir="rtl"] .af .hdsearch .sinput { padding: 8px 40px 8px 16px; }
.af .hdsearch .sinput:focus { outline: none; border-color: var(--red); background: #fff; }

/* ---------- search suggestions ---------- */
/* The panel hangs off .hdsearch, which is already position:relative. Logical properties
   throughout, so it flips with the document rather than needing an RTL variant. */
.af .hdsg {
    position: absolute; inset-block-start: calc(100% + 6px); inset-inline: 0;
    z-index: 130; background: #fff; border: 1px solid var(--grey-light);
    border-radius: 16px; box-shadow: 0 12px 32px rgba(26, 26, 26, .14);
    padding: 8px 0; max-height: 70vh; overflow-y: auto; text-align: start;
}
.af .hdsg-h {
    font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--grey-mid); padding: 8px 16px 4px;
}
.af .hdsg-r {
    display: flex; align-items: center; gap: 12px; padding: 8px 16px;
    color: var(--black); font-size: 13px; line-height: 1.3;
}
.af .hdsg-r:hover, .af .hdsg-r:focus-visible { background: var(--grey-pale); }
.af .hdsg-ic { display: flex; color: var(--grey-mid); flex: none; }
.af .hdsg-th {
    width: 38px; height: 38px; flex: none; border-radius: 6px; overflow: hidden;
    background: var(--grey-pale); display: flex; align-items: center; justify-content: center;
}
.af .hdsg-th img { width: 100%; height: 100%; object-fit: cover; }
.af .hdsg-t { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.af .hdsg-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.af .hdsg-sub { font-size: 11px; color: var(--grey-mid); }
.af .hdsg-p { font-size: 12px; font-weight: 700; flex: none; }
.af .hdsg-n { font-size: 11px; color: var(--grey-mid); flex: none; }
/* The category rows are the reason this panel exists, so they read as the primary action. */
.af .hdsg-cat .hdsg-t { font-weight: 600; }
.af .hdsg-none { padding: 16px; font-size: 13px; color: var(--grey-mid); }
.af .hdsg-all {
    display: block; padding: 12px 16px; margin-top: 4px;
    border-top: 1px solid var(--grey-light);
    font-size: 12px; font-weight: 700; color: var(--red);
}
.af .hdsg-all:hover { background: var(--grey-pale); }
/* Invisible, full-viewport, and behind the panel: it exists only to catch the click that
   closes it, which is why it carries no visual weight of its own. */
.af .hdsg-scrim {
    position: fixed; inset: 0; z-index: 125;
    border: 0; padding: 0; margin: 0; background: transparent; cursor: default;
}

.af .sitenav { display: flex; align-items: center; gap: var(--s4); margin-inline-start: auto; }
.af .sitenav a { color: var(--grey-mid); font-size: 13px; font-weight: 600; }
.af .sitenav a:hover { color: var(--red); }
.af .sitenav .hicon { display: inline-flex; align-items: center; position: relative; }
.af .sitehd .badge {
    background: var(--red); color: #fff; font-size: 11px; font-weight: 700;
    min-width: 16px; height: 16px; border-radius: 999px; padding: 0 4px;
    display: inline-flex; align-items: center; justify-content: center;
    position: absolute; top: -6px; inset-inline-end: -8px; text-transform: none; letter-spacing: 0;
}
.af .langsw { border-inline-start: 1px solid var(--grey-light); padding-inline-start: var(--s4); }

.af .catnav {
    display: flex; gap: var(--s5); overflow-x: auto; scrollbar-width: none;
    margin-top: var(--s3); padding-bottom: 12px; border-bottom: 1px solid var(--grey-light);
}
.af .catnav::-webkit-scrollbar { display: none; }
.af .catnav a { font-size: 13px; font-weight: 600; color: var(--grey); white-space: nowrap; }
.af .catnav a:hover { color: var(--red); }

@media (max-width: 760px) {
    .af .hdmain { flex-wrap: wrap; }
    .af .hdsearch { order: 3; flex-basis: 100%; max-width: none; margin-top: 12px; }
    .af .sitenav .langsw { border: 0; padding-inline-start: 0; }
}

/* ---------- cart drawer ---------- */
.af.cdrawer-wrap { position: fixed; inset: 0; z-index: 120; }
.af .cdrawer-scrim {
    position: absolute; inset: 0; border: 0; padding: 0; cursor: default;
    background: rgba(26, 26, 26, .45); animation: af-fade .2s ease;
}
@keyframes af-fade { from { opacity: 0; } }

.af .cdrawer {
    position: absolute; inset-block: 0; inset-inline-end: 0;
    width: min(400px, 100%); background: #fff;
    display: flex; flex-direction: column;
    box-shadow: var(--shadow-3);
    animation: af-slidein .26s var(--ease);
}
@keyframes af-slidein { from { transform: translateX(100%); } }
html[dir="rtl"] .af .cdrawer { animation-name: af-slidein-rtl; }
@keyframes af-slidein-rtl { from { transform: translateX(-100%); } }

.af .cdrawer-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px; border-bottom: 1px solid var(--grey-light); flex: none;
}
.af .cclose { background: none; border: 0; font-size: 17px; color: var(--grey-mid); line-height: 1; padding: 4px; }
.af .cclose:hover { color: var(--red); }

.af .cdrawer-body { flex: 1; overflow-y: auto; padding: 8px 20px; }
.af .cerr { background: var(--red-tint); color: var(--red); padding: 12px 12px; border-radius: var(--radius-sm); font-size: 13px; margin: 12px 0; }

.af .cline { display: flex; gap: 12px; padding: 16px 0; border-bottom: 1px solid var(--grey-pale); }
.af .cthumb { flex: none; width: 62px; border-radius: var(--radius-sm); overflow: hidden; background: var(--grey-pale); }
.af .cthumb img { width: 100%; aspect-ratio: 4/5; object-fit: cover; }
.af .cthumb .ph { display: grid; place-items: center; aspect-ratio: 4/5; font-weight: 800; color: var(--grey-mid); }
.af .cinfo { flex: 1; min-width: 0; }
.af .cname { font-size: 13px; font-weight: 600; color: var(--black); }
.af .cmeta { margin-top: 2px; }
.af .crow { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 8px; }
.af .cqty { display: inline-flex; align-items: center; gap: 12px; border: 1px solid var(--grey-light); border-radius: 999px; padding: 2px 8px; }
.af .cqty .stepbtn { background: none; border: 0; font-size: 15px; color: var(--grey); line-height: 1; padding: 2px 4px; }
.af .cqty .stepbtn:hover:not(:disabled) { color: var(--red); }
.af .cqty .stepbtn:disabled { opacity: .4; cursor: default; }
.af .cprice { font-size: 13px; }
.af .cremove { background: none; border: 0; color: var(--grey-mid); font-size: 13px; align-self: flex-start; padding: 2px 4px; }
.af .cremove:hover:not(:disabled) { color: var(--red); }

.af .cempty { text-align: center; padding: 64px 20px; color: var(--grey-mid); }
.af .cempty .art { display: flex; justify-content: center; margin-bottom: 12px; color: var(--grey-light); }
.af .cempty .art svg { width: 44px; height: 44px; }
.af .cempty .btn { margin-top: 16px; }

.af .cdrawer-foot { flex: none; border-top: 1px solid var(--grey-light); padding: 16px 20px; display: flex; flex-direction: column; gap: 8px; }
.af .csub { display: flex; justify-content: space-between; align-items: baseline; font-size: 15px; }
.af .csub b { font-size: 17px; }
.af .btn-block { width: 100%; }

@media (prefers-reduced-motion: reduce) {
    .af .cdrawer, .af .cdrawer-scrim { animation: none; }
}

/* ---------- mobile tab bar ---------- */
.af.tabbar { display: none; }

@media (max-width: 760px) {
    .af.tabbar {
        display: grid; grid-template-columns: repeat(4, 1fr);
        position: fixed; inset-inline: 0; bottom: 0; z-index: 80;
        background: #fff; border-top: 1px solid var(--grey-light);
        /* Respect the iOS home indicator rather than sitting under it. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .af.tabbar a {
        display: flex; flex-direction: column; align-items: center; gap: 4px;
        padding: 8px 4px; font-size: 11px; font-weight: 600; color: var(--grey-mid);
    }
    .af.tabbar a.on { color: var(--red); }
    .af.tabbar .ic { position: relative; display: flex; }
    .af.tabbar .badge {
        position: absolute; top: -5px; inset-inline-end: -9px;
        background: var(--red); color: #fff; font-size: 10px; font-weight: 700;
        min-width: 15px; height: 15px; border-radius: 999px; padding: 0 4px;
        display: inline-flex; align-items: center; justify-content: center;
    }

    /* The prototype's tab bar covered page content - the customer's review called it
       out. Reserve the bar's height (plus safe area) so the last element on any page
       stays reachable. */
    body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
}

/* ---------- customer account shell ---------- */
.af.acct .wrap { max-width: var(--maxw); margin: 0 auto; padding: 20px 20px 60px; }
.af .accthead { margin: 8px 0 var(--s5); }
.af .prof-grid { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: var(--s6); align-items: start; }
@media (max-width: 820px) { .af .prof-grid { grid-template-columns: 1fr; } }
.af .prof-nav { display: flex; flex-direction: column; gap: 2px; }
.af .prof-nav a {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 16px; border-radius: var(--radius-sm);
    font-weight: 600; font-size: 13px; color: var(--grey);
    transition: background var(--trans), color var(--trans);
}
.af .prof-nav a:hover { background: var(--grey-pale); }
.af .prof-nav a.on { background: var(--red-tint); color: var(--red); }
.af .prof-nav a.out { color: var(--red); margin-top: var(--s3); }
.af .prof-nav a:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.af .prof-nav .ic { display: flex; flex: none; }

/* ---------- generic surfaces used by the account/cart pages ---------- */
.af .card { background: #fff; border: 1px solid var(--grey-light); border-radius: var(--radius); }
.af .card-pad { padding: var(--s5); }
.af .state { text-align: center; padding: 64px 20px; color: var(--grey-mid); }
.af .state .art { display: flex; justify-content: center; margin-bottom: 4px; }
.af .state h3 { color: var(--black); margin: 12px 0 8px; }
.af .state .btn { margin-top: 16px; }

/* ---------- footer ---------- */
.af-foot { border-top: 1px solid var(--grey-light); margin-top: var(--s6); background: var(--grey-pale); }
.af-foot .inner { max-width: var(--maxw); margin: 0 auto; padding: var(--s6) 20px var(--s5); }
.af-foot .foot-grid { display: grid; grid-template-columns: 2fr repeat(4, 1fr); gap: var(--s5); }
.af-foot h5 { font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--black); margin-bottom: 12px; }
.af-foot a { display: block; font-size: 13px; color: var(--grey-mid); padding: 4px 0; text-decoration: none; }
.af-foot a:hover { color: var(--red); }
.af-foot .afbrand { margin-bottom: 16px; }
.af-foot .blurb { font-size: 13px; line-height: 19px; color: var(--grey-mid); max-width: 42ch; }
.af-foot .note { border-top: 1px solid var(--grey-light); margin-top: var(--s5); padding-top: var(--s4); font-size: 12px; color: var(--grey-mid); }
@media (max-width: 1080px) { .af-foot .foot-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 800px) { .af-foot .foot-grid { grid-template-columns: 1fr 1fr; } }

/* ---------- scroll reveal ----------
   Progressive enhancement: the hidden state applies ONLY when JS is running
   (html.af-js is set by an inline script in App.razor before first paint). If
   storefront.js fails to load, or IntersectionObserver never fires, the page is
   never left with invisible content - it simply renders without the animation. */
html.af-js .af .rev { opacity: 0; transform: translateY(12px); }
html.af-js .af .rev-in { opacity: 1; transform: none; transition: opacity 320ms ease, transform 320ms var(--ease); }

/* Anything already on screen when the page loads is shown at once and with no
   transition at all. The observer fires after first paint, so hiding above-fold
   content meant the first thing a customer saw was nothing, for as long as it
   took the callback to run plus the length of the animation. A scroll reveal
   should reveal what you scroll to; what is already in front of you is not a
   reveal, it is the page. */
html.af-js .af .rev.rev-now { opacity: 1; transform: none; transition: none; }

/* ---------- skeletons ---------- */
.af .skel { position: relative; overflow: hidden; background: var(--grey-pale); border-radius: var(--radius-sm); }
.af .skel::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .6), transparent);
    transform: translateX(-100%); animation: af-shimmer 1.4s infinite;
}
@keyframes af-shimmer { to { transform: translateX(100%); } }

.af .page-in { animation: af-pagein .3s ease; }
@keyframes af-pagein { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
    html.af-js .af .rev { opacity: 1; transform: none; }
    html.af-js .af .rev-in { transition: none; }
    .af .page-in { animation: none; }
    .af .skel::after { animation: none; }
    .af .marquee .track { animation: none; }
}

/* ---------- brand marquee ---------- */
.af .marquee { overflow: hidden; margin-top: var(--s5); border-block: 1px solid var(--grey-light); padding: 16px 0; }
.af .marquee .track { display: flex; gap: 64px; width: max-content; animation: af-marquee 26s linear infinite; }
.af .marquee:hover .track { animation-play-state: paused; }
.af .marquee .br {
    font-size: 22px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
    color: #8F8C89; white-space: nowrap; transition: color var(--trans);
}
.af .marquee .br:hover { color: var(--red); }
.af .marquee .br i { font-style: normal; color: var(--red); opacity: .5; margin-inline: 28px; }
@keyframes af-marquee { to { transform: translateX(-50%); } }

/* ============================================================================
   Image crop dialog (.afcrop)

   NOT nested under .af. The storefront component layer is scoped so it cannot
   collide with the pages' own <style> blocks, but this dialog is used from the
   ADMIN pages, which never carry .af. It gets its own prefix instead, and every
   rule below is prefixed, so it stays just as collision-proof.
   ============================================================================ */
.afcrop-wrap { position: fixed; inset: 0; z-index: 900; display: flex;
               align-items: center; justify-content: center; padding: 20px; }
.afcrop-scrim { position: absolute; inset: 0; background: rgba(20,20,20,.62); }

.afcrop { position: relative; display: flex; flex-direction: column;
          width: min(880px, 100%); max-height: 100%; background: #fff;
          border-radius: 10px; box-shadow: 0 24px 60px rgba(0,0,0,.32);
          font: 400 14px/1.45 var(--font);
          color: #1F1F1F; overflow: hidden; }
.afcrop * { box-sizing: border-box; }

.afcrop-head { display: flex; align-items: center; gap: 12px;
               padding: 16px 16px; border-bottom: 1px solid #E7E7E7; }
.afcrop-title { flex: 1; font-size: 15px; font-weight: 600; }
.afcrop-x { border: 0; background: none; font-size: 17px; line-height: 1;
            cursor: pointer; color: #6E6E6E; padding: 4px; }
.afcrop-x:hover { color: #1F1F1F; }

/* The toolbar that tells the user what is wrong with their image. */
.afcrop-issues { display: flex; flex-direction: column; gap: 1px;
                 background: #E7E7E7; border-bottom: 1px solid #E7E7E7; }
.afcrop-issue { display: flex; gap: 8px; padding: 8px 16px; font-size: 13px; }
.afcrop-issue.ok       { background: #F1F8F2; color: #1E6B33; }
.afcrop-issue.info     { background: #FFF8EC; color: #8A5A10; }
.afcrop-issue.blocking { background: #FDF1F1; color: #A62121; }

.afcrop-stage { position: relative; flex: 1; min-height: 220px;
                display: flex; align-items: center; justify-content: center;
                padding: 16px; background: #2B2B2B; overflow: hidden;
                touch-action: none; user-select: none; }
.afcrop-img { max-width: 100%; max-height: 52vh; display: block;
              -webkit-user-drag: none; user-select: none; }

/* Everything outside the frame is dimmed, so what will be kept is unmistakable. */
.afcrop-shade { position: absolute; inset: 0; background: rgba(20,20,20,.55);
                pointer-events: none; }

.afcrop-frame { position: absolute; cursor: move;
                border: 1px solid rgba(255,255,255,.95);
                box-shadow: 0 0 0 1px rgba(0,0,0,.35); }
/* Rule-of-thirds guides, drawn with gradients rather than extra elements. */
.afcrop-frame::before { content: ""; position: absolute; inset: 0; pointer-events: none;
    background:
      linear-gradient(to right,  transparent 33.33%, rgba(255,255,255,.28) 33.33%, rgba(255,255,255,.28) calc(33.33% + 1px), transparent calc(33.33% + 1px), transparent 66.66%, rgba(255,255,255,.28) 66.66%, rgba(255,255,255,.28) calc(66.66% + 1px), transparent calc(66.66% + 1px)),
      linear-gradient(to bottom, transparent 33.33%, rgba(255,255,255,.28) 33.33%, rgba(255,255,255,.28) calc(33.33% + 1px), transparent calc(33.33% + 1px), transparent 66.66%, rgba(255,255,255,.28) 66.66%, rgba(255,255,255,.28) calc(66.66% + 1px), transparent calc(66.66% + 1px)); }

/* 2px, not the 6px step: at 14px square a 6px radius turns a drag handle into a
   blob. Small functional handles sit outside the ladder, the way 1px and 2px sit
   outside the spacing grid. */
.afcrop-h { position: absolute; width: 14px; height: 14px; background: #fff;
            border: 1px solid rgba(0,0,0,.35); border-radius: 2px; }
.afcrop-h.nw { left: -7px;  top: -7px;    cursor: nwse-resize; }
.afcrop-h.ne { right: -7px; top: -7px;    cursor: nesw-resize; }
.afcrop-h.sw { left: -7px;  bottom: -7px; cursor: nesw-resize; }
.afcrop-h.se { right: -7px; bottom: -7px; cursor: nwse-resize; }

/* Live output size - red the moment the crop drops below the minimum. Sits INSIDE the
   frame: below it, the badge is clipped by the stage whenever the frame reaches the
   bottom edge, which is exactly when the user most needs to read it. */
.afcrop-size { position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%);
               padding: 2px 8px; border-radius: 6px; font-size: 11px; font-weight: 600;
               white-space: nowrap; background: rgba(20,20,20,.8); color: #fff; }
.afcrop-size.bad { background: #A62121; }

.afcrop-foot { display: flex; align-items: center; gap: 12px;
               padding: 12px 16px; border-top: 1px solid #E7E7E7; background: #FAFAFA; }
.afcrop-req { font-size: 12px; color: #6E6E6E; }
.afcrop-spacer { flex: 1; }
.afcrop-btn { padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 600;
              cursor: pointer; border: 1px solid transparent; }
.afcrop-btn.ghost   { background: #fff; border-color: #D5D5D5; color: #1F1F1F; }
.afcrop-btn.primary { background: #1F1F1F; color: #fff; }
.afcrop-btn:disabled { opacity: .45; cursor: not-allowed; }

@media (max-width: 640px) {
  .afcrop-foot { flex-wrap: wrap; }
  .afcrop-req  { flex-basis: 100%; }
}

/* ============================================================================
   Brand lockup (.afbrand)

   NOT nested under .af: the admin pages carry the same lockup and never take that
   class. Prefixed instead, like .afcrop.

   The mark is a transparent PNG; the wordmark is text. The light tone inverts the
   mark to white rather than shipping a second file, which also means a new mark
   only ever has to be dropped in once.
   ============================================================================ */
.afbrand { display: inline-flex; align-items: center; gap: 12px; flex: none;
           text-decoration: none; line-height: 1; }
.afbrand-mark { display: block; width: auto; flex: none;
                /* the calligraphy sits optically high against cap-height text */
                transform: translateY(-1px); }
.afbrand-words { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.afbrand-name { font-weight: 800; letter-spacing: .1em; white-space: nowrap; }
.afbrand-sub  { font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
                white-space: nowrap; }

/* ---- sizes ---- */
.afbrand--sm .afbrand-mark { height: 26px; }
.afbrand--sm .afbrand-name { font-size: 15px; }
.afbrand--sm .afbrand-sub  { font-size: 10px; }

.afbrand--md .afbrand-mark { height: 34px; }
.afbrand--md .afbrand-name { font-size: 19px; }
.afbrand--md .afbrand-sub  { font-size: 10px; }

.afbrand--lg .afbrand-mark { height: 54px; }
.afbrand--lg .afbrand-name { font-size: 26px; }
.afbrand--lg .afbrand-sub  { font-size: 11px; }

/* ---- tones ---- */
.afbrand--brand .afbrand-name { color: var(--black, #1A1A1A); }
.afbrand--brand .afbrand-sub  { color: var(--grey-mid, #6E6E6E); }

/* Turns the red mark white for dark surfaces: brightness(0) flattens every pixel to
   black, invert(1) then lifts it to white, and the alpha channel is untouched. */
.afbrand--light .afbrand-mark { filter: brightness(0) invert(1); }
.afbrand--light .afbrand-name { color: #fff; }
.afbrand--light .afbrand-sub  { color: rgba(255, 255, 255, .55); }

/* ---- variants ---- */
.afbrand--stacked { flex-direction: column; gap: 12px; text-align: center; }
.afbrand--stacked .afbrand-words { align-items: center; }

.afbrand--markonly { gap: 0; }

/* A link version gets a gentle press response; the plain <div> version gets none. */
a.afbrand { transition: opacity var(--trans, 200ms); }
a.afbrand:hover { opacity: .78; }
a.afbrand:focus-visible { outline: 2px solid var(--red, #A6192E); outline-offset: 4px;
                          border-radius: 6px; }
a.afbrand.afbrand--light:focus-visible { outline-color: #fff; }

@media (max-width: 560px) {
    /* The sub-line is the first thing to go when space is tight - the mark and name
       still identify the store on their own. */
    .afbrand--md .afbrand-sub { display: none; }
    .afbrand--md .afbrand-mark { height: 30px; }
    .afbrand--md .afbrand-name { font-size: 17px; }
}

/* ============================================================================
   Admin grid pager (.apg)

   Prefixed and outside .af, like .afcrop and .afbrand: the admin pages never carry
   that class, and these generic-sounding names would otherwise collide with the
   page-level style blocks, which are global.
   ============================================================================ */
.apg { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
       margin-top: 16px; padding-top: 12px; border-top: 1px solid #E9E7E5;
       font-size: 13px; color: #6E6E6E; }
.apg-info { font-variant-numeric: tabular-nums; }
.apg-sp { flex: 1; }
.apg-page { font-variant-numeric: tabular-nums; }
.apg-btn {
    padding: 8px 12px; border-radius: 6px; border: 1px solid #D5D5D5;
    background: #fff; color: #1A1A1A; font-size: 13px; font-weight: 600; cursor: pointer;
}
.apg-btn:hover:not(:disabled) { border-color: #A6192E; color: #A6192E; }
.apg-btn:disabled { opacity: .45; cursor: not-allowed; }

/* "from" prefix on a card whose variants are not all the same price - the figure beside
   it is the cheapest variant, and presenting that as a flat price would misquote the rest. */
/* NOT scoped under .af. Three pages use this label and the product page is not
   in the component layer, so scoping it there left "from" completely unstyled
   on the one page where the price needs it most. */
.fromlbl { font-size: 11px; font-weight: 600; color: var(--grey-mid);
           text-transform: lowercase; }

/* Checkout notice: prices that moved while the items sat in the bag. */
.af .repriced { background: #FFF8EC; border: 1px solid #EAD9AE; border-radius: 6px;
                padding: 12px 16px; margin-bottom: 16px; font-size: 13px; color: #7A5B10; }
.af .repriced p { margin: 4px 0 8px; line-height: 1.5; }
.af .repriced-line { display: flex; justify-content: space-between; gap: 12px;
                     padding: 4px 0; border-top: 1px solid rgba(122, 91, 16, .15); }
.af .repriced-line s { color: #81704A; margin-inline-end: 8px; }
.af .repriced-line .up { color: #A6192E; }
.af .repriced-line .down { color: #2E7D32; }

/* ============================================================================
   Bag → Checkout journey

   The whole journey shares one shell: a wide content column with a summary panel
   pinned beside it. The summary is the point - previously the customer entered an
   address with no idea what was in the order or what it cost, and the only way to
   check was to leave checkout. It sticks, so it is on screen at every step.

   Everything below uses design-system tokens only (--red, --grey-*, --radius,
   --shadow-*), so this stays consistent with the rest of the storefront rather
   than being a second look bolted on.
   ============================================================================ */

.af .jshell { max-width: var(--maxw); margin: 0 auto; padding: var(--s5) 20px var(--s8); }
.af .jhead { margin-bottom: var(--s5); }
.af .jhead h1 { font-size: clamp(22px, 3vw, 32px); font-weight: 800; letter-spacing: -.01em; }
.af .jhead .jsub { font-size: 13px; color: var(--grey-mid); margin-top: 4px; }

/* Two columns: the work on the left, the summary pinned on the right. */
.af .jgrid { display: grid; grid-template-columns: minmax(0, 1fr) 348px; gap: var(--s5); align-items: start; }
@media (max-width: 900px) { .af .jgrid { grid-template-columns: minmax(0, 1fr); } }

.af .jmain { display: flex; flex-direction: column; min-width: 0; }

/* ---------- panels ---------- */
.af .jcard { background: #fff; border: 1px solid var(--grey-light); border-radius: 16px;
             padding: var(--s5); }
.af .jcard + .jcard { margin-top: var(--s4); }
.af .jcard h2 { font-size: 15px; font-weight: 700; letter-spacing: -.005em; margin-bottom: var(--s4);
                display: flex; align-items: center; gap: 8px; }
.af .jcard h2 .ico { color: var(--grey-mid); }

/* ---------- selectable option (address, delivery method) ---------- */
.af .opt {
    display: flex; align-items: flex-start; gap: 12px; padding: 16px 16px; cursor: pointer;
    border: 1.5px solid var(--grey-light); border-radius: 10px; margin-bottom: 12px;
    transition: border-color var(--trans), background var(--trans);
}
.af .opt:hover { border-color: #C9C4BE; }
.af .opt.on { border-color: var(--red); background: var(--red-tint); }
.af .opt input[type=radio] { margin-top: 2px; accent-color: var(--red); flex: none; }
.af .opt .obody { flex: 1; min-width: 0; }
.af .opt .otitle { font-weight: 700; font-size: 15px; }
.af .opt .ometa { font-size: 12px; color: var(--grey-mid); margin-top: 4px; line-height: 1.5; }
.af .opt .oprice { font-weight: 700; font-size: 15px; white-space: nowrap; }
.af .opt .odel { background: none; border: 0; color: var(--grey-mid); cursor: pointer; padding: 2px;
                 display: grid; place-items: center; border-radius: 6px; }
.af .opt .odel:hover { color: var(--red); background: rgba(166, 25, 46, .08); }

/* ---------- line items (bag page + summary) ---------- */
.af .jline { display: flex; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--grey-light); }
.af .jline:last-child { border-bottom: 0; }
.af .jthumb {
    width: 72px; height: 72px; flex: none; border-radius: 10px; overflow: hidden;
    background: var(--grey-pale); display: grid; place-items: center;
}
.af .jthumb img { width: 100%; height: 100%; object-fit: cover; }
.af .jthumb .ico { color: var(--grey-mid); }
.af .jbody { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.af .jname { font-size: 15px; font-weight: 600; line-height: 1.4; }
.af .jmeta { font-size: 12px; color: var(--grey-mid); }
.af .jright { display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; gap: 8px; }
.af .jprice { font-weight: 700; font-size: 15px; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Quantity stepper - one pill rather than three loose controls. */
.af .qty { display: inline-flex; align-items: center; border: 1.5px solid var(--grey-light);
           border-radius: 999px; overflow: hidden; }
.af .qty button {
    width: 30px; height: 30px; border: 0; background: none; cursor: pointer; color: var(--grey);
    display: grid; place-items: center; transition: background var(--trans);
}
.af .qty button:hover:not(:disabled) { background: var(--grey-pale); color: var(--red); }
.af .qty button:disabled { opacity: .35; cursor: not-allowed; }
.af .qty .n { min-width: 26px; text-align: center; font-size: 13px; font-weight: 700;
              font-variant-numeric: tabular-nums; }

/* ---------- summary panel ---------- */
.af .jsum { position: sticky; top: 20px; background: #fff; border: 1px solid var(--grey-light);
            border-radius: 16px; overflow: hidden; }
.af .jsum-head { padding: 16px 16px; border-bottom: 1px solid var(--grey-light);
                 display: flex; align-items: center; justify-content: space-between; }
.af .jsum-head h3 { font-size: 15px; font-weight: 700; }
.af .jsum-head .n { font-size: 12px; color: var(--grey-mid); }
.af .jsum-items { max-height: 296px; overflow-y: auto; padding: 4px 16px; }
.af .jsum-items .jline { padding: 12px 0; }
.af .jsum-items .jthumb { width: 52px; height: 52px; border-radius: 6px; }
.af .jsum-items .jname { font-size: 13px; }
.af .jsum-rows { padding: 16px 16px; border-top: 1px solid var(--grey-light); }
.af .jrow { display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
            font-size: 13px; padding: 4px 0; color: var(--grey); }
.af .jrow b { font-weight: 700; color: var(--black); font-variant-numeric: tabular-nums; }
.af .jrow.free b { color: var(--success); }
.af .jrow.disc b { color: var(--red); }
.af .jrow.grand { border-top: 1px solid var(--grey-light); margin-top: 8px; padding-top: 12px;
                  font-size: 15px; font-weight: 700; color: var(--black); }
.af .jrow.grand b { font-size: 22px; }

/* ---------- reassurance strip ---------- */
.af .jtrust { display: flex; flex-direction: column; gap: 8px; padding: 16px 16px;
              border-top: 1px solid var(--grey-light); background: var(--grey-pale);
              list-style: none; margin: 0; }
.af .jtrust li { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--grey); }
.af .jtrust .ico { color: var(--grey-mid); flex: none; }

/* ---------- callouts ---------- */
.af .jnote { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; line-height: 1.5;
             padding: 12px 16px; border-radius: 10px; }
.af .jnote .ico { flex: none; margin-top: 1px; }
.af .jnote.points { background: var(--warning-tint); color: #7A5B10; }
.af .jnote.ok { background: var(--success-tint); color: var(--success); }
.af .jnote.warn { background: #FFF8EC; color: #8A5A10; }
.af .jnote.bad { background: var(--red-tint); color: var(--red); }

/* ---------- actions ---------- */
.af .jactions { display: flex; align-items: center; justify-content: space-between; gap: 12px;
                margin-top: var(--s5); }
.af .jbtn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 12px 24px; border-radius: 10px; font-size: 15px; font-weight: 700;
    border: 1.5px solid transparent; cursor: pointer; text-decoration: none;
    transition: background var(--trans), border-color var(--trans), transform var(--trans);
}
.af .jbtn.primary { background: var(--red); color: #fff; }
.af .jbtn.primary:hover:not(:disabled) { background: var(--red-dark); }
.af .jbtn.ghost { background: #fff; border-color: var(--grey-light); color: var(--grey); }
.af .jbtn.ghost:hover { border-color: var(--grey-mid); color: var(--black); }
.af .jbtn.block { width: 100%; }
.af .jbtn:disabled { opacity: .45; cursor: not-allowed; }
.af .jbtn:active:not(:disabled) { transform: translateY(1px); }
.af .jlink { background: none; border: 0; padding: 0; cursor: pointer; font-size: 13px;
             color: var(--grey-mid); text-decoration: none; display: inline-flex;
             align-items: center; gap: 4px; }
.af .jlink:hover { color: var(--red); }

/* ---------- empty / loading / success states ---------- */
.af .jstate { text-align: center; padding: 64px 20px; }
.af .jstate .art { width: 64px; height: 64px; margin: 0 auto 16px; border-radius: 50%;
                   display: grid; place-items: center; background: var(--grey-pale); color: var(--grey-mid); }
.af .jstate .art.good { background: var(--success-tint); color: var(--success); }
.af .jstate h3 { font-size: 17px; font-weight: 700; margin-bottom: 8px; }
.af .jstate p { font-size: 13px; color: var(--grey-mid); margin-bottom: 20px; }

@media (prefers-reduced-motion: reduce) {
    .af .jbtn, .af .opt, .af .qty button { transition: none; }
}
/* ---------------------------------------------------------------------------
   Savings strip + Apply Coupons popup
   ---------------------------------------------------------------------------
   Coupons and points sit inside the order summary, immediately above the rows
   they change, so the customer never has to leave the total to improve it.
   Each entry has two states - an invitation (.jsave-btn) and a confirmation
   (.jsave-on) - and they occupy the same footprint so applying one does not
   make the panel jump.                                                       */
.af .jsave { padding: 12px 16px; border-top: 1px solid var(--grey-light);
             display: flex; flex-direction: column; gap: 8px; }

.af .jsave-btn, .af .jsave-on {
    display: flex; align-items: center; gap: 12px; width: 100%; text-align: start;
    padding: 12px 12px; border-radius: 10px; border: 1.5px dashed var(--grey-light);
    background: #fff; font: inherit; color: inherit;
}
.af .jsave-btn { cursor: pointer; transition: border-color .16s, background .16s; }
.af .jsave-btn:hover { border-color: var(--red); background: var(--red-tint); }
.af .jsave-on { border-style: solid; border-color: var(--success);
                background: var(--success-tint); }

.af .jsave .ic { flex: none; display: flex; color: var(--red); }
.af .jsave-on .ic { color: var(--success); }
.af .jsave .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.af .jsave .tx b { font-size: 13px; font-weight: 700; }
.af .jsave .tx em { font-size: 11px; font-style: normal; color: var(--grey-mid); }
.af .jsave .tx em.hot { color: var(--red); font-weight: 600; }
.af .jsave-on .tx em { color: var(--success); }
.af .jsave .go { flex: none; color: var(--grey-mid); display: flex; }
.af .jsave-btn:hover .go { color: var(--red); }

/* A quiet aside under the delivery line - not a total, so not a .jrow. */
.af .jhint { font-size: 11px; color: var(--grey-mid); padding: 0 0 8px;
             margin-top: -4px; }

/* --- the popup ----------------------------------------------------------- */
.af .jmodal { position: fixed; inset: 0; z-index: 120; display: flex;
              align-items: center; justify-content: center; padding: 20px;
              background: rgba(20, 18, 17, .55); backdrop-filter: blur(3px);
              animation: jfade .18s ease; }
.af .jmodal-card { width: 100%; max-width: 440px; max-height: 86vh; display: flex;
                   flex-direction: column; background: #fff; border-radius: 16px;
                   overflow: hidden; box-shadow: 0 24px 60px rgba(0, 0, 0, .28);
                   animation: jrise .2s var(--ease); }
.af .jmodal-head { display: flex; align-items: center; justify-content: space-between;
                   gap: 12px; padding: 16px 16px; border-bottom: 1px solid var(--grey-light); }
.af .jmodal-head h3 { display: flex; align-items: center; gap: 8px;
                      font-size: 15px; font-weight: 700; }
.af .jmodal-x { background: none; border: 0; cursor: pointer; padding: 4px; display: flex;
                border-radius: 6px; color: var(--grey-mid); }
.af .jmodal-x:hover { color: var(--red); background: var(--red-tint); }
.af .jmodal-body { padding: 16px 16px 20px; overflow-y: auto; }

@keyframes jfade { from { opacity: 0; } }
@keyframes jrise { from { opacity: 0; transform: translateY(14px) scale(.98); } }

/* --- one offer, drawn as a ticket ---------------------------------------- */
.af .cpns { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }
.af .cpn { display: flex; align-items: stretch; gap: 12px; padding: 12px;
           border: 1.5px solid var(--grey-light); border-radius: 10px; background: #fff; }
.af .cpn.off { background: var(--grey-pale); border-style: dashed; }

/* The stub is the torn-off half of a paper coupon: the perforation is the dashed
   inline-end border, and the two notches are what a punch would leave behind. */
.af .cpn-stub { position: relative; flex: none; width: 92px; padding-inline-end: 12px;
                border-inline-end: 1.5px dashed var(--grey-light);
                display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.af .cpn-stub::before, .af .cpn-stub::after {
    content: ""; position: absolute; inset-inline-end: -6px; width: 10px; height: 10px;
    border-radius: 50%; background: #fff; border: 1.5px solid var(--grey-light);
}
.af .cpn-stub::before { top: -7px; }
.af .cpn-stub::after { bottom: -7px; }
.af .cpn-stub .v { font-size: 15px; font-weight: 800; color: var(--red); line-height: 1.2; }
.af .cpn.off .cpn-stub .v { color: var(--grey-mid); }
.af .cpn-stub .c { font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
                   color: var(--grey-mid); font-weight: 700; }

.af .cpn-body { flex: 1; min-width: 0; display: flex; flex-direction: column;
                justify-content: center; gap: 4px; }
.af .cpn-name { font-size: 13px; font-weight: 700; }
.af .cpn-meta { font-size: 11px; color: var(--grey-mid); }
.af .cpn-meta.win { color: var(--success); font-weight: 600; }
.af .cpn-act { flex: none; display: flex; align-items: center; }
.af .jbtn.sm { padding: 8px 16px; font-size: 12px; }

@media (max-width: 520px) {
    .af .cpn-stub { width: 76px; }
}

@media (prefers-reduced-motion: reduce) {
    .af .jmodal, .af .jmodal-card { animation: none; }
    .af .jsave-btn { transition: none; }
}
/* ---------------------------------------------------------------------------
   Legal pages (Privacy Policy, Terms & Conditions)
   ---------------------------------------------------------------------------
   A prose column, not a layout. These pages exist to be read start to finish -
   so the measure is capped near 70 characters, headings are quiet enough to
   scan without shouting, and nothing competes with the text.

   Scoped .af.legal (both classes on one element) rather than .af .legal, the
   same way .af.acct is, so .wrap here cannot reach any other page's .wrap.   */
.af.legal .wrap { max-width: 820px; margin: 0 auto; padding: 24px 20px 64px; }
.af.legal .crumb { font-size: 13px; color: var(--grey-mid); margin-bottom: 16px; }
.af.legal .crumb a { color: var(--grey-mid); text-decoration: none; }
.af.legal .crumb a:hover { color: var(--red); }

.af.legal h1 { font-size: 32px; font-weight: 800; letter-spacing: -.01em; line-height: 1.2; }
.af.legal .lead { font-size: 13px; color: var(--grey-mid); margin-top: 8px;
                  padding-bottom: 20px; border-bottom: 1px solid var(--grey-light); }

.af.legal section { margin-top: 32px; }
.af.legal h2 { font-size: 17px; font-weight: 700; color: var(--black); margin-bottom: 12px; }
.af.legal p { font-size: 15px; line-height: 1.75; color: var(--grey); max-width: 70ch; }
.af.legal p + p { margin-top: 12px; }
.af.legal a { color: var(--red); }

.af.legal ul { margin: 12px 0 16px; padding: 0; list-style: none; max-width: 70ch; }
.af.legal li { position: relative; font-size: 15px; line-height: 1.7; color: var(--grey);
               padding-inline-start: 16px; padding-block: 4px; }
/* A marker drawn rather than a list bullet, so it stays on the correct side in Arabic. */
.af.legal li::before { content: ""; position: absolute; inset-inline-start: 2px; top: 12px;
                       width: 5px; height: 5px; border-radius: 50%; background: var(--red); }

/* The one passage the supplied copy singles out. Bordered rather than badged - the
   original carried a warning emoji, which this project does not use as iconography. */
.af.legal .callout { margin-top: 32px; padding: 16px 20px; border-radius: 10px;
                     background: var(--warning-tint); border: 1px solid #EBD9A8;
                     border-inline-start: 4px solid var(--warning); }
.af.legal .callout h2 { color: #7A5B10; }
.af.legal .callout p { color: #6B5210; }

.af.legal .legal-foot { margin-top: 36px; padding-top: 16px;
                        border-top: 1px solid var(--grey-light); }
.af.legal .legal-foot p { font-size: 13px; color: var(--grey-mid); }

@media (max-width: 620px) {
    .af.legal h1 { font-size: 26px; }
}

/* Per-line stock hints in the bag. Sits beside the quantity stepper, because that is
   the control the number constrains - a message anywhere else would be about the
   product rather than about the choice being made. */
.af .stk { display: inline-flex; align-items: center; gap: 4px; margin-inline-start: 12px;
           font-size: 12px; font-weight: 600; vertical-align: middle; }
.af .stk.low { color: var(--grey-mid); font-weight: 500; }
.af .stk.out { color: var(--red); }
/* The over-stocked one is a button: it says what is wrong AND fixes it in one click. */
.af .stk.fix { color: var(--red); background: var(--red-tint); border: 0; cursor: pointer;
               padding: 4px 8px; border-radius: 999px; font-family: inherit; }
.af .stk.fix:hover { background: var(--red); color: #fff; }

/* A capped stepper has to look capped, or it reads as broken. */
.af .qty button:disabled, .af .cqty .stepbtn:disabled { opacity: .35; cursor: not-allowed; }

/* ---------------------------------------------------------------------------
   Address picker (.apick)

   Search, confirm on a map, then the one line the map cannot know. Everything
   here is on the type scale, the 4px grid and the radius ladder documented at
   the top of this file.

   The map panel is deliberately NOT a convincing fake. It is a flat tinted
   surface with a faint grid and a pin, and it carries a line of text saying the
   live map arrives with the API key. A reviewer should never look at a
   screenshot of this and think the integration is done.
   --------------------------------------------------------------------------- */
.af .apick { display: flex; flex-direction: column; gap: 16px; }
.af .apick-field { display: flex; flex-direction: column; gap: 4px; position: relative; }
.af .apick-field > label {
    font-size: 12px; font-weight: 600; letter-spacing: .05em;
    text-transform: uppercase; color: var(--grey-mid);
}
.af .apick-fields { display: flex; flex-direction: column; gap: 16px; }

/* ---- the search box ---- */
.af .apick-search { position: relative; display: flex; align-items: center; }
.af .apick-search .ic {
    position: absolute; inset-inline-start: 12px; display: flex;
    color: var(--grey-mid); pointer-events: none;
}
.af .apick-search .input { padding-inline-start: 36px; }

/* ---- suggestions ---- */
.af .apick-list {
    position: absolute; inset-block-start: calc(100% + 4px); inset-inline: 0; z-index: 40;
    margin: 0; padding: 4px 0; list-style: none;
    background: #fff; border: 1px solid var(--grey-light); border-radius: 10px;
    box-shadow: var(--shadow-2); max-height: 280px; overflow-y: auto;
}
.af .apick-list button {
    display: flex; align-items: flex-start; gap: 12px; width: 100%;
    padding: 8px 12px; border: 0; background: none; cursor: pointer; text-align: start;
}
.af .apick-list button:hover, .af .apick-list button:focus-visible { background: var(--grey-pale); }
.af .apick-list .ic { color: var(--grey-mid); flex: none; margin-top: 2px; }
.af .apick-list .tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.af .apick-list .tx b { font-size: 13px; font-weight: 600; }
.af .apick-list .tx em { font-size: 12px; font-style: normal; color: var(--grey-mid); }

.af .apick-none { font-size: 13px; color: var(--grey-mid); margin: 4px 0 0; }

/* ---- the placeholder map ---- */
.af .apick-map {
    position: relative; height: 180px; border-radius: 10px; overflow: hidden;
    background: var(--grey-pale); border: 1px solid var(--grey-light);
    display: grid; place-items: center;
}
.af .apick-grid {
    position: absolute; inset: 0;
    background-image: linear-gradient(var(--grey-light) 1px, transparent 1px),
                      linear-gradient(90deg, var(--grey-light) 1px, transparent 1px);
    background-size: 32px 32px; opacity: .55;
}
.af .apick-pin {
    position: relative; border: 0; background: none; cursor: pointer;
    color: var(--red); display: grid; place-items: center;
    padding: 8px; border-radius: 999px;
}
.af .apick-pin:hover { background: rgba(255, 255, 255, .7); }
.af .apick-pin:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.af .apick-hint {
    position: absolute; inset-block-end: 32px; margin: 0;
    font-size: 12px; color: var(--grey);
}
.af .apick-stub {
    position: absolute; inset-block-end: 8px; inset-inline: 8px; margin: 0;
    font-size: 11px; color: var(--grey-mid); text-align: center;
}
.af .apick-coords { margin: 0; font-size: 12px; color: var(--grey-mid); }
.af .apick-coords .mono { font-variant-numeric: tabular-nums; }

.af .apick-note { margin: 0; font-size: 12px; color: var(--grey-mid); }
.af .apick-alt { margin: 0; font-size: 13px; color: var(--grey-mid); }
.af .apick-link {
    border: 0; background: none; padding: 0; cursor: pointer;
    font: inherit; color: var(--red); font-weight: 600;
    display: inline-flex; align-items: center; gap: 4px;
}
.af .apick-link:hover { text-decoration: underline; }
