@font-face {
    font-family: 'MenuFont';
    src: url('/asset/fonts/Open_Sans/static/OpenSans-Medium.ttf');
}

html {
    height: 100%;
    overflow: inherit;
}

body {
    font-family: -apple-system, Roboto, MenuFont, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", 'Open Sans', Arial sans-serif;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

html, body {
    height: 100%;
    margin: 0;
}

.link {
    cursor: pointer;
}

/* The dish title's <a class="link"> only opens the modal. Without this it paints the title
   in Bootstrap's link color whenever the editor has no dish title color set; inherit
   gives it the menu font color instead, and a set dish title color still wins on the dish title. */
.mse-dish-row a.link,
.mse-dish-row a.link:hover {
    color: inherit;
    text-decoration: none;
}

/* The whole dish row opens the modal (layout-02.js); the heart in it still only toggles. */
.mse-dish-row {
    cursor: pointer;
}

.language-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.image-column {
    width: 0; /* Default width when empty */
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
}

.image-column:empty {
    width: 0; /* Ensure width stays 0 when empty */
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
}

[data-bs-theme=light] {
    --bs-link-color-rgb: 20, 134, 112;
    --bs-link-hover-color-rgb: 12, 80, 67;
    --bs-link-color: #148670 !important; /* Darker shade of #18bc9c */
    --bs-link-hover-color: #0c5043 !important; /* Even darker for hover */
}

.accordion-button {
    background-color: var(--bs-secondary-bg); /* Default */
}

.accordion-button.has-children {
    background-color: var(--bs-primary-bg-subtle); /* Parents */
}

.accordion-button {
    border-top: 1px solid var(--bs-border-color);
    border-bottom: 1px solid var(--bs-border-color);
    /*background-color: transparent;*/
}

.accordion-item,
.accordion-button:focus,
.accordion-button:not(.collapsed) {
    border: none;
    box-shadow: none;
}


#product_prices {
    font-size: 1.5rem !important
}

.product-prices {
    font-size: 1.1rem !important
}

#product_description {
    white-space: pre-wrap;
}

.image-column {
    width: 106px;
    /*max-width: 100px;*/
}

.image-column img {
    width: 100%;
    max-width: 100px;
}

main {
    flex: 1 0 auto;
}

footer {
    flex-shrink: 0;
}

.custom-input-group {
    width: 90%;
}

@media (min-width: 992px) {
    .custom-input-group {
        width: 50%;
    }
}

#movingHeart {
    display: none;
    position: fixed;
    width: 2.5rem;
    height: 2.5rem;
    opacity: 1;
    animation: moveTopRight 0.4s ease-in-out forwards;
    z-index: 1000;
}

@keyframes moveTopRight {
    0% {
        opacity: 1;
        transform: translate(10px, 0);
    }
    100% {
        opacity: 0;
        transform: none;
        top: 0;
        left: 80%;
    }
}

.show-moving-heart {
    display: block !important;
}

@keyframes blink {
  0%, 100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0;
    transform: scale(3);
  }
}
.blink {
  animation: blink 0.5s ease-in-out 3;
}

.bi {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    background-size: contain;
    background-repeat: no-repeat;
}

.bi-bigger {
    display: inline-block;
    width: 1.5rem;
    height: 1.5rem;
    background-size: contain;
    background-repeat: no-repeat;
}

/* Light mode (default) */
.bi-suit-heart {
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="%23000"><path d="m8 6.236-.894-1.789c-.222-.443-.607-1.08-1.152-1.595C5.418 2.345 4.776 2 4 2 2.324 2 1 3.326 1 4.92c0 1.211.554 2.066 1.868 3.37.337.334.721.695 1.146 1.093C5.122 10.423 6.5 11.717 8 13.447c1.5-1.73 2.878-3.024 3.986-4.064.425-.398.81-.76 1.146-1.093C14.446 6.986 15 6.131 15 4.92 15 3.326 13.676 2 12 2c-.777 0-1.418.345-1.954.852-.545.515-.93 1.152-1.152 1.595zm.392 8.292a.513.513 0 0 1-.784 0c-1.601-1.902-3.05-3.262-4.243-4.381C1.3 8.208 0 6.989 0 4.92 0 2.755 1.79 1 4 1c1.6 0 2.719 1.05 3.404 2.008.26.365.458.716.596.992a7.6 7.6 0 0 1 .596-.992C9.281 2.049 10.4 1 12 1c2.21 0 4 1.755 4 3.92 0 2.069-1.3 3.288-3.365 5.227-1.193 1.12-2.642 2.48-4.243 4.38z"/></svg>');
}

