﻿/*
 * Storefront overrides for the Ecom v5.0 Book Store theme.
 *
 * Loaded after the Ecom stylesheet, so almost nothing in the licensed theme has to be edited. It holds the two
 * web fonts, the direction-aware type stacks, the Persian typography, the accessibility corrections the
 * conversion needed, the mirrored carousel controls, and the styling of the few controls that were changed
 * from a div or a span into a real button.
 *
 * The copied Ecom stylesheets carry exactly one modification, which could not be expressed as an override: the
 * `@import` of a remote web font was deleted from each build. Left in place it fetched DM Sans from a
 * third-party host on every request — fonts.bunny.net in the left-to-right build and fonts.googleapis.com in
 * the right-to-left one — which discloses the visitor to that host and simply fails where those hosts are
 * unreachable. The same faces are served from this application instead, declared below.
 */

/* ------------------------------------------------------------------ *
 * 0. Latin web font
 *
 * DM Sans is the family the Ecom design was drawn with, self-hosted here under its SIL Open Font License so
 * the deployed application makes no outbound request. It is a variable font covering the whole 400 to 700
 * axis in one file per subset, which means weight 500 is a real Medium rather than the nearest static face.
 * ------------------------------------------------------------------ */

@font-face {
    font-family: "DM Sans";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/dmsans/dm-sans-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
                   U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "DM Sans";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/dmsans/dm-sans-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
                   U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------------ *
 * 1. Persian web font
 *
 * IRANYekanX (SemiPro) ships Light, Regular, Bold, Black and ExtraBlack, with no Medium and no SemiBold.
 * The Book Store page only asks for weights 300 to 700, so exactly the two faces it can honour are declared.
 * Weight 500 therefore resolves to Regular and weight 600 to Bold through normal CSS font matching, which
 * keeps every declared weight backed by a real file instead of a synthesised one.
 *
 * Only the WOFF2 build of each face is shipped. Every browser that can run this application supports it, so a
 * second copy of each face in the older format would be downloaded by nobody.
 * ------------------------------------------------------------------ */

@font-face {
    font-family: "IRANYekanX";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/iranyekanx/IRANYekanX-Regular.woff2") format("woff2");
}

@font-face {
    font-family: "IRANYekanX";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/iranyekanx/IRANYekanX-Bold.woff2") format("woff2");
}

/* ------------------------------------------------------------------ *
 * 2. Direction-aware type stacks
 *
 * Ecom hard-codes its Latin family in over a hundred rules instead of letting it inherit, and some of those
 * rules are more specific than any selector list that could be written here — `.header .main-menu li a`, for
 * example. A list of selectors therefore leaves holes, and a hole means Persian text rendered in a family
 * that has no Persian glyphs. The family is instead redirected once, for every element, and the direction
 * chooses which family that is. Icon glyphs are unaffected because both icon fonts are applied to `::before`
 * and `::after`, which an element selector cannot reach.
 * ------------------------------------------------------------------ */

:root {
    --store-font-latin: "DM Sans", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
    --store-font-persian: "IRANYekanX", "Segoe UI", Tahoma, Arial, sans-serif;
    --store-font-ui: var(--store-font-latin);
}

html[dir="rtl"] {
    --store-font-ui: var(--store-font-persian);

    /* Letter spacing is a Latin typesetting device and damages connected Persian script. It is
       declared here, with the other root-level right-to-left overrides, rather than in the
       typography section below: two rules on one selector is a duplicate the next reader has to
       diff before they can trust either. */
    letter-spacing: normal;
}

body,
body * {
    font-family: var(--store-font-ui) !important;
}

/*
 * The page direction cannot decide the face for text that is not in the page's language. The language
 * switcher is the clear case: the English page offers "فارسی" and the Persian page offers "English", and
 * each of those words needs the face of its own language rather than the face of the page around it.
 * Every such element declares its language, so the declared language selects the face.
 */
body [lang|="fa"] {
    font-family: var(--store-font-persian) !important;
}

body [lang|="en"] {
    font-family: var(--store-font-latin) !important;
}

/* ------------------------------------------------------------------ *
 * 3. Persian typography
 *
 * Persian glyphs are taller than Latin ones and carry descenders that the Ecom line heights, tuned for
 * 14px DM Sans, clip. Line heights are opened up per text role; nothing else about the design changes.
 * ------------------------------------------------------------------ */

html[dir="rtl"] body {
    line-height: 1.9;
}

html[dir="rtl"] p,
html[dir="rtl"] li,
html[dir="rtl"] .menu-footer li a,
html[dir="rtl"] .list-links-disc li a {
    line-height: 2;
}

html[dir="rtl"] .font-xs,
html[dir="rtl"] .font-xs-bold {
    line-height: 22px !important;
}

html[dir="rtl"] .font-sm,
html[dir="rtl"] .font-sm-bold {
    line-height: 26px !important;
}

html[dir="rtl"] .font-md,
html[dir="rtl"] .font-md-bold {
    line-height: 30px !important;
}

html[dir="rtl"] .font-base {
    line-height: 28px !important;
}

html[dir="rtl"] .font-lg,
html[dir="rtl"] .font-lg-bold {
    line-height: 34px;
}

html[dir="rtl"] h1 {
    line-height: 1.5;
}

html[dir="rtl"] h2,
html[dir="rtl"] h3 {
    line-height: 1.6;
}

html[dir="rtl"] h4,
html[dir="rtl"] h5,
html[dir="rtl"] h6 {
    line-height: 1.7;
}

html[dir="rtl"] .header .main-menu li a,
html[dir="rtl"] .header .main-menu li .store-menu-trigger {
    line-height: 28px;
}

/* Capitalisation is a Latin typesetting device and damages connected Persian script. */
html[dir="rtl"] .uppercase,
html[dir="rtl"] .capitalize,
html[dir="rtl"] .text-uppercase,
html[dir="rtl"] .btn.btn-arrow,
html[dir="rtl"] .btn.btn-link-brand-2,
html[dir="rtl"] .mobile-menu li a,
html[dir="rtl"] .mobile-account ul li a {
    text-transform: none;
    letter-spacing: normal;
}

/* The Persian labels are longer than the English ones, so the buttons are allowed to grow with their text. */
html[dir="rtl"] .btn {
    white-space: normal;
}

/* ------------------------------------------------------------------ *
 * 4. Accessibility corrections
 * ------------------------------------------------------------------ */

.store-skip-link {
    position: absolute;
    inset-inline-start: -9999px;
    top: 0;
    z-index: 2000;
    padding: 12px 20px;
    background-color: #ffffff;
    color: #0E224D;
    font-weight: 700;
}

.store-skip-link:focus {
    inset-inline-start: 0;
}

/*
 * Bootstrap removes the focus ring from its own controls with `.btn:focus-visible { outline: 0 }`, so this
 * rule has to out-specify that rather than sit inside `:where()`, which would give it no specificity at all.
 */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
.btn:focus-visible {
    outline: 3px solid #FD9636;
    outline-offset: 2px;
}

/*
 * Ecom opens its drop-down menus on hover alone. The trigger of each menu is a button here, and the script
 * toggles this class on its list item, which is what makes the menu reachable without a pointer while the
 * button's reported state stays truthful.
 */
.header .main-menu li.store-submenu-open > ul {
    opacity: 1;
    visibility: visible;
}

/* An anchor without a destination is a placeholder, so it must not offer a link affordance. */
.store-link-pending {
    cursor: default;
}

/*
 * The hero headline is a level-two heading rather than the level-one heading Ecom uses, because the slider
 * duplicates its slides at runtime and a page must not end up with several level-one headings. The Ecom hero
 * metrics are restored here so the correction changes nothing visually.
 */
.box-banner-big .store-hero-headline {
    font-size: 64px;
    line-height: 83px;
}

@media (max-width: 1199.98px) {
    .box-banner-big .store-hero-headline {
        font-size: 44px;
        line-height: 56px;
    }
}

@media (max-width: 575.98px) {
    .box-banner-big .store-hero-headline {
        font-size: 32px;
        line-height: 42px;
    }
}

/* Footer column headings are level-two headings so the outline does not skip a level; Ecom sizes them as h4. */
.footer .store-footer-heading {
    font-size: 24px;
    line-height: 31px;
}

/* Both size corrections above restate Ecom's Latin line heights, which are too tight for Persian glyphs. */
html[dir="rtl"] .box-banner-big .store-hero-headline {
    line-height: 1.5;
}

html[dir="rtl"] .footer .store-footer-heading {
    line-height: 1.7;
}

/* ------------------------------------------------------------------ *
 * 5. Controls promoted from a div or a span to a real button
 *
 * The Ecom markup drives its menu, its drawer and its header dropdowns from non-interactive elements. Those
 * became buttons during the conversion, so the button defaults are removed and the Ecom look is restored.
 * ------------------------------------------------------------------ */

.store-menu-trigger,
.store-action-trigger,
.burger-icon,
.store-drawer-close {
    appearance: none;
    background: none;
    border: 0;
    text-align: inherit;
    font: inherit;
    color: inherit;
}

.header .main-menu li .store-menu-trigger {
    font-size: 16px;
    font-weight: 400;
    color: #425A8B;
    display: block;
    padding: 13px 12px 13px 12px;
    position: relative;
    cursor: pointer;
}

.header .main-menu li .store-menu-trigger:hover {
    color: #FD9636;
}

/* Ecom draws the drop-down chevron from an anchor pseudo-element; the button gets the same glyph. */
.header .main-menu li.has-children > .store-menu-trigger::after {
    content: "\f151";

    /* The generic family is the browser's instruction for the moment the icon font has not
       arrived: the chevron is decoration, so a missing glyph degrades the menu rather than
       breaking it. */
    font-family: uicons-regular-rounded, sans-serif !important;
    font-style: normal;
    font-weight: normal !important;
    font-variant: normal;
    line-height: 1 !important;
    font-size: 14px;
    position: relative;
    top: 2px;
}

.header .main-header .header-left .header-shop .store-action-trigger,
.header .main-header .header-left .header-shop .store-action-static {
    padding: 0px 15px 0px 30px;
    cursor: pointer;
}

.header .main-header .header-left .header-shop .store-action-static {
    cursor: default;
}

.burger-icon {
    padding: 0;
}

/* The drawer sub-menus are opened by a class instead of by a script-driven slide animation. */
.mobile-menu-wrap .mobile-menu .sub-menu {
    display: none;
}

.mobile-menu-wrap .mobile-menu li.store-submenu-open > .sub-menu {
    display: block;
}

.mobile-menu-wrap .mobile-menu li .store-menu-trigger {
    display: block;
    width: 100%;
    cursor: pointer;
}

.mobile-menu-wrap .mobile-menu li.has-children > .store-menu-trigger::after {
    content: "\f151";
    font-family: uicons-regular-rounded, sans-serif !important;
    font-weight: normal !important;
    font-size: 14px;
    float: inline-end;
}

.mobile-menu-wrap .mobile-menu li.store-submenu-open > .store-menu-trigger::after {
    content: "\f113";
}

.mobile-logo {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.store-drawer-close {
    font-size: 28px;
    line-height: 1;
    padding: 4px 10px;
    cursor: pointer;
}

/* ------------------------------------------------------------------ *
 * 6. Direction-sensitive carousel controls
 *
 * Ecom's right-to-left build moves some arrow groups to the other side of their band but never mirrors the
 * pair itself: the forward control keeps its place on the right of its partner and keeps a right-pointing
 * chevron. Swiper already inverts the motion for right-to-left reading, so only the presentation is left to
 * correct, and correcting it is what makes the sliders read forwards to a Persian visitor.
 *
 * Only the arrows are mirrored. Icons that carry no direction — the star rating, the account, wishlist, cart
 * and service icons — are identical in both Ecom builds and are deliberately left alone.
 * ------------------------------------------------------------------ */

/* Ecom's right-to-left build never mirrored the float of the main menu: `.header .main-menu li` carries
   `float: left` in both builds, so the first entry lands at the left edge and the menu reads away from the
   reading start. Home belongs at the right in Persian, with the rest following leftwards. The float is
   mirrored rather than the list turned into a flex row, because the theme positions each submenu against
   its own `position: relative` list item and a layout change would move those too. */
html[dir="rtl"] .header .main-menu li {
    float: right;
}

html[dir="rtl"] .box-button-slider {
    transform: scaleX(-1);
}

html[dir="rtl"] .pick-by-ecom .swiper-button-next-ecom {
    right: auto;
    left: -75px;
    transform: scaleX(-1);
}

html[dir="rtl"] .pick-by-ecom .swiper-button-prev-ecom {
    left: auto;
    right: -75px;
    transform: scaleX(-1);
}

html[dir="rtl"] .box-slider-item .swiper-button-next-style-2,
html[dir="rtl"] .box-slider-item .swiper-button-next-style-2:hover {
    left: 0px;
    background-position: top center;
    transform: scaleX(-1);
}

html[dir="rtl"] .box-slider-item .swiper-button-prev-style-2,
html[dir="rtl"] .box-slider-item .swiper-button-prev-style-2:hover {
    left: 20px;
    background-position: top center;
    transform: scaleX(-1);
}

/*
 * Ecom hangs the arrows of the curated band 75px outside a container that is already 1100px wide, so they
 * leave the viewport on every screen narrower than roughly 1250px. Below that width they move inside.
 */
@media (max-width: 1249.98px) {
    .pick-by-ecom .swiper-button-next-ecom {
        right: 0px;
    }

    .pick-by-ecom .swiper-button-prev-ecom {
        left: 0px;
    }

    html[dir="rtl"] .pick-by-ecom .swiper-button-next-ecom {
        right: auto;
        left: 0px;
    }

    html[dir="rtl"] .pick-by-ecom .swiper-button-prev-ecom {
        left: auto;
        right: 0px;
    }
}

/* ------------------------------------------------------------------ *
 * 7. Native search filter
 *
 * Ecom replaces the category element with a script-driven widget. The native element is kept, so it is styled
 * to match the Ecom search bar instead.
 * ------------------------------------------------------------------ */

.box-header-search .store-search-category {
    border: 0;
    background-color: transparent;
    color: #425A8B;
    font-size: 14px;
    height: 100%;
    min-width: 140px;
    max-width: 180px;
    padding-inline: 12px 26px;
    cursor: pointer;
}

.box-header-search .form-search {
    display: flex;
    align-items: stretch;
}

/* ------------------------------------------------------------------ *
 * 8. Brand mark
 * ------------------------------------------------------------------ */

.store-brand-mark {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    text-decoration: none;
}

/*
 * Ecom sizes its logo box at 150px and relies on the whitespace inside its own logo file to keep the mark
 * clear of the search field. The Ganjineh artwork fills its box edge to edge, so the separation has to be
 * real spacing, and the box is widened a little so the wordmark is not squeezed to fit.
 */
.header .main-header .header-left .header-logo {
    max-width: 184px;
    margin-inline-end: 28px;
}

@media (max-width: 1199.98px) {
    .header .main-header .header-left .header-logo {
        margin-inline-end: 16px;
    }
}

/* The logo is one piece of artwork, so it is sized by height and left to keep its own proportions. */
.store-brand-mark-logo {
    block-size: 52px;
    inline-size: auto;
    max-inline-size: 100%;
}

.store-brand-mark-footer .store-brand-mark-logo {
    block-size: 60px;
}

@media (max-width: 575.98px) {
    .store-brand-mark-logo {
        block-size: 42px;
    }
}

.store-brand-mark-tagline {
    font-size: 12px;
    color: #8C9EC5;
}

/* ------------------------------------------------------------------ *
 * 9. Layout guards
 *
 * Persian labels run longer than their English counterparts, so the bands that Ecom sizes for English text
 * are allowed to wrap rather than to push a horizontal scrollbar onto the page.
 * ------------------------------------------------------------------ */

body {
    overflow-x: hidden;
}

/*
 * The Ecom header is one row: its zones are flex items that shrink to fit. Letting them wrap instead drops
 * the account and cart block onto a second line, so only the top bar, which really is a set of independent
 * blocks, is allowed to wrap.
 */
.topbar .container-topbar {
    flex-wrap: wrap;
}

.list-col-5 {
    flex-wrap: wrap;
}

.card-grid-style-2 .info-right a,
.card-grid-style-3 .info-right a,
.menu-footer li a {
    overflow-wrap: anywhere;
}

img {
    max-width: 100%;
    height: auto;
}

/* ------------------------------------------------------------------ *
 * 10. Authentication surfaces
 *
 * The sign-out action is a form post rather than a link, so the submit button inside the account
 * menus takes on the appearance the Ecom stylesheet gives the surrounding anchor entries. Email and
 * password values are Latin-script data even on the Persian pages, so those inputs keep a
 * left-to-right inline direction while their form stays part of the right-to-left layout.
 * ------------------------------------------------------------------ */

.store-signout-form {
    margin: 0;
}

.store-signout-button {
    background: none;
    border: 0;
    padding: 0;
    width: 100%;
    text-align: start;
    font-family: inherit;
    font-size: inherit;
    color: inherit;
    cursor: pointer;
}

.dropdown-account .store-signout-button {
    display: block;
    padding: 5px 0;
}

/* The theme highlights the sibling anchor entries on hover; the button follows the same accent. */
.dropdown-account .store-signout-button:hover {
    color: #0BA9ED;
}

.mobile-account .store-signout-button {
    display: block;
    padding: 6px 0;
    text-transform: capitalize;
    font-size: 14px;
    line-height: 1;
}

/* Capitalisation is a Latin typesetting device; the Persian drawer entries never use it. */
html[dir="rtl"] .mobile-account .store-signout-button {
    text-transform: none;
}

/* The account tab bar's sign-out entry is a form post; the button mirrors the theme's tab-link look. */
.nav-tabs-account .store-signout-form {
    display: inline-block;
}

.nav-tabs-account .store-signout-button {
    display: inline-block;
    width: auto;
    padding: 0px 10px;
    font-size: 16px;
    line-height: 24px;
    color: #8C9EC5;
}

.nav-tabs-account .store-signout-button:hover {
    color: #425A8B;
}

.store-input-latin {
    direction: ltr;
    unicode-bidi: plaintext;
}

html[dir="rtl"] input.store-input-latin {
    text-align: left;
}

html[dir="rtl"] .form-register .checkagree {
    float: right;
    margin: 2px 0 0 10px;
}

/* ------------------------------------------------------------------ *
 * Product page type scale
 *
 * The Ecom product template titles the product with an `h3` and prints its price inside another one,
 * because the template's own page heading lives elsewhere and a price is not a heading at all. The
 * converted page has no other heading, so the product name has to be the `h1` — and an `h1` in this
 * theme is the 64-pixel hero size, roughly twice what the design draws a product title at, while an
 * `h2` is 45 pixels.
 *
 * The heading level is the semantics and the size is the design, so the levels stay where the document
 * outline needs them and the sizes come back to the template's, including at the one breakpoint the
 * theme shrinks its own `h3` at. The price keeps the template's size without being a heading at all.
 * ------------------------------------------------------------------ */

.store-heading-lg {
    font-size: 32px;
    line-height: 41px;
}

.store-heading-md {
    font-size: 24px;
    line-height: 31px;
}

.store-heading-sm {
    font-size: 20px;
    line-height: 27px;
}

.store-product-price {
    font-weight: bold;
    margin-bottom: 0;
}

/* The editorial sections of a product page are prose rather than the fixed-height teaser the theme
   draws a short description in, so they are not wrapped in the template's clipped block: a section
   the reader can only see the first hundred pixels of is a section nobody reads. Paragraph breaks
   are preserved because the text is stored as plain text and its line breaks are the author's. */
.store-editorial-body {
    white-space: pre-line;
}

@media (max-width: 499.98px) {
    .store-heading-lg {
        font-size: 22px;
        line-height: 31px;
    }
}

/* ------------------------------------------------------------------ *
 * 11. Catalog listing
 *
 * The listing pages are the Ecom `shop-grid` layout with everything the platform cannot back removed: no
 * rating strip, no struck-through reference price, no discount label, no hover tool rail, no add-to-cart
 * button, no price slider, no colour swatches. What is left needs a little styling of its own, because the
 * controls the theme drew with script — a drop-down of links for the sort, a modal for the filters — are
 * native form controls here.
 *
 * Every rule uses logical properties, so the same declaration reads correctly in both directions and neither
 * build of the licensed stylesheet is edited.
 * ------------------------------------------------------------------ */

/* The card is a fixed-height picture box with the text under it, which is what keeps a grid row aligned
   whatever proportions a cover happens to have. */
.store-product-card .image-box {
    display: flex;
    align-items: center;
    justify-content: center;
    block-size: 200px;
    line-height: normal;
    inline-size: 100%;
    overflow: hidden;
}

.store-product-card .image-box img {
    max-block-size: 100%;
    max-inline-size: 100%;
    inline-size: auto;
    block-size: auto;
    object-fit: contain;
}

.store-product-card .info-right {
    display: block;
    inline-size: 100%;
    padding-inline: 0;
}

.store-product-card .price-info {
    margin-block-start: 8px;
}

/* Competition credit is not a price. It is written smaller, under the price, introduced by a word that says
   what it is, and it never crosses anything out. */
.store-product-card-credit {
    margin-block: 6px 0;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: baseline;
}

.store-product-grid {
    align-items: stretch;
}

.store-product-grid > [class*="col-"] {
    display: flex;
    margin-block-end: 24px;
}

.store-product-grid .card-grid-style-3 {
    inline-size: 100%;
}

/* The toolbar: the theme's own band, with native controls instead of the script-driven drop-downs. */
.store-catalog-toolbar-form {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    justify-content: flex-end;
}

.store-catalog-toolbar-field {
    display: inline-flex;
    gap: 6px;
    align-items: center;
}

.store-catalog-select {
    border: 1px solid #E0E6F7;
    border-radius: 4px;
    background-color: #FFFFFF;
    color: #425A8B;
    font-size: 14px;
    padding: 6px 10px;
    cursor: pointer;
}

.store-catalog-apply {
    padding: 8px 18px;
    font-size: 14px;
}

/* The filter panel is the theme's sidebar card, with the groups marked up as fieldsets so assistive
   technology announces which group a box belongs to. */
.store-catalog-filters {
    display: block;
}

.store-catalog-filter-group {
    border: 0;
    margin: 0 0 20px;
    padding: 0;
    min-inline-size: 0;
}

.store-catalog-filter-title,
.store-catalog-filter-heading {
    font-size: 16px;
    line-height: 24px;
    font-weight: bold;
    margin-block: 0 10px;
    padding: 0;
    float: none;
    inline-size: auto;
}

.store-catalog-filter-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    margin-block-start: 10px;
}

.store-catalog-number {
    max-inline-size: 180px;
}

/* The summary of what the visitor chose, and the link that unmakes each choice. */
.store-catalog-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.store-catalog-chip {
    padding: 4px 12px;
    font-size: 13px;
}

.store-catalog-empty {
    padding-block: 60px;
}

.store-catalog-empty-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    justify-content: center;
}

