﻿/* ============================================================================
   THE APP SHELL — dark side rail + top bar, app-wide.
   From the approved mockup `scratchpad/mockup/shell-home.html`; it replaces the
   old top NavBar (deleted) and serves both MainLayout and WideLayout.

   TWO RULES THIS FILE FOLLOWS, AND WHY
   1. EVERY class is `lt-`-prefixed. The mockup writes bare names — `.card`,
      `.tile`, `.page`, `.num`, `.money`, and the element selectors `table`,
      `th`, `td`. app.css is loaded AFTER bootstrap.min.css, so a bare `.card`
      here would restyle Bootstrap's `.card` on Admin/Hotels/Partners/every
      existing page (and `overflow:hidden` would clip their dropdowns), and bare
      `table/th/td` would restyle every grid in the app. `booking-editor.css`
      already solved this with its `bk-` prefix; this file uses `lt-`.
   2. NO colours, no sizes, no fonts are declared here — only `--lt-*` tokens
      from app.css's `:root`. The rail's four dark colours are ALIASES of the
      ledger's (identical values), so there is one palette, not two.

   The collapse state lives on <html data-lt-rail="full|min">, set by a tiny
   inline script in App.razor BEFORE first paint (no flash) and flipped by
   js/shell.js. The content column only ever reads --lt-rail-cur, so the flip is
   one custom property, not a class on every layout.
   ========================================================================= */

:root[data-lt-rail="min"] {
    --lt-rail-cur: var(--lt-rail-w-min);
}

/* The rail's strip is painted STATICALLY here as well as by the rail itself. <AppShell> is
   `prerender: false`, so between first paint and the WASM runtime being ready there is no rail — while
   `.lt-main` already carries its `margin-left`. Without this the cold load shows the page shoved 216px right
   beside a blank white column, which reads as «the menu is broken», not «still loading» (and this app loads the
   full ICU data set, so the window is not brief). With it, the rail fills in over a strip that was already
   there. `fixed` so the strip covers the viewport height rather than repeating with the content. */
body {
    background-color: var(--lt-ground);
    background-image: linear-gradient(to right, var(--lt-rail-bg) var(--lt-rail-cur), transparent var(--lt-rail-cur));
    background-attachment: fixed;
    background-repeat: no-repeat;
}

/* The shell's TYPE is on the shell's own boxes, never on `body`.
   `body { font-family / font-size / color }` here would restyle the text of all ~37 existing pages — they inherit
   from it, and Bootstrap Reboot's own body rule (16px, #212529) is what they were built against. That is rule 1 of
   this file («a bare selector restyles every existing page») and app.css's opening comment («the mockup's base
   resets are NOT copied»); swapping the NavBar is not licence to reflow the typography of the whole app. So: the
   rail, the top bar and the footer are styled here, `.lt-main` is deliberately NOT (it contains every page), and a
   page written against the tokens opts in by name — `.bk-page` in booking-editor.css, `.lt-home` in home.css.
   `.lt-rail` restates its own `color` below and wins by order. */
.lt-skip,
.lt-rail,
.lt-topbar,
.lt-shell-footer {
    color: var(--lt-ink);
    font-family: var(--lt-font-ui);
    font-size: var(--lt-text-body);
}

/* ── The rail ───────────────────────────────────────────────────────────── */
/* Fixed, not a grid column: the rail and the content column are rendered by two
   DIFFERENT components (the rail is an interactive WASM island, @Body is not),
   so they cannot share a grid parent without passing a RenderFragment across a
   render-mode boundary — which Blazor does not allow. */
.lt-rail {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 30;
    width: var(--lt-rail-cur);
    display: flex;
    flex-direction: column;
    background: var(--lt-rail-bg);
    color: var(--lt-rail-ink);
    overflow: hidden;
}

.lt-rail__brand {
    display: flex;
    align-items: center;
    gap: var(--lt-space-4);
    height: var(--lt-topbar-h);
    padding: 0 var(--lt-space-5);
    border-bottom: 1px solid var(--lt-rail-line);
    font-weight: var(--lt-weight-bold);
    white-space: nowrap;
    color: var(--lt-rail-ink);
    text-decoration: none;
}

/* Το σήμα είναι πλέον ΕΙΚΟΝΑ (το λογότυπο), όχι πλακίδιο με δύο γράμματα: χωρίς `object-fit` το PNG θα
   παραμορφωνόταν στο τετράγωνο, και το μπλε του λογότυπου δεν χρειάζεται φόντο accent από πίσω του. */
.lt-rail__mark {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: var(--lt-radius-sm);
    object-fit: contain;
}

.lt-rail__scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--lt-space-4) 0 var(--lt-space-6);
}

.lt-rail__cap {
    margin: 0;
    padding: var(--lt-space-5) var(--lt-space-5) var(--lt-space-2);
    font-size: var(--lt-text-caption);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--lt-rail-muted);
    white-space: nowrap;
}