.bi-suit-heart-fill {
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="%23000"><path d="M4 1c2.21 0 4 1.755 4 3.92C8 2.755 9.79 1 12 1s4 1.755 4 3.92c0 3.263-3.234 4.414-7.608 9.608a.513.513 0 0 1-.784 0C3.234 9.334 0 8.183 0 4.92 0 2.755 1.79 1 4 1"/></svg>');
}

.bi-spinner {
    width: 1.5rem;
    height: 1.5rem;
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20" stroke="%23000" stroke-width="5" fill="none" stroke-dasharray="31.4"><animate attributeName="stroke-dashoffset" from="180" to="0" dur="1s" repeatCount="indefinite"/></circle></svg>');
}

/* Dark mode */
[data-bs-theme="dark"] .bi-suit-heart {
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="%23fff"><path d="m8 6.236-.894-1.789c-.222-.443-.607-1.08-1.152-1.595C5.418 2.345 4.776 2 4 2 2.324 2 1 3.326 1 4.92c0 1.211.554 2.066 1.868 3.37.337.334.721.695 1.146 1.093C5.122 10.423 6.5 11.717 8 13.447c1.5-1.73 2.878-3.024 3.986-4.064.425-.398.81-.76 1.146-1.093C14.446 6.986 15 6.131 15 4.92 15 3.326 13.676 2 12 2c-.777 0-1.418.345-1.954.852-.545.515-.93 1.152-1.152 1.595zm.392 8.292a.513.513 0 0 1-.784 0c-1.601-1.902-3.05-3.262-4.243-4.381C1.3 8.208 0 6.989 0 4.92 0 2.755 1.79 1 4 1c1.6 0 2.719 1.05 3.404 2.008.26.365.458.716.596.992a7.6 7.6 0 0 1 .596-.992C9.281 2.049 10.4 1 12 1c2.21 0 4 1.755 4 3.92 0 2.069-1.3 3.288-3.365 5.227-1.193 1.12-2.642 2.48-4.243 4.38z"/></svg>');
}

[data-bs-theme="dark"] .bi-suit-heart-fill {
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="%23fff"><path d="M4 1c2.21 0 4 1.755 4 3.92C8 2.755 9.79 1 12 1s4 1.755 4 3.92c0 3.263-3.234 4.414-7.608 9.608a.513.513 0 0 1-.784 0C3.234 9.334 0 8.183 0 4.92 0 2.755 1.79 1 4 1"/></svg>');
}

[data-bs-theme="dark"] .bi-spinner {
    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20" stroke="%23fff" stroke-width="5" fill="none" stroke-dasharray="31.4"><animate attributeName="stroke-dashoffset" from="180" to="0" dur="1s" repeatCount="indefinite"/></circle></svg>');
}
/* ── Layout02: style-editor hooks ───────────────────────────────────────────
   Everything above is a verbatim copy of layout-01.css. Below is what the style
   editor needs on top of it.

   menu-style-editor.css styles the header band by #mse-header. The public menu's
   band is #menuHeader, so those rules are repeated here against that id rather
   than renaming an element the production JS and CSS already know.
   ------------------------------------------------------------------------- */

/* layout-01.css makes body a flex column purely for its sticky footer. The stage below
   is plain block flow like the prototype, so that chain no longer reaches <main> and only
   leaves the width boundary wrapper as a flex item, where `margin:0 auto` behaves
   differently than in normal flow. Put body back to block. */
body {
    display: block;
}

/* The prototype styles its band as #mse-header; ours is #menuHeader, so the same rules are
   repeated against that id. Kept identical on purpose — the editor's Content align sets
   justify-content on this flex column, and its header-image control sets padding-bottom.
   Earlier attempts to replace this with grid or padding arithmetic all drifted. */
#menuHeader {
    position: relative;
    z-index: 4;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

#menuHeader::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--mse-header-bg, rgba(108, 117, 125, 0.85));
    z-index: 1;
}

#mse-header-title {
    padding: 1rem 1rem 0.25rem;
}

#mse-header-description {
    padding: 0.25rem 1rem 1rem;
}

/* Only one of the two moved into the band: the 0.25rem that separates them would leave
   it off-centre, so it gets the full 1rem on both sides. */
#mse-header-content > :only-child {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

/* Same below the header: an empty title or description is rendered hidden, and the
   one left on its own gets the full 1rem on both sides. */
#mse-title-outside:has(+ #mse-description-outside[hidden]) > #mse-header-title {
    padding-bottom: 1rem;
}