/* On a narrow screen the panel reflows underneath the products, so the toolbar carries a jump to it. */
.store-catalog-filter-jump {
    margin-block: 12px 0;
}

/* Credit shelf tiles: a percentage and what it means, with nothing invented around it. */
.store-credit-shelf-tile {
    display: flex;
    flex-direction: column;
    gap: 4px;
    align-items: center;
    justify-content: center;
    text-align: center;
    border: 1px solid #E0E6F7;
    border-radius: 8px;
    padding: 24px 12px;
    margin-block-end: 20px;
    text-decoration: none;
}

.store-credit-shelf-tile:hover {
    border-color: #C5CBE0;
}

.store-credit-shelf-percentage {
    font-size: 24px;
    line-height: 32px;
    font-weight: bold;
}

/* Product world tiles on the home page. */
.store-world-tile {
    display: flex;
    flex-direction: column;
    gap: 6px;
    border: 1px solid #E0E6F7;
    border-radius: 8px;
    padding: 20px;
    margin-block-end: 20px;
    text-decoration: none;
}

.store-world-tile:hover {
    border-color: #C5CBE0;
}

.store-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

/* The header search gained a real submit button, which the theme's decorative form had no room for. */
.box-header-search .store-search-submit {
    border-radius: 0;
    padding: 0 18px;
    font-size: 14px;
    white-space: nowrap;
}