/* ── Folding a group (owner, 23/09/2026) ──
   «ωραίο θα ήταν να μπορώ να κάνω expand collapse το μενού και να το κρατάει στα cookies ή κάτι τέτοιο τοπικά».
   Each caption's words are a TOGGLE for the entries under it; the choice is js/shell.js's 'lt-rail-groups'.
   The <button> sits INSIDE `.lt-rail__cap` rather than replacing it, so everything already written about the caption
   holds unchanged: its padding is still the caption's geometry, the icon rail still hides it (the toggles go with the
   captions, so «Μάζεμα» mode is exactly what it was) and the drawer still brings it back. What the button has to
   undo is what Bootstrap Reboot and the browser put on every <button>: Reboot's `text-transform: none`, the UA's
   `letter-spacing: normal`, its colour, padding and border. Measured at 1920: the caption is the same height with
   the button inside it as with bare text.
   WIDER than the caption's content box, into its right padding (all but 4px of it). At 1920x1080 the rail's own
   scrollbar is showing, and «ΔΙΑΘΕΣΙΜΟΤΗΤΑ & ΣΤΑΤΙΣΤΙΚΑ» measured 171px of the 177px left — the chevron beside it
   would have cut the longest caption to an ellipsis. The ellipsis stays as the safety net for a longer name. */
.lt-rail__grp {
    display: flex;
    align-items: center;
    gap: var(--lt-space-2);
    width: calc(100% + var(--lt-space-5) - var(--lt-space-2));
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: left;
    cursor: pointer;
}

    .lt-rail__grp:hover {
        color: var(--lt-rail-ink);
    }

.lt-rail__grptx {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ▾ open, ▸ folded — drawn from two borders of an empty span, not typed: `::after { content }` is read out as part of
   the button's NAME, and a glyph can land as tofu (the hamburger's reason, below). No `transition` on purpose: the
   only reduced-motion answer this sheet may carry is the phone-scoped one (ShellStyleGuardTests). */
.lt-rail__chev {
    flex: none;
    width: .375rem;
    height: .375rem;
    margin: 0 0 var(--lt-space-1) auto;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg);
}

    .lt-rail__grp[aria-expanded="false"] .lt-rail__chev {
        margin-bottom: 0;
        transform: rotate(-45deg);
    }

/* A FOLDED group hides every entry EXCEPT the page you are on. `aria-current` is the attribute the accent bar keys off
   and ShellNav.ActiveKey writes it on exactly one link, so «where am I» survives any fold without a second rule in C#
   that could come to disagree with it. `display: none` takes the hidden links out of the tab order and out of the
   accessibility tree together; the one left is still announced as the current page. */
.lt-rail__fold a:not([aria-current="page"]) {
    display: none;
}

.lt-rail a {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--lt-space-5);
    padding: .3125rem var(--lt-space-5);
    color: var(--lt-rail-ink);
    text-decoration: none;
    font-size: var(--lt-text-control);
    white-space: nowrap;
}

    .lt-rail a:hover {
        background: var(--lt-rail-hover);
        color: var(--lt-rail-ink);
    }

    /* aria-current is set by the component itself: Blazor's NavLink only writes a class. Styling the ATTRIBUTE
       rather than a class is deliberate — the marker cannot then appear without the screen-reader signal.
       Owner 28/09/2026: «ισως να βαζαμε ενα καθετο ισοσκελες τριγωνακι αριστερα απο το επιλεγμενο? αντι για την σκια?» —
       the current page is a small right-pointing isosceles triangle at the left edge, in the accent (or the row's own
       daily colour, below), and NO background shade; the bold text stays. */
    .lt-rail a[aria-current="page"] {
        font-weight: var(--lt-weight-semibold);
    }

        .lt-rail a[aria-current="page"]::before {
            content: "";
            position: absolute;
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            border-top: .4375rem solid transparent;
            border-bottom: .4375rem solid transparent;
            /* UX 20/10/2026, X10: the fallback is the rail's ink, no longer --lt-accent — #1B5FD1 on --lt-rail-bg measures 2.80:1, under
               WCAG 1.4.11's 3:1 for a graphic, so on Οφειλέτες, Οικονομικά, Διαχείριση… the marker all but vanished and only the bold
               text was left. --lt-rail-ink is 15:1 and neutral (it does not read as the «Πλάνο» blue). The daily three keep their own
               colour (--lt-hot); the triangle, its size and the no-shade rule stay as the owner decided. */
            border-left: .5rem solid var(--lt-hot, var(--lt-rail-ink));
        }

    .lt-rail a.lt-rail__soon {
        color: var(--lt-rail-muted);
        font-style: italic;
    }

    /* The daily three (owner 25/09/2026): coloured glyph + a wash of the same colour on the row — stronger since
       28/09/2026 («πιο εντονο το χρωμα? για να ξεχωριζουν στο μάτι»). The current page is still the triangle above (in
       the row's colour), so «where am I» and «what is frequent» stay two signals; the wash does not change when selected. */
    .lt-rail a.lt-rail__hot {
        background: color-mix(in srgb, var(--lt-hot) 26%, transparent);
    }

    .lt-rail a.lt-rail__hot:hover {
        background: color-mix(in srgb, var(--lt-hot) 38%, transparent);
    }

    .lt-rail a.lt-rail__hot .lt-ic {
        color: var(--lt-hot);
    }

    .lt-rail a.lt-rail__hot--new { --lt-hot: var(--lt-rail-hot-new); }
    .lt-rail a.lt-rail__hot--search { --lt-hot: var(--lt-rail-hot-search); }
    .lt-rail a.lt-rail__hot--plan { --lt-hot: var(--lt-rail-hot-plan); }

    .lt-rail .lt-ic {
        flex: none;
        width: 1.125rem;
        text-align: center;
        font-size: .9375rem;
        line-height: 1;
    }

    .lt-rail .lt-tx {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }

