/* Portal-specific overrides on top of MudBlazor. Keep minimal; component styling lives in MudBlazor. */

/* The theme owns the typeface (KompanTheme asks for Figtree/Work Sans). This rule exists only because
   app.css loads after MudBlazor's, so an explicit family here would silently win — it defers instead.
   Any font-family added to this file must go through the same variable; PortalHostAssetTests checks. */
html, body {
    font-family: var(--mud-typography-default-family);
}

/* Button labels.
   MudBlazor drives .mud-button, .mud-fab and .mud-typography-button from one variable,
   --mud-typography-button-text-transform, which MudThemeProvider emits from
   MudTheme.Typography.Button.TextTransform — and Material defaults that to `uppercase`.
   KompanTheme.Default sets only the typeface, so the Material default survives and every button in a
   KOMPAN app shouts. SalesTools has it too; it is inherited, not chosen.

   That it is a leak rather than a decision is visible inside KompanButton itself: a label passed as
   `Text` is wrapped in <MudText Typo="Typo.body2">, whose own text-transform is `none`, so it renders
   sentence case — while the identical label passed as *child content* lands bare in the MudButton and
   is uppercased. Same component, same design system, two casings depending on which parameter you
   reached for. The package turns the same default off ad hoc elsewhere for the same reason
   (KompanBreadcrumbsPath.ItemTextTransform defaults to "none"; KompanQuickFilterPropertyHeader
   hardcodes text-transform:none !important) but never globally.

   KompanThemeHost hardcodes Theme="KompanTheme.Default" and takes no Theme parameter, so the Portal
   cannot set this in C# without giving up the design system's theme host (and with it prerender-safe
   theme resolution and the OS-preference watch). The variable is the same knob from the other side,
   and unlike overriding .mud-button it covers all three consuming selectors at once.

   `html:root`, not `:root`: MudThemeProvider writes its variables into an inline <style> in the body,
   which is later in document order than this file, so an equal-specificity `:root` here would lose.
   Naming the element as well outranks it (0,1,1 against 0,1,0) wherever the provider's style lands.
   KompanButtonCasingTests pins the package default this compensates for, so a KompanUI version that
   sets it in the theme fails loudly instead of leaving a dead rule behind. */
html:root {
    --mud-typography-button-text-transform: none;
}

/* Tabs shout for the same reason, but not through the same knob: MudBlazor's `.mud-tab` hardcodes
   `text-transform: uppercase` rather than reading a theme variable, so the rule above cannot reach it
   and there is nothing to set in a theme either. Left alone it is worse than before — with every
   button in sentence case, the tab strip becomes the only thing on the page still shouting.
   app.css loads after MudBlazor's (App.razor), so an equal-specificity selector wins on order.
   KompanLabelCasingTests pins the package rule this answers. */
.mud-tab {
    text-transform: none;
}

/* Tab panels: the package's wrapper makes MudBlazor's own show/hide rules inert.
   MudBlazor 9.7.0 stopped rendering only the active panel and now hides the others purely in CSS,
   with two *direct-child* rules:

       .mud-tabs-panels > .mud-tab-panel                                        { display: none }
       .mud-tabs-panels > .mud-tab-panel.mud-tab-panel-active:not(.mud-tab-panel-hidden) { display: contents }

   KompanTabPanel wraps MudTabPanel in its own <div class="kompan-tab-panel">, so the panel is a
   *grandchild* of .mud-tabs-panels and neither rule matches. Two things follow, and both were in the
   report: nothing ever hides a panel, so every tab that has been opened keeps painting on top of the
   others; and the active panel never gets `display: contents`, so it stays a block that honours the
   inline `height: 40px` KompanTabPanel writes onto it (that height is the *tab button's* size —
   MudTabPanel.Style is applied to the button and the content panel alike), which is the "fixed height,
   far too small" box with its own scrollbar. Measured on /admin/domains/catalogue before this rule:
   both panels display:block, both 40px, and the inactive one still rendering its grid.

   Mirroring the upstream pair one level deeper fixes both at once — `display: contents` removes the
   box, so the stray height and the package's `min-height: 24px !important` become inert with it.
   KompanTabPanelRenderTests pins the package markup this depends on, so a package version that stops
   wrapping (or stops writing the height) fails loudly instead of leaving dead rules behind. */
.mud-tabs-panels > .kompan-tab-panel > .mud-tab-panel {
    display: none;
}

.mud-tabs-panels > .kompan-tab-panel > .mud-tab-panel.mud-tab-panel-active:not(.mud-tab-panel-hidden) {
    display: contents;
}

/* Icons.
   KompanIcon inherits MudIcon and wraps its <svg> in a bare <div> (to carry RootStyle). MudBlazor's svg
   is display:inline-block, so inside that block wrapper it sits on a *text baseline*: the line box adds
   descender space underneath and the wrapper comes out ~27px tall for a 20px icon, with the glyph pinned
   to the top. No amount of align-items:center on the surrounding row fixes that — flexbox centres the
   wrapper, and the glyph is off-centre *within* it. Measured at 2.5-3.6px high on every KompanIcon in a
   row. Collapsing the wrapper onto the icon removes the line box altogether.

   The selector is deliberately narrow: KompanIcon's wrapper is the only classless div in the app that
   directly parents a mud svg, so this cannot reach MudBlazor's own icon slots. KompanIconRenderTests
   pins that structure, so a package version that drops the wrapper fails loudly instead of leaving a
   dead rule behind. */