/* ------------------------------------------------------------------ *
 * Product gallery
 *
 * Every picture beyond the first is shown beneath the leading one rather than behind a slider rail: a rail that
 * needs script to reach the second picture hides it from anybody the script did not run for.
 * ------------------------------------------------------------------ */

.store-product-gallery {
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.store-product-gallery img {
    inline-size: 96px;
    block-size: auto;
    border-radius: 8px;
    background-color: #f4f6fa;
}

/* ------------------------------------------------------------------ *
 * 12. Cart
 *
 * The Ecom cart page lays its rows out with the wishlist classes, whose widths assume six cells including a
 * selection checkbox this platform does not have. The row is laid out here instead, as a grid that becomes a
 * stack below the large breakpoint, so a cart is usable on a telephone rather than a table somebody has to
 * scroll sideways. Everything visual - the type scale, the colours, the buttons - still comes from the theme.
 *
 * The theme's plus and minus glyphs are background images this repository does not vendor, so the quantity is
 * a box the shopper types into with a button beside it. That also makes it work without script, which the
 * theme's jQuery stepper does not.
 * ------------------------------------------------------------------ */

.store-cart-head,
.store-cart-line .item-wishlist {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1.2fr) minmax(0, 0.8fr);
    gap: 16px;
    align-items: center;
}

