/* ============================================================
   damba-shell.css
   ============================================================
   Framework-level shell styling for all Damba web apps.
   Served as an RCL static asset at:
     /_content/Damba.WebUi/static/css/damba-shell.css

   Layered AFTER the Kendo theme CSS (which we do NOT own) and
   BEFORE each theme's site.css (which owns theme-specific tweaks).

   This file owns:
     - Shell grid structure (appbar / body / footer)
     - Width variables consumed from inline <style> emitted by _Layout
     - Brand slot, menu slot, login slot
     - SideRail drawer (push, grid column)
     - HamburgerOverlay drawer (fixed, no push) + backdrop + scroll-lock
     - .full-bleed escape hatch for landing pages
     - The package's own content vocabulary (.damba-sec*, .damba-event*, .damba-post-*,
       .damba-upload-*, .damba-map*) — structure only, colours via --kendo-color-* tokens.
       These are class names the PACKAGE emits, so they must be implemented here: _Layout
       loads only one theme sheet but always loads this one. See the section at the bottom.

   This file does NOT own:
     - Any .k-* selector (that's Kendo theme territory)
     - Any theme colors (those live in the theme's site.css)
     - Any font-family (this sheet loads AFTER the theme; declaring one would override brand)
     - Mobile media queries (emitted inline by _Layout from config)
   ============================================================ */

/* -- Base variable defaults --
   _Layout emits a leading <style>:root{...}</style> that overrides these
   with config-driven values. Keeping fallbacks here means damba-shell.css
   renders sanely even if the inline block is missing. */
:root {
    --appbar-w:         100vw;
    --content-w:        min(1140px, 100vw);
    --footer-w:         min(1140px, 100vw);
    --appbar-h:         48px;
    --drawer-collapsed: 50px;
    --drawer-expanded:  280px;
    --rail-w:           50px;
    --chrome-offset:    0px;
    --brand-logo-h:     32px;
}

/* -- Canonical admin form-field label — single source of truth --
   The Kendo theme ships `.k-label { margin:0 }` (typographically inert), so bare
   `k-label` labels inherit the field's CONTENT font and read as body text. This one
   rule (Layer 3, all hosts, all themes — it's `--kendo-*` token-based so it tracks
   light/dark) gives every stacked form-field label a distinct look: sm / semibold /
   subtle. Scoped to `> label` children of a Bootstrap column or `.k-form-field` so
   Kendo's floating / checkbox / validation `.k-label` variants stay untouched.
   See docs/DCL_Editor_Label_Typography_Concept.md. */
.k-form-field > .k-label,
.k-form-field > label,
[class*="col-"] > label.k-label,
[class*="col-"] > label.form-label {
    display: block;
    margin-block-end: var(--kendo-spacing-1, 0.25rem);
    font-size: var(--kendo-font-size-sm, 0.875rem);
    font-weight: var(--kendo-font-weight-semibold, 600);
    color: var(--kendo-color-subtle, #6c757d);
}

/* -- Shared app widgets (host-neutral; moved out of per-theme site.css) --
   Generic overlay + cookie-banner + large-icon helpers used by Core features
   (cookie consent / first-visit gate). Colors are intentionally neutral so
   each theme's site.css / _custom.scss can restyle if needed. */
.overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1000;
    display: none;
}
.cookie-banner {
    position: relative;
    z-index: 1001;
}
.icon-large {
    font-size: 1.5em;
    color: inherit;
}

/* -- A disabled button must LOOK disabled -----------------------------------------
   Kendo's entire treatment for a natively-disabled button is:

       .k-button:disabled, .k-button.k-disabled { box-shadow: none }

   That is all. The visible treatment — opacity, greyscale, default cursor, no pointer events —
   lives on the generic `.k-disabled` CLASS, which Kendo's JS widgets add themselves. A plain
   `<button class="k-button" disabled>` in Razor never gets that class, so it renders **identically
   to an enabled button**. Verified on /theme-test: enabled and disabled were indistinguishable for
   solid, outline, flat and link.

   This is the defect behind "I click the button and nothing happens" on the contact form: the
   submit button was disabled until the privacy box was ticked, looked perfectly clickable, and
   could not explain itself. That form no longer uses `disabled` — but every other view that does
   deserves not to hit the same trap.

   `:disabled` only. `.k-disabled` already works and is left to Kendo. */
.k-button:disabled,
.k-button[disabled] {
    opacity: var(--kendo-disabled-opacity, 0.65);
    filter: var(--kendo-disabled-filter, grayscale(0.1));
    cursor: default;
    pointer-events: none;
    box-shadow: none;
}