#mse-title-outside[hidden] + #mse-description-outside > #mse-header-description {
    padding-top: 1rem;
}

/* The stage is plain block flow, exactly as the prototype builds it. Do not turn
   #mse-preview or #mse-scroll-content into flex containers to carry layout-01.css's
   `main { flex: 1 0 auto }` sticky-footer chain through — that made the stage's height
   depend on its children instead of the other way round, and the header ended up
   displaced. #mse-preview's own min-height:100vh keeps a short menu filling the frame,
   which is all the sticky footer was buying. */

/* #mse-bg-layer, .mse-tint and .mse-vignette are absolute with inset:-30px and expect
   #mse-preview to be their containing block. Nothing in menu-style-editor.css sets that
   — the prototype gets it from an inline <style> in its own template. Without it they
   resolve against the viewport, so the background is one screen tall and gets cut off
   the moment an accordion opens and the page grows past it. */
#mse-preview {
    position: relative;

    /* menu-style-editor.css uses `overflow: hidden !important` here to clip #mse-bg-layer's
       inset:-30px bleed. But overflow:hidden makes this a scroll container — scrollable by
       script even with no scrollbar — so the accordion's scrollIntoView() scrolls the stage
       instead of the page. The header scrolls up inside the clipped box and cannot come
       back, because there is no scrollbar to return it.
       overflow:clip clips identically but is NOT a scroll container, so scrollIntoView
       falls through to the document and the jump-to-category feature works as on the
       public menu. Needs !important to beat the rule it is replacing. */
    overflow: clip !important;
}

/* menu-style-editor.css gives #mse-scroll-content height:100% + overflow-y:auto. That is
   inert while #mse-preview stays auto-height, but spelled out here so a long menu can
   never scroll inside itself — the editor sizes the iframe from a ResizeObserver on
   #mse-preview, and a self-scrolling stage would report a near-empty height. */
#mse-scroll-content {
    height: auto;
    overflow-y: visible;
}

/* Footer at the bottom of the window when the menu is shorter than it. Only this wrapper
   is a flex column, filling the stage's own min-height; #mse-preview stays block flow (see
   the note above). main takes the spare height, so the footer sits at the bottom. */
#mse-scroll-content {
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - 2 * var(--mse-frame-gap, 0px));
}

#mse-scroll-content > main {
    flex: 1 0 auto;
}

/* #mse-bg-layer is absolute with z-index 0, so static content would paint underneath it.
   Only the content wrappers are lifted — NOT `#mse-scroll-content > *`, which would also
   catch .modal and cap it below the z-1050 backdrop that Bootstrap appends to <body>,
   leaving the whole page greyed out and unclickable. #menuHeader has its own z-index
   above, and .modal keeps Bootstrap's 1055. */
#mse-scroll-content > main,
#mse-scroll-content > footer {
    position: relative;
    z-index: 1;
}

/* Dish spacing. style-editor/layout-01.css spaces prototype dishes with
   `.mse-dish-row + .mse-dish-row { margin-top }`, which does nothing on a <tr>.
   Same variable, applied as cell padding instead, split half above and half below
   every dish: the gap between two dishes stays the slider value, and each dish sits
   centred between the row dividers instead of low against the one under it. */
tr.mse-dish-row > td {
    padding-top:    calc(var(--mse-dish-gap, 1rem) / 2);
    padding-bottom: calc(var(--mse-dish-gap, 1rem) / 2);
}

/* Accordion color variables, same contract as style-editor/layout-01.css. */
.mse-top-accordion,
.mse-sub-accordion {
    --bs-accordion-color:                inherit;
    --bs-accordion-btn-color:            inherit;
    --bs-accordion-active-color:         inherit;
    --bs-accordion-border-color:         rgba(128, 128, 128, 0.25);
    --bs-accordion-btn-focus-box-shadow: none;
}

/* clip, not hidden: for nested categories an outer .accordion-item is an ancestor of the
   one being scrolled to, and overflow:hidden would make it another silent scroll
   container for scrollIntoView to hijack. clip rounds the corners just the same. */
.mse-top-accordion > .accordion-item,
.mse-sub-accordion > .accordion-item {
    overflow: clip;
}

/* Corner sliders in the Layout tab (layout-02.js); 4px is what they had before. */
.mse-top-accordion > .accordion-item {
    border-radius: var(--mse-top-radius, 4px);
}

.mse-sub-accordion > .accordion-item {
    border-radius: var(--mse-cat-radius, 4px);
}