.store-cart-head {
    padding-block: 12px;
    border-block-end: 1px solid #e5e8ec;
}

.store-cart-line {
    padding-block: 18px;
    border-block-end: 1px solid #eef1f5;
}

/* A line that cannot be bought is marked by a bar on the reading edge as well as by its own sentence, so the
   state is never carried by colour alone. */
.store-cart-line-blocked {
    border-inline-start: 3px solid #fd9636;
    padding-inline-start: 12px;
}

.store-cart-line-issue {
    color: #c8102e;
    margin-block: 6px 0;
}

.store-cart-line .product-wishlist {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.store-cart-line .product-image img {
    inline-size: 72px;
    block-size: auto;
    border-radius: 8px;
    background-color: #f4f6fa;
}

.store-cart-quantity-form {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.store-cart-quantity {
    inline-size: 72px;
    text-align: center;
}

.store-cart-quantity-submit,
.store-cart-remove {
    white-space: nowrap;
}

.store-cart-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    margin-block-start: 24px;
}

.store-cart-summary {
    padding: 20px;
}

/* The theme's coupon row spaces its box from its button with a physical margin, which would sit on the wrong side
   in a right-to-left page; a gap is the same space on whichever side the button falls. */
.store-cart-coupon-row {
    gap: 15px;
}

.store-cart-coupon-row .form-control {
    flex: 1 1 auto;
    min-width: 0;
}

/* The right-to-left build lets every button wrap, which would break a two-word Persian label beside the box. */
.store-cart-coupon-row .btn {
    flex: 0 0 auto;
    white-space: nowrap;
}

.store-cart-coupon-code {
    letter-spacing: 0.05em;
}

.store-coupon-minimum,
.store-order-promotion-code {
    margin-inline-start: 0.25em;
}

/* A line a promotion reached shows what came off it and what it comes to after, under the line's own figure. */
.store-cart-line-discount {
    display: block;
}

.store-cart-summary-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding-block-end: 10px;
}