/* -- Coherent action buttons ------------------------------------------------------
   One spec for every icon action, whatever markup produced it. Three patterns existed side by
   side, measured on /admin/books/createedit:

     _AdminEditToolbar   .k-icon-button .k-toolbar-button .k-secondary   38x38, white on white
     form actions        .k-button-flat .k-rounded-md                    50x39, transparent
     Account sections    .k-button-solid .k-button-primary               40x40, solid navy

   Same kind of control, three sizes, three fills, and in the first case a 1px border whose colour
   equalled its background — a button with no visible edge at all. The `k-secondary` / `k-danger`
   family is Damba's own convention (299 usages incl. _AdminEditToolbar) that Kendo styles nowhere,
   which is why those rendered grey.

   The spec: neutral surface, a REAL 1px border so the control is a defined object, square-ish, and
   meaning carried by the glyph rather than by a block of fill. A five-action toolbar stays calm.

   Icon-only is detected two ways because both markups exist: Kendo's own `.k-icon-button`, and
   `:has(> i.bi:only-child)` for the hand-written ones.

   CORRECTED 2026-08-18. This claimed "text buttons are untouched". They were not:
   `:only-child` counts ELEMENT children, and a text node is not an element, so

       <button><i class="bi bi-files"></i>Copy / Split…</button>

   matched too — 24 buttons across the admin UI were forced into a 42x42 square with no padding,
   and their labels printed on top of each other. It surfaced on the incoming-message Routing bar.

   The fix is `min-width` instead of `width`: an icon-only button still lands on exactly 42px
   (12px inline padding either side + a ~16px glyph = 40px of content, so the minimum wins), while
   a button that also carries a label simply grows past it and keeps the padding it inherits from
   `.k-button`. No markup changes, no per-button opt-in to forget.

   Radius is NOT set here: the corner is a brand decision and lives in each theme's site.css. */
.k-button.k-icon-button,
.k-button:has(> i.bi:only-child) {
    min-width: var(--damba-btn-size, 42px);
    height: var(--damba-btn-size, 42px);
    padding-block: 0;
    border-width: 1px;
    border-style: solid;
}

/* A normal glyph (~16px) plus the inherited 12px inline padding is 40px, so the min-width above
   already lands those on a 42px square. `icon-large` does not fit: 26 + 24 = 50, and the button
   turns into a rectangle — visible on the AppBar's search / language / logout icons.

   Zeroing the inline padding for them is safe in a way the general case is not: `icon-large`
   appears on 9 buttons and NONE of them carries a label (verified across every .cshtml), so this
   selector cannot catch a text button the way `:only-child` did. If that ever changes, the label
   would sit flush against the border — which is visible immediately, not silent. */
.k-button:has(> i.bi.icon-large:only-child) {
    padding-inline: 0;
}

/* Fill and role colour are NOT here — they live in each theme's site.css, next to the corner
   radius, because "what an icon action looks like" is brand language rather than structure. This
   file only guarantees that every icon action is the same SIZE and carries a border box. */

/* -- Validation messages ---------------------------------------------------------
   `.k-error` is the class the Damba form contract mandates for validation messages
   (damba-create-adminui calls out `k-form-error` as "a wrong spelling that renders unstyled",
   and `k-error` as the correct token). Kendo itself does not style it.

   This lives HERE, not in a theme, because it is not a design choice — it is the difference
   between a validation error being visible and reading as ordinary body copy. It was written in
   the damba-default theme's _overrides.scss first, whose own comment said it belonged upstream;
   moving it means the three DARK themes get it too. Before this, measured per theme:

       damba-default 1 · sportinformatik 1 · rkckb26q2 0 · rkcdark26q1 0 · semanticode 0

   RkcKb — the live site — was one of the zeros, so every validation message there rendered as
   plain text at body size and colour.

   `:not(:empty)` is load-bearing: ValidationMessageFor emits the span unconditionally and leaves
   it empty for a valid field, so a bare `display:block` would add phantom spacing under every
   clean field on every form.

   error-on-surface, not error: the message sits on the page surface as text, and the fill colour
   is tuned for white-on-fill buttons rather than for text contrast. */
.k-error:not(:empty) {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--kendo-color-error-on-surface, #b3232a);
}

/* -- Focus: Kendo controls own their own focus treatment -------------------------
   A theme's site.css may define a house focus ring as a bare `:focus-visible` rule
   (damba-default and sportinformatik both do, in the brand accent). That selector matches
   EVERY focusable element, including Kendo's — so a Kendo control ends up with two rings in
   two different colours.

   Which one you actually SEE was decided by DOM nesting rather than by design, which is why
   this looked like a Login-page bug rather than a global one:

     - A real Kendo widget renders <span class="k-input"><input class="k-input-inner"></span>.
       Focus lands on the inner input, and the wrapper's `overflow: hidden` CLIPS its outline
       away. You see only Kendo's own ring. (The admin Edit-User form.)
     - A plain <input class="k-input …"> — the pattern used across the whole anonymous area:
       Login, Register, ResetPassword, ForgotPassword, 2FA, ExternalLogin, Contact — IS the
       outermost element. Nothing clips it, so the accent outline shows and Kendo's ring is
       what gets lost. (The Login page.)

   Specificity is why the accent won in the second case: a bare `:focus-visible` is (0,1,0) and
   `.k-input` is also (0,1,0), so the later stylesheet — site.css, layer 4 — took it. The
   selectors below are (0,2,0) and therefore win from layer 3 regardless of source order, which
   is what lets this live in the package and cover every theme, present and future.

   NOT an accessibility regression: each of these carries a verified box-shadow focus ring of
   its own, built from --kendo-color-primary. Never add a control here without first confirming
   the Kendo theme gives it a visible focus indicator. */
.k-input:focus-visible,
.k-input-inner:focus-visible,
.k-textarea:focus-visible,
.k-picker:focus-visible,
.k-checkbox:focus-visible,
.k-radio:focus-visible {
    outline: none;
}