div:not([class]):has(> svg.mud-svg-icon) {
    display: flex;
    align-items: center;
}

/* Field adornment icons.
   KompanInputField renders its adornment by handing AdornmentIcon to a MudTextField, and never passes
   IconSize — so MudBlazor's default Medium (24px) applies, inside a 33px dense field, beside 20px
   KompanIcons in the same row. On the domain page that put a 24px looking glass on "Find a surface"
   next to the 20px funnel in the field beside it. The component exposes no IconSize parameter, and a
   subclass cannot reach the MudTextField it renders internally, so the size is set here.

   1.25rem is not a guess: it is MudBlazor's own .mud-icon-size-small, which is what `Size.Small` means
   everywhere else in the app. Start adornments only — a select's end adornment is its dropdown arrow,
   which is 24px throughout MudBlazor and reads as chrome rather than as an icon in the row.
   PortalFieldIconTests pins both halves. */
.mud-input-adornment-start .mud-input-adornment-icon {
    font-size: 1.25rem;
}

/* Tooltip-wrapped fields.

   KompanTooltip's outermost element is a bare <div> with no class or style hook — ActivatorStyle
   lands on MudTooltip's root, one level *inside* that div — so a tooltip-wrapped field cannot claim
   width from anywhere. In a flex row the bare div is a shrink-to-fit item: it stops at its content
   width, `width:100%` on everything below it then resolves against that shrunken box, and the flex
   sizing put on the wrapper is simply never handed down. Measured on /admin/domains/catalogue:
   "Filter by service" 220px beside an identically-declared "Find a surface" at 335px, with the
   select's dropdown inheriting the 220px and clipping its longest option.

   So the wrapper carries the row's flex sizing (`flex: 1 1 <basis>`) and this rule passes it through
   the div in between. Applies to a *field* in a tooltip; a tooltip around an icon or a button wants
   the shrink-to-fit behaviour and keeps it. PortalMarkupLayoutTests fails the build on a tooltip
   wrapping a field without this wrapper. */
.portal-tooltip-field {
    display: flex;
}

.portal-tooltip-field > div {
    flex: 1 1 auto;
    /* Without this the field cannot shrink below its content, so a long selection label pushes the
       row wider instead of ellipsising inside the field. */
    min-width: 0;
}

/* A multi-select's collapsed value: one line, ellipsised.

   MudSelectExtended renders that value in a div it styles inline as

       overflow: hidden; text-overflow: ellipsis

   which does nothing whatever, because it never sets `white-space`. The div inherits `normal`, so the
   text wraps rather than ellipsising — and `text-overflow` only ever applies to a line the box cannot
   contain, which after wrapping there is not. The slot around it is `height: auto` inside a KompanField
   whose content row is a fixed 33px, so the extra lines are not absorbed anywhere: they are drawn over
   the labels above and below. Measured on the Request-a-scope dialog: five selected scopes, three lines,
   struck through "Scopes" and printed across "Justification".

   Three rules, because the ellipsis needs room as well as permission:

     - `white-space: nowrap` is the property the package left out, and the only one that makes its own
       `text-overflow` mean anything;
     - `min-width: 0` on the value slot is what lets the text be too long in the first place. A flex
       item's default `min-width: auto` is its min-content width, and with nowrap that is the entire
       string — so the slot would grow to fit and get clipped by an ancestor's `overflow: hidden`, with
       no ellipsis to show for it;
     - `flex-wrap: nowrap` on the row, because wrapping is decided against each item's *hypothetical*
       size, before any shrinking: at content width the value fills the line and the 20px input beside
       it drops to a second one, which is the same overflow again with the text on one line. The wrap
       comes from MudBlazor's `flex-wrap` utility class, which is `!important`, so this has to be too.

   PortalMultiSelectValueTests pins the inline styles this completes, so a package version that sets
   `white-space` itself fails loudly instead of leaving dead rules behind. */
.mud-input.mud-select-input-extended > .d-flex {
    flex-wrap: nowrap !important;
}

.mud-input-slot.mud-select-input-extended {
    min-width: 0;
}

.mud-input-slot.mud-select-input-extended > div {
    white-space: nowrap;
}

/* A field's label is absolutely positioned at the top of its control, and the space it occupies is
   reserved by a 16px margin on the input beside it:

       .mud-input-control > .mud-input-control-input-container > div.mud-input.mud-input-text-with-label
           { margin-top: 16px }

   MudDataGrid then takes that margin back for every input in a cell:

       .mud-data-grid .mud-table-cell:not(.mud-table-child-content) .mud-input-text
           { margin-top: 0 !important }

   which is right for the grid's own inline editing, where the cell *is* the field and there is no
   label — but it is applied to any input in any cell, so a labelled field in a CellTemplate keeps
   drawing its label and loses the row that label was standing in. The label lands 14px inside the
   input and prints over the value: on /admin/admins every "Platform roles", "Domain" and "Role" in
   the Manage column was struck through by its own caption.

   Restored only where a label actually exists (mud-input-text-with-label is only emitted then), so
   the grid's unlabelled editors keep filling their cells tightly. The value is MudBlazor's own, not
   a guess, and !important is forced by the rule being answered — at equal weight this one still wins
   on specificity. PortalGridFieldLabelTests pins both package rules this one sits between. */