.store-cart-attention {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
    padding: 12px 16px;
    margin-block-end: 20px;
    border-inline-start: 3px solid #fd9636;
    background-color: #fff7ee;
    border-radius: 8px;
}

/* The two outcomes differ by a word and by a border as well as by colour. */
.store-cart-message {
    padding: 10px 16px;
    margin-block-end: 20px;
    border-radius: 8px;
    border-inline-start: 3px solid transparent;
}

.store-cart-message-done {
    border-inline-start-color: #2f9e44;
    background-color: #f1f8f3;
    color: #1c6b30;
}

.store-cart-message-refused {
    border-inline-start-color: #c8102e;
    background-color: #fdf2f4;
    color: #9a1024;
}

.store-cart-empty {
    padding-block: 40px;
}

/* A sign-in that changed the shopper's cart says so above whatever page they were returned to. It is drawn like the
   cart's own attention band because it says the same kind of thing: your cart is not quite what you left it as. */
.store-cart-merge-notice {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 12px 16px;
    margin-block: 20px 0;
    border-inline-start: 3px solid #fd9636;
    background-color: #fff7ee;
    border-radius: 8px;
}

/* The price and the line total are named by the column headings while those are drawn, so inside the
   cell the name is for a screen reader only. It is not Bootstrap's `visually-hidden`, because that
   one is declared `!important` and could not be undone below. */