.lt-rail__foot {
    border-top: 1px solid var(--lt-rail-line);
    padding: var(--lt-space-4) var(--lt-space-5);
    display: flex;
    align-items: center;
}

.lt-rail__toggle {
    background: transparent;
    border: 1px solid var(--lt-rail-line);
    color: var(--lt-rail-ink);
    border-radius: var(--lt-radius-sm);
    height: 1.5rem;
    padding: 0 var(--lt-space-4);
    font: inherit;
    font-size: var(--lt-text-caption);
    cursor: pointer;
    white-space: nowrap;
}

    .lt-rail__toggle:hover {
        background: var(--lt-rail-hover);
    }

/* Collapsed: captions and labels go, glyphs stay centred. */
:root[data-lt-rail="min"] .lt-rail__cap,
:root[data-lt-rail="min"] .lt-rail .lt-tx,
:root[data-lt-rail="min"] .lt-rail__brandtx {
    display: none;
}

:root[data-lt-rail="min"] .lt-rail a {
    justify-content: center;
    padding-inline: 0;
    gap: 0;
}

:root[data-lt-rail="min"] .lt-rail__brand,
:root[data-lt-rail="min"] .lt-rail__foot {
    justify-content: center;
    padding-inline: 0;
}

/* …and the icon rail keeps EVERY icon, folded group or not. A fold is a choice about the labelled list; with the
   captions — and so the toggles — hidden here, a fold that also hid icons could neither be seen nor undone. */
:root[data-lt-rail="min"] .lt-rail__fold a:not([aria-current="page"]) {
    display: flex;
}

/* ── The top bar ────────────────────────────────────────────────────────── */
.lt-topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    margin-left: var(--lt-rail-cur);
    display: flex;
    align-items: center;
    gap: var(--lt-space-5);
    min-height: var(--lt-topbar-h);
    padding: 0 var(--lt-space-6);
    background: var(--lt-surface);
    border-bottom: var(--lt-border);
}

/* Not an <h1>: every page in this app already owns one, and Routes.razor focuses the first `h1` on navigation.
   A heading here would swallow that focus and stop the announced heading changing between pages. */
.lt-topbar__title {
    margin: 0;
    font-size: var(--lt-text-title);
    font-weight: var(--lt-weight-semibold);
    white-space: nowrap;
}

.lt-topbar__spacer {
    flex: 1 1 auto;
}

/* Audit 18 (26/09/2026; owner Q3 «δεν είναι στοιχισμένο σωστα»): ONE height for everything on the top bar's row — the quick
   search, the initial dot, the buttons and the «Βλέπετε ως» button all read --lt-control-h-sm (24 px). They were 28 / 24 / 24 / 22. */
.lt-quick input {
    height: var(--lt-control-h-sm);
    width: 15rem;
    max-width: 32vw;
    padding: 0 var(--lt-space-4);
    border: var(--lt-border-strong);
    border-radius: var(--lt-radius-sm);
    background: var(--lt-surface);
    font: inherit;
    font-size: var(--lt-text-control);
}

    /* UX 20/10/2026, QS-1: a refused Enter («ΠΑ», too short to search) marks the box instead of doing nothing. The editors' mark
       (booking-editor.css `.bk-control.is-invalid`): an INSET shadow in --lt-due, never an outline, which is the focus ring and
       stays visible on the very box the caret is in. */
    .lt-quick input[aria-invalid="true"] {
        border-color: var(--lt-due);
        box-shadow: inset 0 0 0 1px var(--lt-due);
    }

/* No quick box on «Γενική Αναζήτηση» (AppShell's `lt-topbar--search`), at EVERY width since 01/11/2026 — owner, with the desktop
   screenshot: «giati exume 2 kutia kai malista se diaforetiko simeio?». It only feeds that page's own «Λέξη Κλειδί» / «Αρ. Κρ.»
   (QuickSearchQuery), which are right there in its filter card; on every other page it stays the way in. (UX 20/10/2026, MOB-ST
   had hidden it on a phone only.) */