.mse-sub-accordion .accordion-body,
.mse-top-accordion > .accordion-item > .accordion-collapse > .accordion-body:not(:has(.mse-sub-accordion)),
#whichListTable .modal-body {
    background-color: var(--mse-dish-bg, transparent);
    color: var(--mse-dish-color, inherit);
}

/* Dish corners above 0 (layout-02.js puts .mse-dish-cards on body): every dish becomes its
   own rounded card. The dish color moves from the panel behind the list onto the rows,
   the row dividers go, and the rows get half the dish spacing between them. */
.mse-dish-cards .mse-sub-accordion .accordion-body,
.mse-dish-cards .mse-top-accordion > .accordion-item > .accordion-collapse > .accordion-body:not(:has(.mse-sub-accordion)),
.mse-dish-cards #whichListTable .modal-body {
    background-color: transparent;
}

.mse-dish-cards table.table_product_list {
    border-collapse: separate;
    border-spacing: 0 calc(var(--mse-dish-gap, 1rem) / 2);
}

.mse-dish-cards tr.mse-dish-row > td {
    background-color: var(--mse-dish-bg, transparent);
    border-bottom-width: 0;
    /* Bootstrap's alternating row shade (an inset box-shadow) would make every other
       card a different color */
    box-shadow: none;
}

.mse-dish-cards tr.mse-dish-row > td:first-child {
    border-top-left-radius: var(--mse-dish-radius, 0);
    border-bottom-left-radius: var(--mse-dish-radius, 0);
}

.mse-dish-cards tr.mse-dish-row > td:last-child {
    border-top-right-radius: var(--mse-dish-radius, 0);
    border-bottom-right-radius: var(--mse-dish-radius, 0);
}

/* The popup title sits in a Bootstrap .card, which resets the color, and the search
   results are outside the accordion bodies above. layout-02.js sets --mse-dish-color
   on both. Description and price carry inline colors. */
.mse-dish-row .mse-item-name,
#modalProduct #product_title,
#modalProduct #modal_heart {
    color: var(--mse-dish-color, inherit);
}

/* layout-01.css paints every accordion button with --bs-secondary-bg. The editor
   sets its own colors as inline styles and custom properties, so the flat
   defaults have to stop winning here. */
.mse-top-accordion .accordion-button,
.mse-sub-accordion .accordion-button {
    background-color: var(--bs-accordion-btn-bg, transparent);
}

/* The dish tables inherit the accordion body's background rather than Bootstrap's
   table default, otherwise the dish color never shows. */
.mse-top-accordion .table,
.mse-sub-accordion .table,
#whichListTable .table {
    --bs-table-bg: transparent;
    color: inherit;
}

/* Bootstrap colors every cell with --bs-table-color (the emphasis color), which beat the
   dish text color on the accordion body. Cells inherit it instead, so the dish title,
   price and description follow it unless a per-text color is set. */
.mse-top-accordion .table > :not(caption) > * > *,
.mse-sub-accordion .table > :not(caption) > * > *,
#whichListTable .table > :not(caption) > * > * {
    color: inherit;
}

/* ── Wishlist hearts as inline SVG ──────────────────────────────────────────
   layout-01.css paints .bi-suit-heart / .bi-suit-heart-fill as background-image data
   URLs with a hardcoded fill (#000, or #fff under data-bs-theme=dark). That cannot
   follow the colors the style editor applies, so the preview uses the sprite in
   base.html.twig instead and lets fill:currentColor inherit.

   The class contract is unchanged — layout-02.js still swaps bi-suit-heart <->
   bi-suit-heart-fill and toggles bi-spinner — only which of the two <use> elements is
   visible changes. .bi-spinner keeps its background-image, so the <use> children are
   hidden while it spins.
   ------------------------------------------------------------------------- */

svg.bi.bi-suit-heart,
svg.bi.bi-suit-heart-fill {
    background-image: none;
}

svg.bi > use {
    display: none;
}

svg.bi.bi-suit-heart > use.mh-heart-outline,
svg.bi.bi-suit-heart-fill > use.mh-heart-fill {
    display: inline;
}

/* Must come last: same specificity as the two rules above, and the spinner has to win
   while it is on — layout-02.js adds .bi-spinner without removing the heart class. */
svg.bi.bi-spinner > use.mh-heart-outline,
svg.bi.bi-spinner > use.mh-heart-fill {
    display: none;
}

/* setHeartState() spins the heart for 250ms before flipping it. layout-01.css does that
   with .bi-spinner's background-image, but the rule above that clears background-image on
   these SVGs outranks it, so the heart just went blank. Spin the sprite's own arc instead
   — it also picks up currentColor rather than the data URL's hardcoded stroke. */
svg.bi.bi-spinner {
    background-image: none;
}