/* Thumbnail placeholder icon — the glyph an admin list row shows in its image slot
   when the record has no picture (AppUsers, AppRoles, Books, Events, Instructors, …).

   WHY THIS CLASS EXISTS. These eight icons hard-coded Bootstrap's `text-white`, which is
   not a colour so much as an assumption that the surface behind it is dark. That held while
   every Damba theme was dark; it broke the moment a light theme shipped (damba-default,
   sportinformatik), where the glyph rendered white-on-white and simply vanished. Nothing
   errors — the icon is there, drawn in the background colour.

   Two properties make this theme-proof:
     - --kendo-color-subtle is emitted by EVERY compiled Kendo theme, and each theme sets it
       to the right end of its own scale (#4a6d94 on damba-default, #9EA6AB on rkcdark26q1,
       rgba(246,249,237,.7) on rkckb26q2). So the icon follows the theme instead of fighting it.
     - It is a MUTED tone, not the body colour. A 60px glyph in full text colour out-shouts the
       title beside it; this is a placeholder for a missing picture, not content.

   The same lesson as the MenuItems grid, which never had the bug because it sets no colour at
   all and inherits currentColor. Inheriting is always safe; naming a literal colour is only
   safe when you also own the background. */
.damba-thumb-icon {
    color: var(--kendo-color-subtle, #6c757d);
}

/* -- Shell grid: appbar row / body row / footer row -- */
.app-shell {
    display: grid;
    grid-template-rows: auto 1fr auto;
    min-height: 100vh;
}

/* -- AppBar row --
   Two elements with separated concerns:
     .app-appbar-row — pure layout: sticky grid row spanning the full viewport,
                       carries no chrome. Owns the appbar height.
     .app-appbar     — the visible AppBar. Carries `k-appbar k-appbar-primary`
                       so Telerik's theme paints it natively (single source of
                       truth — no overrides). Sized by --appbar-w, so:
                         AppBar.Mode = Full        → spans the viewport
                         AppBar.Mode = Fixed/Fluid → centered, theme paints only the centered box
                       This makes AppBarPlacement = CenteredOverContent work
                       without touching the theme paint at all. */
.app-appbar-row {
    position: sticky;
    top: 0;
    z-index: 1000;
    height: var(--appbar-h);
    /* In centered mode this row is wider than its visible chrome (.app-appbar)
       and sits at z-index 1000 — without this, the transparent left/right
       gutters would silently swallow clicks meant for the rail's top menu
       items. pointer-events: none lets clicks fall through to whatever is
       behind (the rail in centered mode, nothing in FullWidth mode). */
    pointer-events: none;
}
.app-appbar {
    display: flex;
    align-items: center;
    gap: 1rem;
    height: 100%;
    width: var(--appbar-w);
    margin: 0 auto;
    padding: 0 1rem;
    min-width: 0;
    /* Re-enable pointer events on the visible chrome so the brand link,
       hamburger, top menu, and login widgets stay interactive. */
    pointer-events: auto;
}

/* Brand slot — left of the menu slot. Flex-start, never grows. */
.app-brand {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    text-decoration: none;
    color: inherit;
    white-space: nowrap;
}
.app-brand:hover { text-decoration: none; opacity: 0.9; }
.app-brand-logo  { max-height: var(--brand-logo-h); width: auto; display: block; }
.app-brand-text  { font-weight: 600; font-size: 1.05rem; }

/* Menu slot — grows to fill available space. Alignment modifiers for text menus. */
.app-menu-slot {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    min-width: 0;
}
/* -- Top menu (MenuLayout.TopMenu) --
   Same job the .app-rail rules below do for the drawer's PanelBar: a Kendo widget
   dropped into a shell container needs the container's colours, and the theme has
   no way to know it landed on one.

   Two defects, both invisible until 2026-08-17, because until then the top menu
   never rendered at all (it fetched its items from a route that did not exist):

   1. CONTRAST. Telerik colours menu items from `.k-menu:not(.k-context-menu) > .k-item`
      — a value chosen for a menu sitting on a light page. On `k-appbar-primary` that
      is the AppBar's own blue on the AppBar's own blue.

      The colour is set EXPLICITLY, and on the .k-link as well as the .k-item. The
      obvious `color: inherit` on .k-item alone was tried first and measurably does not
      win, even at higher specificity and even with !important — the painted text kept
      Telerik's value. Rather than keep escalating a selector fight whose outcome could
      not be explained, this states the value the AppBar already uses for its brand and
      login widget. Verified in the browser, not reasoned about: white on blue, and the
      submenu still dark-on-light.

      Scoped to the ROOT list on purpose (`> .k-item`). The popup is a separate
      `.k-menu-group` and already renders dark-on-light correctly — painting the
      AppBar's near-white there would make it white on white.

   2. CLIPPING. Telerik sets `.k-appbar { overflow: hidden }`, and a horizontal Kendo
      Menu keeps its popup INSIDE the <li> rather than appending it to <body>. A 48px
      AppBar therefore cuts every submenu off at its own bottom edge: the popup opens,
      and nothing is visible. `:has()` keeps the default clipping for AppBars that
      carry no menu. */
.app-appbar:has(.k-menu) { overflow: visible; }
.app-appbar .k-menu { background: transparent; }
.app-appbar .k-menu > .k-item,
.app-appbar .k-menu > .k-item > .k-link { color: var(--kendo-color-on-primary, #fff); }

/* Icon + Text je Eintrag (MenuItem.Icon, eine Bootstrap-Icon-Klasse).
   Nicht auf die AppBar beschränkt: das Popup hängt zwar im DOM unter .app-appbar, aber die
   Regel soll auch dort greifen, damit Wurzel und Untermenü dieselbe Ausrichtung haben.
   Anders als im Drawer KEINE feste Icon-Breite — die gibt es dort nur, damit Icons in der
   eingeklappten 50-px-Leiste übereinander stehen. Waagerecht wäre sie bloß eine Lücke. */
.appbar-menu-item { display: inline-flex; align-items: center; gap: .4rem; }
.appbar-menu-icon { font-size: 1rem; line-height: 1; }

.app-menu-slot.align-left    { justify-content: flex-start; }
.app-menu-slot.align-center  { justify-content: center; }
.app-menu-slot.align-right   { justify-content: flex-end; }

/* Login slot — right of menu slot, never grows. */
.app-login-slot {
    flex: 0 0 auto;
    padding-right: .5rem;
}

/* Hamburger button (shared between SideRail and HamburgerOverlay modes) */
.app-hamburger {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    cursor: pointer;
    color: inherit;
    padding: 0 .5rem;
    height: 100%;
}
.app-hamburger .bi { font-size: 1.6em; line-height: 1; }

/* -- Body row --
   Default: single-column (TopMenu / None / HamburgerOverlay modes).
   .has-rail: two columns (rail + content) — SideRail mode only. */
.app-body {
    display: grid;
    min-width: 0;
    grid-template-columns: 1fr;
}
.app-shell.has-rail .app-body {
    grid-template-columns: var(--rail-w) 1fr;
    transition: grid-template-columns .25s ease-out;
}
.app-body > .center-pane { min-width: 0; }

/* The 1rem gutter is declared HERE, not as Bootstrap's `px-3` on the <main>.
   Utilities carry !important, so while the gutter was a utility no rule could
   override it — the landing-page exception below was served, matched, and did
   nothing, measured as 16px still applied. A shell dimension the shell needs to
   vary cannot live in someone else's !important. */
.center-pane {
    width: var(--content-w);
    margin: 0 auto;
    padding-inline: 1rem;
}

/* -- Landing pages reach the column edge --
   For a page of TEXT the gutter is right: it insets body copy by the same 1rem
   the AppBar insets its brand and widgets, so a heading and the logo share a
   left edge.

   A landing page does not lay out text, it paints bands. There the same gutter
   makes every band 2rem narrower than the AppBar above it. Invisible while the
   AppBar spans the viewport — the two were never comparable — and obvious the
   moment AppBarPlacement.CenteredOverContent puts them on the same width, which
   is where this was found.

   Zeroed on the pane rather than pulled back with a negative margin on
   .landing-content: a margin would have to repeat the gutter's value and would
   silently drift the day that value changes above.

   .full-bleed inside stays correct — its `50% - 50vw` is relative to its
   containing block, so it lands on the viewport edge for any pane width. */
.center-pane:has(> .landing-content) {
    padding-inline: 0;
}

/* -- SideRail drawer (grid column) -- */
.app-rail {
    grid-column: 1;
    background: var(--kendo-color-surface-alt, #141d38);
    border-right: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
    overflow: hidden;
    position: sticky;
    top: var(--appbar-h);
    height: calc(100vh - var(--appbar-h));
}
.app-rail-inner {
    width: var(--drawer-expanded);
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
}
.app-rail .k-panelbar { background: transparent; border: none; }

/* Drawer menu item layout — specificity must beat Kendo's
   .k-panelbar > .k-panelbar-header > .k-link (0,3,0) and
   .k-panelbar .k-panelbar-group > .k-panelbar-item > .k-link (0,4,0) */
.app-rail .k-panelbar .k-panelbar-item .k-link {
    padding-inline: 0;
}
.app-rail .k-panelbar .k-panelbar-toggle {
    margin-inline-end: .75rem;
}
.drawer-item {
    display: inline-flex;
    align-items: center;
}
.drawer-icon {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    width: var(--drawer-collapsed);
    flex-shrink: 0;
}
.drawer-text { white-space: nowrap; }

/* Rail brand header (optional, when BrandPosition == RailHeader) */
.app-rail .app-brand {
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
    width: var(--drawer-expanded);
}

/* -- SideRail FloatOver variant (fixed, no grid column, no backdrop) -- */
.app-shell.has-rail-float .app-body {
    grid-template-columns: 1fr;
}
.has-rail-float .app-rail {
    position: fixed;
    top: var(--appbar-h);
    left: 0;
    bottom: 0;
    width: var(--drawer-collapsed);
    z-index: 999;
    overflow: hidden;
    transition: width .25s ease-out;
}
.has-rail-float .app-rail.expanded {
    width: var(--drawer-expanded);
}
/* Collapsed rail: remove sub-menu indentation so all icons align */
.app-rail:not(.expanded) .k-panelbar .k-panelbar-group > .k-panelbar-item .k-link {
    padding-inline-start: 0;
}

/* -- HamburgerOverlay drawer (fixed, transforms in/out, no grid push) -- */
.app-overlay-drawer {
    position: fixed;
    top: var(--appbar-h);
    left: 0;
    bottom: 0;
    width: var(--drawer-expanded);
    max-width: 100vw;
    background: var(--kendo-color-surface-alt, #141d38);
    border-right: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
    transform: translateX(-100%);
    transition: transform .25s ease-out;
    z-index: 999;
    overflow-y: auto;
    overflow-x: hidden;
}
.app-overlay-drawer.expanded { transform: translateX(0); }

.app-overlay-drawer .app-brand {
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
}

/* Overlay backdrop — only visible when body.drawer-overlay-open is set */
.app-overlay-backdrop {
    display: none;
    position: fixed;
    inset: var(--appbar-h) 0 0 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 998;
}
body.drawer-overlay-open { overflow: hidden; }
body.drawer-overlay-open .app-overlay-backdrop { display: block; }

/* Rail backdrop — used on mobile when SideRail falls back to overlay via emitted media query */
.app-rail-backdrop { display: none; }

/* -- Centered AppBar mode --
   Triggered by CoreOptions.Widths.AppBarPlacement = CenteredOverContent (desktop only;
   mobile always renders FullWidth via the layout's !isMobile guard). The AppBar
   itself centers automatically — its width is var(--appbar-w), so setting
   Widths.AppBar to match Widths.Content gives a centered Telerik chrome with no
   theme override needed. This block only relocates the SideRail drawer.

   SideRail: leaves the grid; RIGHT edge anchored at content's LEFT edge, width
   grows leftward into the otherwise-empty left margin when expanded. Content does
   NOT reflow (P4's JS keeps --chrome-offset at 0 so .full-bleed stays centered).

   Narrow desktop viewports (where (viewport - content) / 2 < drawer width): the
   min() clamp keeps the drawer's LEFT edge on-screen, so it overlays the content
   from the viewport's left inward — z-index keeps it above .center-pane. Without
   the clamp the fixed right edge pushed the drawer past the viewport's left edge
   and the expanded menu was simply cut off. The clamp is width-specific because
   right + width together decide the left edge: capping the collapsed rail with
   the expanded width would shove it into the content on viewports where the
   collapsed rail still fits. */
.app-shell.appbar-centered.has-rail .app-body {
    grid-template-columns: 1fr;
}
.app-shell.appbar-centered.has-rail .app-rail {
    position: fixed;
    top: 0;              /* aligns with AppBar top — drawer lives in the empty left
                            margin, never overlaps the centered AppBar horizontally. */
    bottom: auto;        /* don't stretch to viewport bottom… */
    height: auto;        /* …fit the menu's intrinsic height instead. */
    max-height: 100vh;   /* safety: if the menu grows beyond the viewport, cap it
                            so the inner's overflow-y: auto can scroll it. */
    right: min(calc(50vw + var(--content-w) / 2), calc(100vw - var(--drawer-collapsed)));
    left: auto;
    width: var(--drawer-collapsed);
    z-index: 999;
    transition: width .25s ease-out, right .25s ease-out;
    grid-column: auto;
    border-right: none;
    border-left: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
}
.app-shell.appbar-centered.has-rail .app-rail.expanded {
    width: var(--drawer-expanded);
    right: min(calc(50vw + var(--content-w) / 2), calc(100vw - var(--drawer-expanded)));
}

/* CenteredOverContent placement + Full-width AppBar: the AppBar chrome still spans
   the full viewport, so anchoring the drawer to the content's left edge no longer
   makes sense — the AppBar isn't constrained to the content column. Revert to
   regular left-side rail behavior: anchored to viewport left, grows rightward,
   sits below the AppBar (so its first row isn't hidden by the chrome). */
.app-shell.appbar-centered.appbar-fullwidth.has-rail .app-rail {
    top: var(--appbar-h);
    max-height: calc(100vh - var(--appbar-h));
    left: 0;
    right: auto;
    border-left: none;
    border-right: 1px solid var(--kendo-color-border, rgba(255, 255, 255, 0.08));
}

/* -- Footer row -- */
.app-footer .footer-content {
    width: var(--footer-w);
    margin: 0 auto;
    padding: 0 1rem;
}

/* -- .full-bleed escape hatch --
   Breaks out of .center-pane to span the viewport width (minus any chrome
   offset produced by an active rail). Usage:
     <section class="full-bleed">
         <div class="container">inner capped content</div>
     </section>
*/
.full-bleed {
    width: calc(100vw - var(--chrome-offset, 0px));
    margin-left:  calc(50% - 50vw + var(--chrome-offset, 0px) / 2);
    margin-right: calc(50% - 50vw - var(--chrome-offset, 0px) / 2);
}

/* -- admin-page-header actions slot --
   The Kendo ToolBar component wraps our action buttons in a .k-toolbar
   container with its own background, border, and internal padding. Inside
   the page header that chrome visually misaligns the rightmost button from
   the grid's right edge (the toolbar's padding creates a scrollbar-width-
   sized gap). Strip it so the buttons sit directly on the page background,
   flush with the grid below. */
.admin-page-header-actions > .k-toolbar,
.admin-page-header-actions > .k-widget.k-toolbar {
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
}

/* -- admin-panel-actions: description (left) + Add button (right) inside a PanelBar item --
   Wraps the row that contains a description text plus an icon-only "+" toolbar
   above a sub-items list.

   Two non-obvious bits:

   1. Strips Kendo ToolBar chrome the same way .admin-page-header-actions does
      (background / border / internal padding) so the spacing is driven only by
      this wrapper's own margin-bottom rather than stacking three sources of
      vertical air (panel p-3 + toolbar chrome + Bootstrap mb-3).

   2. Forces `flex: 0 0 auto` and `width: auto` on the toolbar. Kendo's stock
      .k-toolbar ships with `width: 100%`, which would otherwise grab the entire
      row and force the description below — even though we placed it as the
      second flex child with `flex-wrap`. This override lets the toolbar size
      to its content (just the icon-only "+") so the description's flex-grow
      can fill the remaining row space, and on narrow viewports flex-wrap
      breaks the toolbar onto its own line under the description. */
.admin-panel-actions {
    margin-bottom: 0.5rem;
}
.admin-panel-actions > .k-toolbar,
.admin-panel-actions > .k-widget.k-toolbar {
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
    flex: 0 0 auto;
    width: auto;
}

/* -- .admin-list-row: server-rendered admin list item (whole row clickable) --
   Replaces the ad-hoc `border-bottom py-2 d-flex align-items-center` block
   used across admin edit pages for child-entity lists (appointments, agenda
   items, sub-pages, …). Layout:

     [        anchor (icon + content + chevron)        ][  actions  ]

   `<a class="admin-list-row-link">` covers the click target; sibling
   `<div class="admin-list-row-actions">` holds Up/Down/Delete buttons that
   stay outside the anchor (no event.stopPropagation needed).

   Hover background hints clickability — the cursor:pointer alone wasn't
   pulling its weight on dense lists. */
.admin-list-row {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--kendo-color-border, rgba(0, 0, 0, 0.1));
    padding-block: 0.5rem;
    transition: background-color 0.15s ease;
}
.admin-list-row:hover {
    background-color: var(--kendo-color-base-hover, rgba(0, 0, 0, 0.04));
}
.admin-list-row > .admin-list-row-link {
    display: block;
    text-decoration: none;
    color: inherit;
    flex-grow: 1;
    min-width: 0;
}
.admin-list-row > .admin-list-row-link:hover {
    color: inherit;
    text-decoration: none;
}
.admin-list-row > .admin-list-row-actions {
    display: flex;
    align-items: center;
    padding-inline-start: 0.5rem;
    gap: 0.25rem;
    flex-shrink: 0;
}

/* -- .stage-grid: icon-only Kendo Grid command + toolbar buttons --
   Add `.HtmlAttributes(new { @class = "stage-grid" })` to a Kendo Grid that
   uses Edit/Destroy/Update/Cancel commands and ToolBar.Create() declared
   with .Text(" "). The space character keeps the button non-empty (Kendo
   would otherwise render the default label) but takes no visible space;
   this rule then hides the text span entirely so only the auto-generated
   icon and the `title` tooltip remain.

   Reference implementation: EventTemplates/CreateEdit.cshtml — Rabat and
   Cancellation stage grids inside the PanelBar. */
.stage-grid .k-grid-add .k-button-text,
.stage-grid .k-grid-edit .k-button-text,
.stage-grid .k-grid-update .k-button-text,
.stage-grid .k-grid-cancel .k-button-text,
.stage-grid .k-grid-delete .k-button-text {
    display: none;
}
.stage-grid .k-grid-add,
.stage-grid .k-grid-edit,
.stage-grid .k-grid-update,
.stage-grid .k-grid-cancel,
.stage-grid .k-grid-delete {
    min-width: 0;
    padding-inline: 0.5rem;
}

/* Subtitle-as-link in <admin-page-header> for IUrl entities. Auto-rendered by the TagHelper
   when for="@Model" is bound to a VM whose entity has a registered {name}ByUrl public route.
   The link wraps the subtitle text itself — clicking anywhere on the subtitle line opens the
   public detail page in a new tab. Visually subtle: inherits the muted subtitle color, hover
   reveals an underline as a clickability hint. */
.admin-page-header-subtitle-link {
    color: inherit;
    text-decoration: none;
    transition: color 0.15s ease-in-out;
    cursor: pointer;
}
.admin-page-header-subtitle-link:hover,
.admin-page-header-subtitle-link:focus {
    color: var(--bs-link-hover-color, var(--kendo-color-primary, #0d6efd));
    text-decoration: underline;
}


/* ============================================================================
   Generalized upload gallery (_UploadGallery.cshtml + damba.webui.upload-gallery.js)
   The item list IS the drop target: a dashed dropzone that holds the file cards,
   shows a "drop here" hint, highlights on drag-over, and dims while uploading.
   ============================================================================ */
.damba-upload-gallery {
    position: relative;
}
.damba-upload-gallery .damba-upload-open {
    line-height: 1;
}
/* Smaller glyph for the per-card delete icon (the folder-open button keeps the standard
   Damba button icon size so it matches the page's other buttons). */
.damba-upload-gallery .damba-upload-del .bi {
    font-size: 0.8rem;
}
.damba-upload-dropzone {
    position: relative;
    border: 2px dashed var(--kendo-color-border, #d1d5db);
    border-radius: var(--kendo-border-radius-md, 6px);
    padding: 1rem;
    min-height: 8rem;
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out;
}
.damba-upload-dropzone.is-empty {
    display: flex;
    align-items: center;
    justify-content: center;
}
.damba-upload-dropzone.is-dragover {
    border-color: var(--kendo-color-primary, #0d6efd);
    background-color: color-mix(in srgb, var(--kendo-color-primary, #0d6efd) 8%, transparent);
}
/* The "drop here" hint: shown centered when empty; a subtle top strip otherwise. */
.damba-upload-hint {
    color: var(--kendo-color-subtle, #6b7280);
    font-size: 0.85rem;
    pointer-events: none;
    text-align: center;
}
.damba-upload-dropzone:not(.is-empty) .damba-upload-hint {
    margin-bottom: 0.75rem;
    opacity: 0.7;
}
.damba-upload-dropzone.is-dragover .damba-upload-hint {
    color: var(--kendo-color-primary, #0d6efd);
    opacity: 1;
}
.damba-upload-gallery.is-busy {
    opacity: 0.6;
    pointer-events: none;
}
.damba-upload-item .k-card-image {
    width: 100%;
}

/* ============================================================
   Public map page (Areas/Core/Map) — host-neutral layout;
   colours track the active Kendo theme via --kendo-color-* tokens
   (RkcKb: burgundy surface / red primary).
   ============================================================ */
.damba-map {
    height: 600px;
    width: 100%;
    border: 1px solid var(--kendo-color-border, rgba(0, 0, 0, 0.12));
    border-radius: var(--kendo-border-radius-md, 6px);
    overflow: hidden;
}
.damba-map-filters {
    position: sticky;
    top: 1rem;
}
.damba-map-filters .k-label {
    font-weight: 600;
}
/* Marker click-popup (rendered inside the Kendo tooltip) — a flat list of links, one per line. */
.damba-map-pop {
    min-width: 180px;
    font-size: 0.9rem;
    line-height: 1.4;
}
.damba-map-pop-item {
    margin: 0.12rem 0;
}
.damba-map-pop a {
    color: var(--kendo-color-primary, #0d6efd);
    text-decoration: none;
}
.damba-map-pop a:hover {
    text-decoration: underline;
}

/* ============================================================================
   Package content vocabulary — section bands + date-led rows + post meta.

   WHY THIS LIVES IN damba-shell.css AND NOT IN A THEME:
   these class names are a MARKUP CONTRACT the package itself emits —
     .damba-sec*    Areas/Admin/CardGrids/_CardGridPreviewModal.cshtml writes them into
                    CardGrid data as the "surface" choice, so they arrive from the database
     .damba-event*  Areas/Core/Posts/Index.cshtml + _PostRow.cshtml
     .damba-post-*  Areas/Core/Posts/_PostRow.cshtml
   Until 2026-08-03 they were implemented ONLY in RkcKb's private theme, so the package's
   own post and event lists rendered completely unstyled on the other three hosts and on any
   fresh consumer of the NuGet package. _Layout loads exactly ONE theme sheet (the host's, or
   the packaged fallback) but ALWAYS loads this file — so a contract the package emits has to
   be implemented here, or every consumer is obliged to reimplement it.

   Structure only. Every colour comes from a --kendo-color-* token, so these track whatever
   Kendo theme the host ships, light or dark. No font-family is set anywhere below: themes
   own typography, and this sheet loads AFTER the theme, so declaring one would silently
   override the host's brand font.
   ============================================================================ */

/* -- Section band --
   Seamless full-width bands inside the content column: no gaps, no rounding, alternating
   background rhythm. The three modifiers are surface ROLES, not literal colours — the names
   come from RkcKb (a dark theme) where "light" was the inverted band. On a light theme the
   inversion flips with the tokens, which is the intent: --dark is the page surface, --light
   is its inverse, --panel is a subtly raised surface. */
.damba-sec {
    margin: 0;
    border-radius: 0;
    padding: clamp(2.25rem, 5vw, 3.5rem) clamp(1.25rem, 3vw, 2.25rem);
}
.damba-sec--dark {
    background: var(--kendo-color-app-surface, #fff);
}
.damba-sec--light {
    background: var(--kendo-color-on-app-surface, #212529);
    color: var(--kendo-color-app-surface, #fff);
}
/* Raised panel. Most Kendo themes make base-subtle nearly equal to app-surface, which gives
   no visible step, so a theme that wants a distinct panel sets --damba-sec-panel-bg. It is a
   VARIABLE rather than a competing rule on purpose: this sheet loads after the theme, so a
   theme-side `.damba-sec--panel {background:…}` would lose the cascade. */
.damba-sec--panel {
    background: var(--damba-sec-panel-bg, var(--kendo-color-base-subtle, rgba(128, 128, 128, 0.08)));
}

/* -- Date-led row (events, posts) --
   Three-column grid: fixed date chip, flexible main, drill-in chevron. The whole row is one
   anchor, so colour is inherited and only the hover accents move. */
.damba-events {
    border-top: 2px solid var(--kendo-color-primary, #0d6efd);
}
.damba-event {
    display: grid;
    grid-template-columns: 84px 1fr auto;
    gap: 1.25rem;
    align-items: center;
    padding: 1.1rem 0;
    border-bottom: 1px solid var(--kendo-color-border, rgba(128, 128, 128, 0.25));
    color: inherit;
    text-decoration: none;
}
.damba-event-date {
    text-align: center;
    border-radius: var(--kendo-border-radius-md, 6px);
    padding: 0.45rem 0.25rem;
    background: var(--kendo-color-primary, #0d6efd);
    color: var(--kendo-color-on-primary, #fff);
}
.damba-event-date .d {
    font-size: 1.8rem;
    line-height: 0.9;
}
.damba-event-date .m {
    font-weight: 700;
    font-size: 0.6rem;
    letter-spacing: 0.12em;
}
.damba-event-main h3 {
    font-size: 1.25rem;
    margin: 0 0 0.3rem;
    transition: color 0.15s ease-in-out;
}
.damba-event:hover .damba-event-main h3 {
    color: var(--kendo-color-primary, #0d6efd);
}
.damba-event-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    font-size: 0.78rem;
    color: var(--kendo-color-subtle, #6c757d);
}
.damba-event-meta i {
    color: var(--kendo-color-primary, #0d6efd);
    margin-right: 0.3rem;
}
/* Muted drill-in chevron. The row is already a link, so this is an affordance, not a button —
   it takes the accent colour and nudges right only on row hover. */
.damba-event__go {
    display: grid;
    place-items: center;
    font-size: 1.3rem;
    color: var(--kendo-color-subtle, #6c757d);
    opacity: 0.55;
    transition: color 0.15s ease-in-out, opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
}
.damba-event:hover .damba-event__go {
    color: var(--kendo-color-primary, #0d6efd);
    opacity: 1;
    transform: translateX(3px);
}

/* -- Post extras --
   _PostRow reuses the event row and adds an excerpt and tag pills. Both were emitted with no
   rule anywhere before 2026-08-03: the excerpt rendered as an unstyled paragraph and the tags
   as a run-together line of bare text. */
.damba-post-desc {
    margin: 0.35rem 0 0;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--kendo-color-subtle, #6c757d);
}
.damba-post-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.5rem;
}
.damba-post-tag {
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--kendo-color-border, rgba(128, 128, 128, 0.25));
    border-radius: var(--kendo-border-radius-sm, 4px);
    color: var(--kendo-color-subtle, #6c757d);
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------------------------
   Busy spinner for in-band AI actions (Translations modal "Regenerate").

   These calls are a real LLM round-trip — 17 s measured on one DCL property with a small local
   model — so the button must show that work is happening. Until 2026-08-17 the modal instead
   closed and reloaded the page 600 ms after the request STARTED, which looked like success no
   matter what the server eventually answered.

   prefers-reduced-motion: the disabled state still communicates "busy" without the rotation.
   --------------------------------------------------------------------------------------------- */
.damba-spin {
    display: inline-block;
    animation: damba-spin 900ms linear infinite;
}

@keyframes damba-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .damba-spin { animation: none; }
}

/* ── Items-due badge on the account entry ────────────────────────────────────────────────
   The unread count in the AppBar (N-D8, D1). Three things here are measured, not chosen by
   eye — see docs/Items_Due_Implementation_Plan.md ID0.

   COLOUR. The badge sits on `.app-appbar`, which carries `k-appbar-primary` — a surface painted
   with --kendo-color-primary. So a `k-badge-solid-primary` badge is the SAME colour as the bar it
   is on: the pill vanishes and only the white digit remains, reading as a superscript rather than
   a notification. `k-badge-solid-error` is no better here; measured against this theme's primary
   (#03328f) it lands at 2.01:1, under the 3:1 a non-text element needs to be seen at all.

   The pairing below is the theme's own guarantee instead: whatever a theme picks for primary, it
   promises on-primary is legible on it. That is the same contract the AppBar's own text relies on,
   so the badge inherits it — and it inverts correctly on a light-primary theme, where on-primary
   is dark. Measured 11.12:1 on the default theme.

   PLACEMENT. Kendo's `k-badge-edge k-top-end` translates by (12.4px, -11.2px), which pushed the
   badge ABOVE the AppBar entirely and 12px into the search button — whose left edge is exactly the
   account entry's right edge, so there is no horizontal room to overhang into at all. It is
   positioned inside the container instead, which is the only placement that cannot clip or collide.

   SHAPE. Equal min-width and height keep one and two digits circular; "99+" widens into a pill,
   which is what a pill is for.

   The selector is deliberately two classes. The Kendo theme stylesheet loads AFTER this file (see
   _Layout.cshtml), so a single-class rule loses every tie to `.k-badge-md` -- which is exactly what
   happened to the padding on the first attempt: colour and position applied, sizing silently did
   not, and the pill came out 24.8 x 20 instead of round. */
.k-badge.app-items-due-badge {
    position: absolute;
    top: 0;
    right: 0;
    transform: none;

    background-color: var(--kendo-color-on-primary, #ffffff);
    border-color: var(--kendo-color-on-primary, #ffffff);
    color: var(--kendo-color-primary, #03328f);

    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 0.3rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.25rem;
    box-sizing: border-box;

    /* A hairline in the bar's own colour separates the pill from the AppBar when the two are
       close in tone, and disappears when they are not. */
    box-shadow: 0 0 0 1px var(--kendo-color-primary, #03328f);
}