.store-cart-cell-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* The add-to-cart control sits on one line with the quantity box beside it. */
.store-product-buy {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

@media (max-width: 991.98px) {
    /* The column headings describe a table that is no longer drawn, and every cell below carries its own
       label, so the head row goes rather than wrapping into five stray words. */
    .store-cart-head {
        display: none;
    }

    .store-cart-line .item-wishlist {
        grid-template-columns: minmax(0, 1fr);
        gap: 10px;
    }

    .store-cart-cell-price,
    .store-cart-cell-quantity,
    .store-cart-cell-total,
    .store-cart-cell-remove {
        display: flex;
        align-items: center;
        gap: 10px;
        flex-wrap: wrap;
    }

    /* The head row is gone, so these names are the only thing left saying which figure is which.
       Without them a shopper reads two amounts in Toman, one above the other, and has to work out
       from their size which one is the price. */
    .store-cart-cell-label {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip: auto;
        white-space: normal;
        color: #6b7280;
        font-size: 13px;
    }
}

/* ------------------------------------------------------------------ *
 * 13. Checkout and orders
 *
 * The Ecom checkout page lays its two panels out with `box-border` and its summary rows with the wishlist
 * classes, both of which assume a fixed desktop width. The rows are laid out here instead, as a grid that
 * becomes a stack below the large breakpoint, so a checkout is usable on a telephone rather than a table
 * somebody has to scroll sideways. Everything visual - the type scale, the colours, the buttons - still comes
 * from the theme.
 *
 * The theme's arrow glyphs on the checkout's own buttons are background images this repository does not
 * vendor, so those classes are not used: a button reserving forty-five pixels for artwork that never draws is
 * worse than a plain one.
 * ------------------------------------------------------------------ */

.store-checkout-panel,
.store-checkout-summary,
.store-order-group,
.store-order-summary,
.store-order-address {
    padding: 20px;
    margin-block-end: 20px;
}

/* The two outcomes differ by a word and by a border as well as by colour. */
.store-checkout-message {
    padding: 10px 16px;
    margin-block-end: 20px;
    border-radius: 8px;
    border-inline-start: 3px solid transparent;
}

.store-checkout-message-done {
    border-inline-start-color: #2f9e44;
    background-color: #f1f8f3;
    color: #1c6b30;
}

.store-checkout-message-refused {
    border-inline-start-color: #c8102e;
    background-color: #fdf2f4;
    color: #9a1024;
}

.store-checkout-attention {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
    padding: 12px 16px;
    margin-block-end: 20px;
    border-inline-start: 3px solid #fd9636;
    background-color: #fff7ee;
    border-radius: 8px;
}

.store-checkout-empty {
    padding-block: 40px;
}

/* One saved address. The chosen one is marked by a border on the reading edge as well as by the control being
   checked, so a reader who cannot see the radio still knows which address the order is going to. */
.store-checkout-address {
    padding: 12px 14px;
    margin-block-end: 12px;
    border: 1px solid #dde4f0;
    border-radius: 8px;
}

.store-checkout-address:has(input:checked) {
    border-inline-start: 3px solid #425a8b;
    background-color: #f7f9fc;
}

.store-checkout-address-choice {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-block-end: 6px;
}

.store-checkout-address-default {
    display: inline-block;
    margin-block-start: 6px;
    margin-inline-end: 12px;
    padding: 2px 8px;
    border-radius: 999px;
    background-color: #eef2f8;
    color: #425a8b;
}

.store-checkout-cancel {
    margin-inline-start: 16px;
}

.store-checkout-line,
.store-order-line {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 1.2fr);
    gap: 12px;
    align-items: center;
    padding-block: 14px;
    border-block-end: 1px solid #eef1f5;
}