svg.bi.bi-spinner > use.mh-spinner {
    display: inline;
    transform-box: fill-box;
    transform-origin: center;
    animation: mh-spin 0.8s linear infinite;
}

@keyframes mh-spin {
    to {
        transform: rotate(360deg);
    }
}

/* ── Header resize lug ──────────────────────────────────────────────────────
   Smaller than the prototype's 64x28 in menu-style-editor.css, which is loaded
   before this file, so equal specificity is enough to win. row-resize first as a
   fallback for anything that lacks ns-resize; both draw the up/down arrow. */
#mse-header-resize-lug {
    width: 44px;
    height: 16px;
    border-radius: 0 0 8px 8px;
    cursor: row-resize;
    cursor: ns-resize;
}

#mse-header-resize-lug::after {
    width: 22px;
    height: 3px;
    border-radius: 2px;
}

/* ── Dish modal and wishlist ─────────────────────────────── */
/* menu-preview-02.js copies the menu's background, tint and vignette layers into both
   modals (mirrorMenuBackgroundToModal). Same geometry as the stage's own layers: the
   background bleeds 30px for blur, which .modal-content's overflow:hidden clips. The
   header, body and cards are made see-through so the background shows behind them. */
#modalProduct .modal-content,
#whichListTable .modal-content {
    position: relative;
    overflow: hidden;
}

#modalProduct .mse-modal-bg,
#modalProduct .mse-modal-tint,
#modalProduct .mse-modal-vignette,
#whichListTable .mse-modal-bg,
#whichListTable .mse-modal-tint,
#whichListTable .mse-modal-vignette {
    position: absolute;
    pointer-events: none;
    z-index: 0;
}

#modalProduct .mse-modal-bg,
#whichListTable .mse-modal-bg {
    inset: -30px;
    background-size: cover;
    background-position: center;
}

#modalProduct .mse-modal-tint,
#modalProduct .mse-modal-vignette,
#whichListTable .mse-modal-tint,
#whichListTable .mse-modal-vignette {
    inset: 0;
}

#modalProduct .modal-header,
#modalProduct .modal-body,
#whichListTable .modal-header,
#whichListTable .modal-body,
#whichListTable .modal-footer {
    position: relative;
    z-index: 1;
}

/* An opaque base under the copied layers: a background color picked with alpha would
   otherwise let the page and the backdrop show through the popup. */
#modalProduct .modal-content,
#whichListTable .modal-content {
    background-color: var(--bs-body-bg);
}

#modalProduct .modal-body .card {
    background-color: transparent;
}

/* ── Page background layer ─────────────────────────────── */
/* Created by menu-preview-02.js for bg.page. Fixed behind everything (z-index -1 is above
   the body background, below the page); same defaults and 30px blur bleed as #mse-bg-layer. */
#mse-page-bg-layer {
    position: fixed;
    inset: -30px;
    z-index: -1;
    pointer-events: none;
    background-size: cover;
    background-position: center;
}

/* ── Menu border ───────────────────────────────────────── */
/* Set by applyFrame() in menu-preview-02.js. The radius needs !important and the extra
   class to beat `.mse-preview-full { border-radius: 0 !important }` in
   menu-style-editor.css; overflow:clip (above) cuts the background to the corners, and a
   box-shadow is not clipped by its own element. The border is a box-shadow ring outside
   the column, so where the column fills the window (phones) it gets just enough side
   margin to stay on screen; on wide screens that margin works out to 0. */
#mse-preview.mse-preview-full {
    border-radius: var(--mse-frame-radius, 0) !important;
    box-shadow: 0 0 0 var(--mse-frame-width, 0) var(--mse-frame-color, transparent),
                0 0 var(--mse-frame-shadow, 0) var(--mse-frame-shadow-color, rgba(0, 0, 0, 0.35));
    /* the gap itself is padding on #mse-stage-wrap: a bottom margin here would fall
       outside the page's scroll area and never show */
    min-height: calc(100vh - 2 * var(--mse-frame-gap, 0px));
    /* auto, not menu-style-editor.css's 100%, so the side margins narrow the column
       instead of pushing it past the right edge */
    width: auto !important;
    margin-left:  max(0px, calc(var(--mse-frame-width, 0px) - max(0px, (100vw - 900px) / 2)));
    margin-right: max(0px, calc(var(--mse-frame-width, 0px) - max(0px, (100vw - 900px) / 2)));
}

#mse-stage-wrap {
    padding-top: var(--mse-frame-gap, 0);
    padding-bottom: var(--mse-frame-gap, 0);
}