.lt-topbar--search .lt-quick {
    display: none;
}

.lt-who {
    display: flex;
    align-items: center;
    gap: var(--lt-space-4);
    font-size: var(--lt-text-control);
    color: var(--lt-ink-2);
    white-space: nowrap;
}

    .lt-who a {
        color: var(--lt-accent-hover);
    }

    /* UX 20/10/2026, X20: «Προβολή ως…» is a link dressed as the bar's button (.lt-topbar__btn, below). As a flex item of .lt-who
       it takes the 24 px height, but a link's text would sit at the top of that box, so it centres the way a <button> does. The ink,
       the hover ink and the missing underline are the button's, restated because `.lt-who a` above outranks the bare class. */
    .lt-who a.lt-topbar__btn {
        display: inline-flex;
        align-items: center;
        color: var(--lt-ink-2);
        text-decoration: none;
    }

        .lt-who a.lt-topbar__btn:hover {
            color: var(--lt-accent-hover);
        }

.lt-who__dot {
    width: var(--lt-control-h-sm);
    height: var(--lt-control-h-sm);
    border-radius: 50%;
    background: var(--lt-accent-soft);
    color: var(--lt-accent-hover);
    display: grid;
    place-items: center;
    font-size: var(--lt-text-caption);
    font-weight: var(--lt-weight-bold);
}

.lt-topbar__btn {
    height: var(--lt-control-h-sm);
    padding: 0 var(--lt-space-4);
    border: var(--lt-border-strong);
    border-radius: var(--lt-radius-sm);
    background: var(--lt-surface);
    font: inherit;
    font-size: var(--lt-text-caption);
    color: var(--lt-ink-2);
    cursor: pointer;
    white-space: nowrap;
}

    .lt-topbar__btn:hover {
        border-color: var(--lt-accent-line);
        background: var(--lt-accent-soft);
        color: var(--lt-accent-hover);
    }

/* «Βλέπετε ως» — the impersonation strip, moved out of its own full-width band and into the bar, as the
   approved shell asks. It keeps the notice palette so it is still the loudest thing on the screen. */
.lt-imp {
    display: flex;
    align-items: center;
    gap: var(--lt-space-4);
    padding: var(--lt-space-2) var(--lt-space-5);
    border: 1px solid var(--lt-notice-line);
    border-radius: var(--lt-radius-sm);
    background: var(--lt-notice-soft);
    color: var(--lt-notice-ink);
    font-size: var(--lt-text-label);
    font-weight: var(--lt-weight-semibold);
    white-space: nowrap;
}

    .lt-imp button {
        height: var(--lt-control-h-sm);
        padding: 0 var(--lt-space-4);
        border: 1px solid var(--lt-notice-line);
        border-radius: var(--lt-radius-sm);
        background: var(--lt-surface);
        font: inherit;
        font-size: var(--lt-text-caption);
        color: var(--lt-notice-ink);
        cursor: pointer;
    }

/* ── The content column ─────────────────────────────────────────────────── */
.lt-main {
    margin-left: var(--lt-rail-cur);
    min-width: 0;
    padding: var(--lt-space-6);
    /* The CAP is the reading width itself — margin-left already moved the box past the rail, so adding the rail
       here would let the content run --lt-rail-w wider than the cap on an ultra-wide screen.
       1366px check: rail 216 + 2x16 gutter leaves 1118px of content and nothing scrolls sideways. */
    max-width: var(--lt-shell-page-max);
}

/* The booking editor keeps the width it already had (the deleted `.bk-wide`, NEW_BOOKING_SPEC §5.1): 16px
   gutters, capped at --lt-page-max (120rem). `.bk-wide` also centred itself with `margin-inline: auto`; here
   margin-left carries the rail offset, so the column is LEFT-aligned after the rail instead — deliberate, and the
   only visible difference is on a monitor wider than the rail plus 1920px.
   20/09/2026 — IT IS NO LONGER THE BOOKING EDITOR ALONE. The owner, on a 1920x1080 screen: «giati den
   ekmetaleyomaste ολη την οθονη. ειναι μια συνηθησμενη 1920*1080 δεν μιλαμε για ultra wide». The reading cap above
   is right for prose and forms and wrong for a data grid, so the GRID screens opt in here too (@layout WideLayout
   in Αναζήτηση, Πλάνο, Οικονομικά, Υπόλοιπα, Σύνολα περιόδου, Πληρωμές) instead of the cap being raised for every
   page. The arithmetic, in the register of the 1366px note above: at 1920 the rail takes 216px, 1704px remain and
   the 96rem cap wastes 168 of them; at 1366 only 1150px remain, so NEITHER cap binds and nothing moves. Note the
   missing TOP padding below — it is the booking editor's sticky action bar's requirement, and the 16px a grid page
   gives up by opting in. */