.store-checkout-line .product-wishlist,
.store-order-line .product-wishlist {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.store-checkout-line .product-image img,
.store-order-line .product-image img {
    inline-size: 64px;
    block-size: auto;
    border-radius: 8px;
    background-color: #f4f6fa;
}

.store-checkout-line-issue {
    color: #c8102e;
    margin-block: 6px 0;
}

.store-checkout-line-total,
.store-order-line-total {
    text-align: end;
}

/* The theme sizes these cells as percentages of its own table row. Inside the grid track they already sit in,
   a percentage of the track squeezes the price cell to a sliver and a line's figures spill over its name, so
   both cells take the whole of their track instead. */
.listCheckout .store-checkout-line .wishlist-product,
.store-checkout-line .wishlist-price,
.store-order-line .wishlist-product,
.store-order-line .wishlist-price {
    width: auto;
}

.store-checkout-summary-row,
.store-order-summary-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}

/* What an order is doing right now is a sentence beside a heading rather than a coloured pill, because the
   two things it can say - the items are held until a moment, or the hold has ended - are facts a reader has
   to be able to read rather than infer from a colour. */
.store-order-state {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
    padding: 12px 16px;
    border-inline-start: 3px solid #425a8b;
    background-color: #f7f9fc;
    border-radius: 8px;
}

/* The cell names are visible only where the head row is not drawn, exactly as the cart's are. */
.store-checkout-line-label,
.store-order-line-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

@media (max-width: 991.98px) {
    .store-checkout-line,
    .store-order-line {
        grid-template-columns: minmax(0, 1fr);
    }

    .store-checkout-line-total,
    .store-order-line-total {
        text-align: start;
        display: flex;
        align-items: baseline;
        gap: 10px;
        flex-wrap: wrap;
    }

    /* Stacked, these names are the only thing left saying which figure is which. */
    .store-checkout-line-label,
    .store-order-line-label {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip: auto;
        white-space: normal;
        color: #6b7280;
        font-size: 13px;
    }
}

/* ------------------------------------------------------------------ *
 * 14. Ratings and reviews
 *
 * The Ecom theme draws its own `.product-rating` entirely from `imgs/page/product/rating-stars.png`, a sprite
 * this repository does not vendor, so a rating built on it would render as a blank twelve-pixel strip. The
 * stars here are two overlaid rows of inline SVG instead: a pale row giving the scale, and a coloured row
 * clipped to the fraction of the score, so an average of four and a half shows four stars and a half rather
 * than five.
 *
 * The clip is written with logical properties. In Persian the row reads right to left, so the filled part has
 * to begin at the right edge; `inset-inline-start` is that edge in both directions, and `left` would be the
 * wrong one in exactly one of them.
 *
 * Everything else is the theme's - the type scale, the brand colours, `box-border` for the cards - because a
 * rating that looked like a different site's would be read as somebody else's opinion of the shop.
 * ------------------------------------------------------------------ */

.store-rating-stars {
    position: relative;
    display: inline-block;
    line-height: 0;
    vertical-align: middle;
}

.store-rating-stars-track,
.store-rating-stars-fill {
    display: block;
    white-space: nowrap;
}

/* The filled row sits exactly over the pale one and is cut to the score. Its width is the arithmetic rather
   than a rounded number of stars, so the shape and the printed average cannot disagree. */
.store-rating-stars-fill {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    overflow: hidden;
}