.mud-data-grid .mud-table-cell:not(.mud-table-child-content) .mud-input-control > .mud-input-control-input-container > .mud-input.mud-input-text-with-label {
    margin-top: 16px !important;
}

.blazor-error-boundary {
    background: #b32121;
    color: #fff;
    padding: 1rem;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* App bar.
   MudAppBar's toolbar is a flex row whose children default to stretching, which left the selects a
   different height from the buttons beside them. Centring here rather than on each control keeps the
   row aligned however many controls it ends up carrying. */
.portal-appbar .mud-toolbar {
    align-items: center;
    gap: 8px;
}

/* The title is the only flexible-width item in the row, so it is what gets squeezed — and squeezed
   far enough it wraps to a second line and unbalances the bar. */
.portal-appbar-title {
    white-space: nowrap;
    flex: 0 0 auto;
}

/* Selects in the app bar: fixed size, vertically centred, and never the item that absorbs the
   leftover width. */
.portal-appbar-field {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

    .portal-appbar-field .mud-input-control {
        margin-top: 0;
        margin-bottom: 0;
    }

/* Drawer.
   MudDrawer's content box is a plain block, so a MudSpacer between the nav and the theme switch pushes
   nothing and the switch ends up below the fold — visible only as a clipped sliver. Making the content a
   column and letting the footer take the leftover margin pins it to the bottom at any drawer height. */
.portal-drawer .mud-drawer-content {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.portal-drawer-footer {
    margin-top: auto;
    flex: 0 0 auto;
    display: flex;
    justify-content: center;
    padding: 12px;
}

/* Grouped data grids: the whole group row toggles, not just the chevron.

   A group header reads as one thing, so the 48px chevron being the only hit target is a needlessly
   small target for a 900px row — and the row is where the eye already is, because that is where the
   surface name and its counts are.

   There is no API for this. MudBlazor exposes a public MudDataGrid.ToggleGroupExpand(column, key,
   expanded) and a GroupDefinition<T>.KeyPath to call it with, but KompanUI *forks* the grid:
   KompanDataGrid keeps its own internal _groupExpansionsDict (keyed by an anonymous
   { GroupDefinition.Title, Items.Key }), KompanDataGridGroupRow.GroupExpandClick is internal, and
   KompanGroupDefinition<T> carries neither KeyPath nor a back-reference to the grid — verified against
   the 1.6.0 assembly, not the checkout. Only ExpandAll/CollapseAllGroupsAsync are public. So the choice
   is CSS over the rendered row, or reflection into package internals.

   The package renders

       td.mud-datagrid-group > div(flex) > [ button.mud-datagrid-group-button , <GroupTemplate/> ]

   so stretching that button over the row makes the row the button: one element, so the package's own
   click handler, ripple, hover and keyboard activation (it is a real <button>: Tab, then Enter or
   Space) all come along, and nothing has to be re-implemented or kept in sync.

   Taking it out of flow costs the 48px box it was holding, so the flex div pays it back as padding and
   a min-height — hence the custom property, which states the package's icon-button size once and uses
   it for both. Anchoring to the *div* rather than the td matters: the div starts at the td's content
   edge, so the cell's padding and MudBlazor's mud-row-group-indented-N nesting indent still apply to
   the chevron for free. Measured on /admin/domains/catalogue before and after: chevron at x=28,
   template at x=64, row 61px tall — identical, with the button 48x48 -> 741x48.

   The template then has to let clicks through to the button underneath it, which is what
   .portal-group-row does; anything in the template that is itself clickable takes .portal-group-row-action
   to opt back in. PortalMarkupLayoutTests fails the build on a GroupTemplate that carries neither, and
   KompanDataGridGroupRowRenderTests pins the package markup this rule reaches into, so a version that
   restructures the group row fails loudly rather than silently returning a 48px hit target. */
td.mud-datagrid-group {
    cursor: pointer;
}

td.mud-datagrid-group > div {
    --portal-group-toggle-size: 48px;
    position: relative;
    min-height: var(--portal-group-toggle-size);
    padding-left: var(--portal-group-toggle-size);
}

td.mud-datagrid-group .mud-datagrid-group-button {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* The button is the row now: a pill would draw a 900px lozenge, and centring would put the chevron
       in the middle of the row instead of where the package had it. */
    border-radius: 0;
    justify-content: flex-start;
}

/* Both are positioned with z-index:auto, so paint order is DOM order and the template — which the
   package renders after the button — sits above it. */
.portal-group-row {
    position: relative;
    pointer-events: none;
}

.portal-group-row-action {
    pointer-events: auto;
}