.lt-main--wide {
    max-width: var(--lt-page-max);
    padding: 0 var(--lt-space-6) var(--lt-space-6);
}

/* --lt-ink-2, not --lt-ink-3: the footer sits on --lt-ground (#EEF1F4), not on a white surface, and #66727E
   there measures 4.33:1 — under AA. Verified with an automated contrast audit, not by eye. */
.lt-shell-footer {
    margin-left: var(--lt-rail-cur);
    padding: var(--lt-space-5) var(--lt-space-6);
    color: var(--lt-ink-2);
    font-size: var(--lt-text-caption);
    text-align: center;
}

/* Focus must stay visible everywhere in the shell — the rail is dark, so the default ring can vanish. */
.lt-rail a:focus-visible,
.lt-rail__grp:focus-visible,
.lt-rail__toggle:focus-visible,
.lt-topbar a:focus-visible,
.lt-topbar button:focus-visible,
.lt-topbar input:focus-visible {
    outline: 2px solid var(--lt-accent);
    outline-offset: 1px;
}

.lt-rail a:focus-visible,
.lt-rail__grp:focus-visible {
    outline-color: var(--lt-on-accent);
}

/* «Παράβλεψη στο περιεχόμενο» — the first tab stop, visible only when focused. The rail holds ~30 links; without
   it a keyboard user walks all of them on every page. */
.lt-skip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 40;
    padding: var(--lt-space-3) var(--lt-space-5);
    background: var(--lt-accent);
    color: var(--lt-on-accent);
    border-radius: 0 0 var(--lt-radius-sm) 0;
    font-size: var(--lt-text-control);
}

    .lt-skip:focus {
        left: 0;
        color: var(--lt-on-accent);
    }

/* The skip link's target is focusable (tabindex="-1") only so that focus can LAND there; a ring around the whole
   page would be noise, and the user already knows where they went — they pressed the link that says so. */
.lt-main:focus {
    outline: none;
}

/* ── Phone-only chrome ─────────────────────────────────────────── */
/* The hamburger and the drawer's backdrop are rendered on EVERY page — <AppShell> is a WASM island and cannot
   read the viewport — so this is the one and only pair of rules the phone work adds OUTSIDE a media query, and
   all it does is take two BRAND-NEW elements out of the layout. `display:none` generates no box, and a
   `display:none` flex child does not even take the top bar's `gap`, so above the breakpoint the shell is the
   shell that shipped. Everything else new is inside the `max-width: 60rem` query below.
   UX 20/10/2026, MOB-P15: the drawer's «Κλείσιμο» and its account block (name · «Προβολή ως…» · «Αποσύνδεση») are two more
   brand-new elements of the same kind — rendered everywhere, drawn only in the query. */
.lt-burger,
.lt-scrim,
.lt-rail__close,
.lt-rail__account {
    display: none;
}

/* ── Phone / narrow: the rail becomes a drawer ──────────────────────────── */
/* Below 60rem the rail used to STAY on screen as an icons-only strip. On a phone that is a column of glyphs
   nobody can read, permanently eating the left edge — the owner's report of 20/09. So below the breakpoint the
   rail leaves the layout entirely (`--lt-rail-cur: 0`, the one property the content column, the top bar, the
   footer and the painted strip all read) and comes back only as an overlay drawer over a backdrop, with its
   full labels. 60rem is the breakpoint this file and home.css ALREADY share; there is deliberately no second
   one. The stored «full/min» choice is never written here, so the desktop the same person signs into is
   unchanged. */