.store-rating-star {
    fill: #E0E6F7;
}

.store-rating-star-filled {
    fill: #FD9636;
}

/* The score is always written out beside the stars, so it is never carried by the shapes alone. */
.store-rating-value {
    margin-inline-start: 6px;
    white-space: nowrap;
}

/* The strip beside the product heading is a link down to the reviews, and reads as text rather than as a
   button, because it takes the reader further down the same page. */
.store-product-rating {
    display: flex;
    align-items: center;
    gap: 4px;
}

.store-product-rating a {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

.store-product-rating a:hover .store-rating-value,
.store-product-rating a:focus-visible .store-rating-value {
    text-decoration: underline;
}

/* The average and the distribution it was worked out from, side by side above the reviews themselves. */
.store-review-summary {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    gap: 10px 30px;
    align-items: start;
    padding: 20px;
    margin-block-end: 20px;
    background-color: #f7f9fc;
    border-radius: 8px;
}

.store-review-summary-score {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.store-review-empty {
    margin-block-end: 0;
}

.store-review-distribution {
    list-style: none;
    margin: 0;
    padding: 0;
    min-width: 0;
}

.store-review-distribution-row {
    display: grid;
    grid-template-columns: 5.5em minmax(60px, 1fr) 3em;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: #6B83B6;
}

/* The rows need air between them: five of them stacked at the type's own line height read as one
   block of numbers rather than as five separate counts. */
.store-review-distribution-row + .store-review-distribution-row {
    margin-block-start: 6px;
}

.store-review-distribution-track {
    display: block;
    height: 8px;
    border-radius: 4px;
    background-color: #E0E6F7;
    overflow: hidden;
}

.store-review-distribution-bar {
    display: block;
    height: 100%;
    background-color: #FD9636;
}

.store-review-distribution-count {
    text-align: end;
}

/* Sorting is a row of links, and the order in force is a plain word rather than a link to the page the reader
   is already looking at. */
.store-review-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 16px;
    margin-block-end: 15px;
    font-size: 14px;
}

.store-review-sort {
    color: #6B83B6;
}

.store-review-sort-current {
    color: #425A8B;
    font-weight: 700;
}

.store-review-list,
.store-account-review-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* The two controls a review offers its author sit on one line and wrap together on a narrow screen.
   Written in logical properties so the row reads correctly in both directions. */
.store-account-review-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.store-account-review-actions:empty {
    display: none;
}

/* The invitation sits under the line it belongs to rather than beside the price, so a narrow screen
   keeps it with the product it is about. */
.store-order-line-review {
    display: inline-block;
    margin-block-start: 4px;
    text-decoration: underline;
}

.store-review {
    padding-block: 20px;
    border-block-start: 1px solid #E0E6F7;
}

.store-review:first-child {
    padding-block-start: 0;
    border-block-start: 0;
}

.store-review-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    margin-block-end: 8px;
}

/* A display name is whatever the writer chose, so it is allowed to break rather than to widen the card. */
.store-review-author {
    overflow-wrap: anywhere;
}

/* A verified purchase is marked by a word on a tinted chip, never by the tint alone. */
.store-review-verified {
    padding: 2px 8px;
    border-radius: 999px;
    background-color: #f1f8f3;
    color: #1c6b30;
}

.store-review-date {
    margin-inline-start: auto;
}

.store-review-title {
    margin-block-end: 5px;
}

/* The body is printed as the customer typed it, so the line breaks they put in are kept, and a long unbroken
   run of characters breaks rather than widening the page. */
.store-review-body {
    margin-block-end: 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Objecting to a review is folded away, because a page of reviews is for reading and a form under
   every one of them would drown the words they are about. */
.store-review-report {
    margin-block-start: 10px;
}

.store-review-report > summary {
    cursor: pointer;
    width: fit-content;
}

.store-review-report form {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 8px 12px;
    margin-block-start: 10px;
    padding: 12px 16px;
    border-radius: 8px;
    background-color: #f7f9fc;
}

.store-review-report label {
    display: block;
    margin-block-end: 4px;
}

/* The reason is a short list and the note is free text, so the note gets the room. Left to their
   intrinsic widths the select takes a line of its own and the layout reads the other way round. */
.store-review-report select {
    flex: 0 1 220px;
    min-width: 0;
}

.store-review-report input[type="text"] {
    flex: 1 1 240px;
    min-width: 0;
}

.store-review-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 16px;
    margin-block-start: 20px;
    font-size: 14px;
}

/* The two page links read as the sort links above them do, because they do the same kind of thing:
   they change what this section shows without leaving the page. */
.store-review-page {
    color: #6B83B6;
}

.store-review-page-position {
    color: #6B83B6;
}

@media (max-width: 767.98px) {
    .store-review-summary {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Stacked, the date has no room to sit at the far end of the line, so it follows the rest. */
    .store-review-date {
        margin-inline-start: 0;
        flex-basis: 100%;
    }
}

/* The product page's wishlist and alert controls wrap onto as many lines as a narrow screen needs, with room
   between them so each is its own touch target. */
.store-product-wishlist-actions {
    gap: 10px;
}

/* A wishlist row whose product is no longer offered keeps its place, and says so in words as well as tone. */
.store-wishlist-unavailable {
    color: #6c757d;
}