@media (max-width: 60rem) {
    /* 1. The rail is out of the layout. BOTH selectors, because a media query adds no specificity and
       `:root[data-lt-rail="min"]` above is more specific than a bare `:root` — the booking screen's
       auto-collapse would otherwise put its 3.25rem strip back beside the drawer. */
    /* UX 20/10/2026, MOBILE P4 (owner 20/10 «Αποφάσισε εσύ»; built WITH P2, the editors' phone bar, never before it): a thumb's
       targets. Buttons and boxes 40 px (were 30), the small ones 36 (24), list rows 40 (26), a checkbox row 32 (18); the top bar 48
       (44 — the 44 px ☰ of MOB-P14 filled it to its border). Tokens only, so every staff screen that reads them follows; the grid's
       --lt-row-h stays (a customer row is a row of boxes, not a target list). The editors' sticky bar reads --lt-topbar-h for its
       `top`, so the two bars stay flush. */
    :root,
    :root[data-lt-rail="min"] {
        --lt-rail-cur: 0rem;
        --lt-control-h: 2.5rem;
        --lt-control-h-sm: 2.25rem;
        --lt-list-row-h: 2.5rem;
        --lt-check-row-h: 2rem;
        --lt-topbar-h: 3rem;
    }

    /* 2. The drawer. `visibility`, not only the transform, is what keeps its ~30 links out of the tab order and
       out of the accessibility tree while it is closed; it is delayed on the way out so the slide is seen.
       `z-index` is RAISED here, and only here: as a docked desktop column the rail's 30 was never contested,
       because the content column started after it (`margin-left: var(--lt-rail-cur)`) and could not overlap it.
       As an overlay the content starts at x=0 UNDER the drawer, so every page layer above 30 would paint over
       it — `.bk-actionbar` (booking-editor.css, sticky, z-index 40, opaque) is the confirmed one: it drew a
       white band across the open drawer and swallowed the taps aimed at the links behind it. Nothing between
       <body> and those layers opens a stacking context, so the numbers compete directly. See the backdrop
       below: the pair moves together or the band is simply undimmed instead of on top. */
    .lt-rail {
        width: min(var(--lt-rail-w), 84vw);
        box-shadow: var(--lt-shadow-edge);
        transform: translateX(-100%);
        visibility: hidden;
        transition: transform 180ms ease, visibility 0s linear 180ms;
        z-index: 60;
    }

    /* Set by <AppShell> in C#, not by the JS attribute the collapse rides on: the drawer then still opens for
       someone whose browser refused the interop, and C# stays the single source of truth for `aria-expanded`. */
    .lt-rail--open {
        transform: none;
        visibility: visible;
        transition: transform 180ms ease, visibility 0s 0s;
    }

    /* 3. The drawer is NEVER the collapsed strip: full labels whatever `data-lt-rail` says. These repeat the
       collapsed selectors verbatim because they have to match their specificity in order to beat them. The
       attribute itself is left alone — the booking screen's auto-collapse is a desktop behaviour and stays. */
    :root[data-lt-rail="min"] .lt-rail__cap,
    :root[data-lt-rail="min"] .lt-rail .lt-tx,
    :root[data-lt-rail="min"] .lt-rail__brandtx {
        display: block;
    }

    :root[data-lt-rail="min"] .lt-rail a {
        justify-content: flex-start;
        padding-inline: var(--lt-space-5);
        gap: var(--lt-space-5);
    }

    :root[data-lt-rail="min"] .lt-rail__brand {
        justify-content: flex-start;
        padding-inline: var(--lt-space-5);
    }

    /* The fold is back in the drawer, because the drawer shows labels and toggles whatever `data-lt-rail` says — and
       the booking editor keeps «min» on a phone. The icon rail's restore selector verbatim, so it wins by order;
       without it every toggle on that one page would look dead. */
    :root[data-lt-rail="min"] .lt-rail__fold a:not([aria-current="page"]) {
        display: none;
    }

    /* «Μάζεμα σε εικονίδια» is desktop-only: there is no collapsed drawer to toggle into. */
    .lt-rail__foot {
        display: none;
    }

    /* 4. The backdrop, directly under the drawer (55 / 60) and over everything the page itself can raise. Those
       two numbers are one decision: they clear the page layers that outrank a docked rail's 30 — `.bk-actionbar`
       (40) and `.bk-menu__list` (50) — and stay well under `.bk-modal` (1080), so a dialog still covers the
       drawer rather than the other way round. Dimming has to clear the SAME layers as the drawer: at 25 the
       action bar painted over the backdrop too, so the band was not even greyed. The dim is the rail's own dark
       surface at 45%, so no new colour enters the palette.
       `cursor: pointer` is not decoration. Blazor binds `@onclick` through a single document-level delegator,
       and iOS Safari does not propagate clicks on a non-interactive element (a bare <div>) to document-level
       listeners unless it carries `cursor: pointer`. Without it the backdrop tap — the only exit left on a
       touch device, since Esc wants a keyboard, a link pick navigates away and the ☰ is underneath the open
       drawer — silently does nothing, leaving the drawer open over a scroll-locked page. */
    .lt-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 55;
        background: var(--lt-rail-bg);
        opacity: .45;
        cursor: pointer;
    }

    /* 5. The page behind does not scroll while the drawer is open. On the root element as WELL as on `body`:
       iOS Safari ignores `overflow: hidden` on `body` alone. The attribute is js/shell.js's. */
    :root[data-lt-drawer="open"],
    :root[data-lt-drawer="open"] body {
        overflow: hidden;
    }

    /* 6. The hamburger, first in the top bar. Three bars drawn from `currentColor` rather than the «☰» glyph,
       which is missing from enough Android fonts to land as tofu on the one device this is for.
       UX 20/10/2026, MOB-P14: 2.75rem square (it was 2rem, a 32 px target measured 20/10) — the top bar's own height, so the
       bar does not grow. */
    .lt-burger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: none;
        width: 2.75rem;
        height: 2.75rem;
        border: var(--lt-border-strong);
        border-radius: var(--lt-radius-sm);
        background: var(--lt-surface);
        color: var(--lt-ink-2);
        cursor: pointer;
    }

        .lt-burger span {
            width: 1rem;
            height: 2px;
            background: currentColor;
            box-shadow: 0 -.3125rem 0 currentColor, 0 .3125rem 0 currentColor;
        }

    /* 7. The top bar has to survive a 360px screen with nothing overflowing. Not by a pixel budget — the
       impersonation strip would rot it — but by making the elastic things genuinely elastic (`min-width: 0` plus a
       live shrink factor) and leaving only the hamburger and the avatar at their min-content width.
       UX 20/10/2026, G-4: `flex-wrap`, for ONE item — «Βλέπετε ως … · Προβολή μόνο» + «Επιστροφή», the loudest state in the
       app (you are not yourself), which an ellipsis cut to a stub. It takes a line of its own under the bar (below); nothing
       else can wrap, because the quick box's basis is 0 (52vw at most while focused) and the other two items are fixed — ARITH:
       burger 44 + avatar 24 + gaps 16 + padding 24 leave 52vw room down to a 225 px screen. While it shows, the bar is taller
       than --lt-topbar-h (which the editors' sticky action bar reads). Wave 2 (review): P4's 3rem did not cover a strip on its own
       line, so while it shows the editors' bar is NOT sticky on a phone (booking-editor.css, the G-4 screen block after its print
       block: `html:has(.lt-imp) .bk-actionbar`) — impersonation is view only, and the token stays a constant (it is also this bar's
       min-height). */
    .lt-topbar {
        gap: var(--lt-space-4);
        padding: 0 var(--lt-space-5);
        flex-wrap: wrap;
    }

    /* UX 20/10/2026, MOB-P14 («μην το μπουκώνεις», owner 23/09/2026): no page title in the bar on a phone. It was ellipsised to a
       stub (flex-shrink 3) right above the same words — every page's own <h1>, which FocusOnNavigate lands on; the room goes to
       the quick box. The desktop bar keeps its title. */
    .lt-topbar__title {
        display: none;
    }

    /* The spacer's job — push the right-hand group over — is the quick box's now (it grows); `margin-left: auto` on .lt-who
       below keeps that true where there is no quick box (signed out, or «Γενική Αναζήτηση»). */
    .lt-topbar__spacer {
        display: none;
    }

    /* MOB-P14: the quick box takes all the room the title left (it kept 66-70 px, measured 20/10). Basis 0 rather than `auto`:
       with the bar able to wrap (G-4), an `auto` basis — the input's intrinsic ~20 characters — could push the box onto a line of
       its own on a very narrow screen; from 0 it only ever grows. The focus growth below stays (it no longer changes the width,
       which is already the most the bar has) so the reduced-motion answer keeps something to answer. */
    .lt-quick {
        flex: 1 1 0;
        min-width: 2.25rem;
        transition: flex-basis 150ms ease;
    }

        .lt-quick:focus-within {
            flex-basis: min(14rem, 52vw);
            flex-shrink: .05;
        }

        .lt-quick input {
            width: 100%;
            min-width: 0;
            max-width: none;
        }

    /* G-4 (UX 20/10/2026, «loud when not»): the strip's own full-width line, LAST (order 1; it comes before the quick box in
       the markup, so without the order it would push the box and the avatar down to a third line). Its words wrap instead of
       ellipsising — the name of whom you are viewing as is the point of it — and «Επιστροφή» is a 2.5rem target. */
    .lt-imp {
        order: 1;
        flex: 1 1 100%;
        min-width: 0;
        justify-content: space-between;
        margin-bottom: var(--lt-space-3);
        padding-inline: var(--lt-space-4);
        white-space: normal;
    }

        /* …and its own text, a flex item of a nested flex box, which needs the floor lifted there too. */
        .lt-imp span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .lt-imp button {
            flex: none;
            height: 2.5rem;
        }

    .lt-who {
        gap: var(--lt-space-3);
        margin-left: auto;
    }

    /* MOB-P15: «Προβολή ως…» and «Αποσύνδεση» are in the drawer's account block on a phone (below); the bar keeps the avatar.
       By their class, not `.lt-who a`: a signed-out bar's «Σύνδεση» link is not one of them and stays. The `a.` twin matches
       the desktop rule that makes the link inline-flex, which would otherwise outrank this one. */
    .lt-who .lt-topbar__btn,
    .lt-who a.lt-topbar__btn {
        display: none;
    }

    /* The name drops to the initial in the avatar beside it — VISUALLY only. `display: none` would take the
       account name out of the accessibility tree as well, and the dot is `aria-hidden`, so nothing would be left
       to announce; this is the ordinary visually-hidden recipe, so a screen reader still reads the name in full.
       (It replaces the 5rem truncation that was here: at 360px those five characters were the difference
       between a page title and no page title.) */
    .lt-who span:not(.lt-who__dot) {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .lt-main {
        padding: var(--lt-space-5) var(--lt-space-5);
    }

    /* 8. UX 20/10/2026, MOB-ST: no quick box on «Γενική Αναζήτηση» — since 01/11/2026 a rule for every width, above (`.lt-who`). */

    /* 9. UX 20/10/2026, MOB-P15 — the drawer for a thumb. Rows were ~30 px; a tap just beside a group's name landed on the
       caption <p>'s padding and RailClick shut the whole menu. Every row is 2.75rem, and the caption's padding moves ONTO its
       toggle (which stops the click), so a near miss folds the group instead of closing the drawer. The toggle's desktop
       geometry — into the caption's right padding but for --lt-space-2 — is kept by its own right padding. Only a caption that
       HOLDS a toggle: the «Φόρτωση…» caption before the permissions land keeps its padding. */
    .lt-rail a {
        min-height: 2.75rem;
    }

    .lt-rail__cap:has(> .lt-rail__grp) {
        padding: 0;
    }

    .lt-rail__grp {
        width: 100%;
        min-height: 2.75rem;
        padding: var(--lt-space-5) var(--lt-space-2) var(--lt-space-2) var(--lt-space-5);
    }

    /* «Κλείσιμο» in the brand row: over the right end of the brand link (its sibling in the markup), the row's full height. */
    .lt-rail__close {
        display: inline-flex;
        align-items: center;
        position: absolute;
        top: 0;
        right: 0;
        height: var(--lt-topbar-h);
        padding: 0 var(--lt-space-5);
        border: 0;
        background: transparent;
        color: var(--lt-rail-ink);
        font: inherit;
        font-size: var(--lt-text-control);
        cursor: pointer;
    }

        .lt-rail__close:hover {
            background: var(--lt-rail-hover);
        }

    /* The account block at the drawer's foot (the «Μάζεμα» foot is hidden above): the name, then «Προβολή ως…» and «Αποσύνδεση»
       as rows like the entries above them. */
    .lt-rail__account {
        display: flex;
        flex-direction: column;
        flex: none;
        border-top: 1px solid var(--lt-rail-line);
        padding: var(--lt-space-4) 0;
    }

    .lt-rail__who {
        padding: var(--lt-space-2) var(--lt-space-5);
        font-size: var(--lt-text-caption);
        color: var(--lt-rail-muted);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .lt-rail__account button {
        display: flex;
        align-items: center;
        min-height: 2.75rem;
        padding: 0 var(--lt-space-5);
        border: 0;
        background: transparent;
        color: var(--lt-rail-ink);
        font: inherit;
        font-size: var(--lt-text-control);
        text-align: left;
        cursor: pointer;
    }

        .lt-rail__account button:hover {
            background: var(--lt-rail-hover);
        }

    /* The dark rail's ring (the desktop block above draws it for the rail's links and toggles). */
    .lt-rail__close:focus-visible,
    .lt-rail__account button:focus-visible {
        outline: 2px solid var(--lt-on-accent);
        outline-offset: 1px;
    }

    /* 10. UX 20/10/2026, MOB-P3: every field 16 px on a phone. Under 16 px iOS Safari zooms the whole page on each tap into a
       field and stays zoomed — the seller pinched back out after every customer field (12-13 px: .bk-control, the find box,
       Bootstrap's -sm on Αναζήτηση / Πλάνο / Πληρωμές). Dialogs, calendars and suggestion lists render inside <main>, so they are
       covered; the top bar's quick box is the one field outside it. Every part keeps `.lt-` (ShellStyleGuardTests splits this
       list on its commas — so no comma inside the :not()s), and the viewport meta keeps zoom allowed: no maximum-scale, no
       user-scalable (UxPass2010BTests). The editors' grid widths that follow from it are booking-editor.css's. */
    .lt-main input:not([type=checkbox]):not([type=radio]),
    .lt-main select:not([multiple]),
    .lt-main textarea,
    .lt-topbar input {
        font-size: 1rem;
    }
}

/* The drawer slides and the search box grows; someone who has asked for less motion gets neither. A second
   `max-width: 60rem` query rather than a nested one — the same breakpoint, not a new one. */
@media (max-width: 60rem) and (prefers-reduced-motion: reduce) {
    .lt-rail,
    .lt-rail--open,
    .lt-quick {
        transition: none;
    }
}

/* ── Blazor's error bar ─────────────────────────────────────────────────── */
/* Global, not scoped: MainLayout and WideLayout each used to carry a private copy of these rules, because scoped
   CSS is rewritten per component and one copy could not reach the other's markup. One global block, one copy. */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    /* UX 20/10/2026, G-2: the right padding clears «Κλείσιμο» (absolute, right .75rem). With the old 1.25rem the first line ran
       under it at 320 px (MEASURED, harness-int/errbar.html); 6.5rem clears it at 320 / 375 / 414 / 1366. */
    padding: 0.6rem 6.5rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    /* UX 20/10/2026, G-2: the dismiss is a real <button type="button" class="dismiss">Κλείσιμο</button> in both layouts (it was a
       bare span with an emoji: no focus, no name). Blazor binds it by the class; the last four undo what the browser puts on a button. */
    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
        padding: 0;
        border: 0;
        background: none;
        font: inherit;
    }
