/* /Components/Layout/HeroWireframe.razor.rz.scp.css */
/* The wireframe takes its colour from the theme rather than naming gold itself, so the palette
   stays the single source of truth. */
.hero-wireframe[b-jw9ikhp9jf] {
    display: block;
    width: 100%;
    height: auto;
    color: var(--mud-palette-primary);
    /* A faint bloom, as though the lines were lit rather than printed. */
    filter: drop-shadow(0 0 14px rgba(201, 162, 39, 0.18));
}

/* Depth comes from opacity: the further back a layer sits, the fainter it is drawn. These are the
   resting values, and also what each layer's keyframes animate to. */
.layer-grid[b-jw9ikhp9jf]   { opacity: 0.18; }
.layer-base[b-jw9ikhp9jf]   { opacity: 0.45; }
.layer-walls[b-jw9ikhp9jf]  { opacity: 0.62; }
.layer-towers[b-jw9ikhp9jf] { opacity: 0.80; }
.layer-keep[b-jw9ikhp9jf]   { opacity: 1; }

/* --- Draw-in -------------------------------------------------------------------------------
   Each layer traces itself once, back to front, so the castle appears to be built rather than to
   appear. The dash length is deliberately larger than the longest path in the drawing: one value
   then serves every path whatever its real length, which keeps this to a few lines of CSS instead
   of measuring each path in JavaScript.

   Everything is inside prefers-reduced-motion: no-preference — so a visitor who has asked for less
   motion gets the finished drawing at its resting opacity, with no animation to interrupt. */

@media (prefers-reduced-motion: no-preference) {
    .hero-wireframe .layer[b-jw9ikhp9jf] {
        stroke-dasharray: 1200;
        stroke-dashoffset: 1200;
        opacity: 0;
        animation-duration: 1.1s;
        animation-timing-function: ease-out;
        animation-fill-mode: forwards;
    }

    .layer-grid[b-jw9ikhp9jf]   { animation-name: hero-draw-grid-b-jw9ikhp9jf;   animation-delay: 0s; }
    .layer-base[b-jw9ikhp9jf]   { animation-name: hero-draw-base-b-jw9ikhp9jf;   animation-delay: 0.12s; }
    .layer-walls[b-jw9ikhp9jf]  { animation-name: hero-draw-walls-b-jw9ikhp9jf;  animation-delay: 0.26s; }
    .layer-towers[b-jw9ikhp9jf] { animation-name: hero-draw-towers-b-jw9ikhp9jf; animation-delay: 0.40s; }
    .layer-keep[b-jw9ikhp9jf]   { animation-name: hero-draw-keep-b-jw9ikhp9jf;   animation-delay: 0.54s; }
}

/* One keyframe set per layer, because each settles at a different opacity. */

@keyframes hero-draw-grid-b-jw9ikhp9jf {
    from { stroke-dashoffset: 1200; opacity: 0; }
    to   { stroke-dashoffset: 0; opacity: 0.18; }
}

@keyframes hero-draw-base-b-jw9ikhp9jf {
    from { stroke-dashoffset: 1200; opacity: 0; }
    to   { stroke-dashoffset: 0; opacity: 0.45; }
}

@keyframes hero-draw-walls-b-jw9ikhp9jf {
    from { stroke-dashoffset: 1200; opacity: 0; }
    to   { stroke-dashoffset: 0; opacity: 0.62; }
}

@keyframes hero-draw-towers-b-jw9ikhp9jf {
    from { stroke-dashoffset: 1200; opacity: 0; }
    to   { stroke-dashoffset: 0; opacity: 0.80; }
}

@keyframes hero-draw-keep-b-jw9ikhp9jf {
    from { stroke-dashoffset: 1200; opacity: 0; }
    to   { stroke-dashoffset: 0; opacity: 1; }
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
#blazor-error-ui[b-djo7o1hu9j] {
    /* Was `color-scheme: light only` with a lightyellow background — a template default that
       painted a bright strip across a dark app. Themed by hand rather than by MudBlazor: this bar
       is rendered outside MudLayout and shown by blazor.web.js, so it never sees the palette. */
    background: #2A2118;
    color: #E8E6E3;
    border-top: 1px solid #C9A227;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-djo7o1hu9j] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Pages/Admin/LogBrowser.razor.rz.scp.css */
/* The page fills the viewport exactly and never scrolls itself: the toolbar stays put and the list
   owns its overflow. OrganizationList's two-rule lock, with the events table's sticky header. */

.log-browser[b-vx3nbr7xuz] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    /* The viewport, less the app bar and MudContainer's py-8 — the same budget every locked page
       here uses. --mud-appbar-height is emitted at runtime by MudThemeProvider, hence the fallback. */
    height: calc(100dvh - var(--mud-appbar-height, 64px) - 4rem);
}

.log-header[b-vx3nbr7xuz],
.log-toolbar[b-vx3nbr7xuz] {
    flex: 0 0 auto;
}

.log-scroll[b-vx3nbr7xuz] {
    flex: 1 1 auto;
    /* Load-bearing: without it a flex child refuses to shrink below its content, so the list grows
       instead of scrolling and the document scrolls in its place — taking the toolbar with it. */
    min-height: 0;
    /* Both axes. Setting one to a non-visible value makes the browser coerce the other from
       `visible` to `auto` anyway, and the sticky header detaches from the rows when scrolled
       sideways unless it is declared. */
    overflow: auto;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

/* One template shared by the sticky header and every row, so the columns line up without a
   <table> — which would not survive a row expanding into a second element anyway. */
.log-row[b-vx3nbr7xuz] {
    display: grid;
    grid-template-columns:
        11rem                   /* time    */
        6rem                    /* level   */
        minmax(10rem, 1fr)      /* source  */
        minmax(20rem, 3fr);     /* message */
    gap: 0.75rem;
    align-items: baseline;
    min-width: 52rem;
    padding: 0.4rem 1rem;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* The whole row opens the detail, so it has to look like it does. A real button rather than a click
   handler on a div: keyboard operation and the pressed state come from the element. */
.log-row[b-vx3nbr7xuz] {
    width: 100%;
    background: none;
    border-left: 0;
    border-right: 0;
    border-top: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.log-row:hover[b-vx3nbr7xuz] {
    background-color: var(--mud-palette-action-default-hover);
}

.log-row:focus-visible[b-vx3nbr7xuz] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

/* The past scrolls up past this, so it stays put. */
.log-head[b-vx3nbr7xuz] {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--mud-palette-surface);
    font-size: var(--mud-typography-overline-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mud-palette-text-secondary);
    cursor: default;
}

.log-head:hover[b-vx3nbr7xuz] {
    background-color: var(--mud-palette-surface);
}

.log-time[b-vx3nbr7xuz],
.log-source[b-vx3nbr7xuz] {
    color: var(--mud-palette-text-secondary);
}

/* A collapsed row is one line however long the message is: a table whose row heights vary with the
   text cannot be scanned. Expanding is what shows the rest. */
.log-cell[b-vx3nbr7xuz] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.log-time[b-vx3nbr7xuz],
.log-source[b-vx3nbr7xuz],
.log-message[b-vx3nbr7xuz] {
    font-family: var(--mud-typography-body2-family), monospace;
    font-size: 0.8rem;
}

/* An entry carrying an exception is worth spotting without reading the level column. */
.log-row.is-failure .log-message[b-vx3nbr7xuz] {
    color: var(--mud-palette-error-text);
}

/* The expanded half. Its own element rather than a taller row, so the grid above is untouched. */
.log-detail[b-vx3nbr7xuz] {
    padding: 0.5rem 1rem 1rem 1rem;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background-color: var(--mud-palette-background-gray);
}

.log-detail pre[b-vx3nbr7xuz] {
    margin: 0.25rem 0 0 0;
    padding: 0.5rem;
    /* Scrolls inside its own box. A stack trace is wider than any screen, and letting it widen the
       grid would push every row's columns out of line with the header. */
    overflow-x: auto;
    white-space: pre;
    font-size: 0.75rem;
    background-color: var(--mud-palette-surface);
    border-radius: var(--mud-default-borderradius);
}

.log-detail-label[b-vx3nbr7xuz] {
    font-size: var(--mud-typography-overline-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mud-palette-text-secondary);
}

/* Sits above the rows while the reader is anywhere but the top — see LogBrowser.razor for why new
   entries wait rather than being prepended under somebody mid-list. */
.log-new[b-vx3nbr7xuz] {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* What the observers watch. Zero-height, so neither takes a row's worth of space. */
.log-sentinel[b-vx3nbr7xuz] {
    height: 1px;
}

/* The lock is a desktop affordance: in a short or narrow window a toolbar and a list sharing one
   viewport become strips. The list keeps `overflow: auto` and a max-height rather than going
   `visible` — the IntersectionObservers are rooted on it, and an element with no scroll viewport
   of its own would report every sentinel as visible at once. */
@media (max-height: 700px), (max-width: 900px) {
    .log-browser[b-vx3nbr7xuz] {
        height: auto;
    }

    .log-scroll[b-vx3nbr7xuz] {
        max-height: 40rem;
    }
}
/* /Components/Pages/Admin/OrganizationList.razor.rz.scp.css */
.organizations[b-cixce718n1] {
    display: flex;
    flex-direction: column;
    /* Fill what MudMainContent leaves us: the viewport, less the app bar and the container's py-8.
       --mud-appbar-height is emitted at runtime by MudThemeProvider, hence the fallback. */
    height: calc(100dvh - var(--mud-appbar-height, 64px) - 4rem);
}

.organizations-scroll[b-cixce718n1] {
    flex: 1 1 auto;
    /* Without min-height a flex child refuses to shrink below its content, and the page scrolls
       instead of the list — taking the create button with it. */
    min-height: 0;
    overflow-y: auto;
}
/* /Components/Pages/Home.razor.rz.scp.css */
.org-card[b-qo438hukge] {
    height: 100%;
}

/* Marks the organization the viewer was last in. MudBlazor's Outlined card draws a neutral
   border, so the colour is what carries the signal — the chip and the Continue button say the
   same thing in words, for anyone who cannot see it. */
.org-card-last[b-qo438hukge] {
    border-color: var(--mud-palette-primary);
    border-width: 2px;
}

/* --- Signed-out landing --------------------------------------------------------------------
   MainLayout renders no app bar or drawer for a signed-out visitor, so this fills the viewport
   itself rather than sitting inside MudContainer's padding. */

.landing[b-qo438hukge] {
    position: relative;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    padding: 2rem 1.5rem;
}

/* The light the palace stands in. Sits behind the content and takes no pointer events, so it can
   never intercept a click on the button. */
.landing-glow[b-qo438hukge] {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse 60% 45% at 50% 42%, rgba(201, 162, 39, 0.13), transparent 70%),
        radial-gradient(ellipse 90% 60% at 50% 100%, rgba(201, 162, 39, 0.05), transparent 60%);
}

.landing-content[b-qo438hukge] {
    position: relative;
    width: 100%;
    max-width: 46rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.landing-wordmark[b-qo438hukge] {
    margin: 1.5rem 0 0;
    font-size: clamp(2rem, 6vw, 3.25rem);
    font-weight: 300;
    /* Wide tracking is what makes a single word read as a wordmark rather than a heading. */
    letter-spacing: 0.32em;
    /* The tracking adds space after the final letter too, which visually pulls the word
       off-centre; half of it back as padding re-centres it. */
    padding-left: 0.32em;
    text-transform: uppercase;
    color: var(--mud-palette-text-primary);
}

.landing-tagline[b-qo438hukge] {
    margin: 0.75rem 0 0;
    max-width: 32rem;
    font-size: clamp(0.95rem, 2vw, 1.1rem);
    line-height: 1.6;
    color: var(--mud-palette-text-secondary);
}

.landing-cta[b-qo438hukge] {
    margin-top: 2.25rem;
    padding-inline: 2.5rem;
    letter-spacing: 0.06em;
}

/* On a short or narrow viewport the drawing is the first thing that should give way — the
   wordmark and the button are what the page is for. */
@media (max-height: 620px), (max-width: 480px) {
    .landing-content :global(.hero-wireframe)[b-qo438hukge] {
        max-width: 26rem;
    }

    .landing-wordmark[b-qo438hukge] {
        font-size: clamp(1.6rem, 8vw, 2.25rem);
    }
}
/* /Components/Pages/Org/ClientDetail.razor.rz.scp.css */
/* The page fills the viewport exactly and never scrolls itself. A header that never moves, then a
   tab set taking the rest, whose Overview panel holds three collapsible sections that own their
   own overflow.

   min-height: 0 appears on every flex child that scrolls, and it is load-bearing in each case:
   without it a flex child refuses to shrink below its content, so the region grows instead of
   scrolling and the document scrolls in its place — taking the header off screen, which is the one
   thing that must not move. CLAUDE.md flags this for OrganizationList; here it bites six times,
   and two of those are on markup MudBlazor renders rather than on ours. */

.client-detail[b-p7m7hqbm15] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    /* The viewport, less the app bar and MudContainer's py-8. --mud-appbar-height is emitted at
       runtime by MudThemeProvider, hence the fallback. Same budget as OrganizationList. */
    height: calc(100dvh - var(--mud-appbar-height, 64px) - 4rem);
}

.client-detail-header[b-p7m7hqbm15] {
    flex: 0 0 auto;
}

/* --- The tab set ------------------------------------------------------------------------------
   Everything from .mud-tabs down is MudBlazor's own, so it never carries this component's scope
   attribute — hence one plain element of ours to anchor on, the same arrangement .board-body and
   .events-body already use below.

   MudBlazor 9.9.0 ships exactly two rules for a panel, and both are traps, in opposite directions:

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

   * The inactive panel is hidden by *lacking* .mud-tab-panel-active — not by carrying
     .mud-tab-panel-hidden, which hides the TAB in the bar (.mud-tab.mud-tab-panel-hidden) and is
     what Visible="false" uses. So a selector on .mud-tab-panel matches both panels, and at (0,4,0)
     it outranks the (0,3,0) hider: give the panel a display and both tabs paint at once, stacked.
   * The active panel is display: contents at (0,5,0), which outranks anything ::deep can write. Its
     box is gone, so flex, min-height and gap set on it are discarded in silence.

   So nothing here styles a panel. display: contents hoists the three sections into
   .mud-tabs-panels, which is therefore their real flex parent — one nesting level fewer than if the
   panel were a box, and nothing fighting the library. */

.client-tabs[b-p7m7hqbm15] {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.client-tabs[b-p7m7hqbm15]  .mud-tabs {
    flex: 1 1 auto;
    min-height: 0;
    /* Its children are the bar and the panels and nothing else, so this is the space between the
       tab strip and the first section. Nothing else supplies it: .client-detail's gap now reaches
       only as far as .client-tabs. */
    gap: 1rem;
}

/* The bar carries no flex rule of its own, so it falls to 0 1 auto and compresses under a tall
   panel. min-height: 48px sits on .mud-tabs-tabbar-inner, so what gives is the bar's own painted
   box — the underline and background detach from the labels rather than the tabs shrinking. */
.client-tabs[b-p7m7hqbm15]  .mud-tabs-tabbar {
    flex: 0 0 auto;
}

.client-tabs[b-p7m7hqbm15]  .mud-tabs-panels {
    /* Load-bearing. MudBlazor grants flex-grow here only through .mud-tabs.mud-tabs-rounded, and
       Rounded is off — so without this the panels area falls to 0 1 auto, sizes to its content, and
       the height lock never reaches the sections. Turning Rounded on would mask that rather than
       fix it, which is one more reason to leave it off. */
    flex: 1 1 auto;
    min-height: 0;

    /* The active panel is display: contents, so the three sections are *this* element's flex items:
       the column, the nth-of-type shares and the gap .client-detail used to give them resolve here. */
    display: flex;
    flex-direction: column;
    gap: 1rem;

    /* MudBlazor's own `transition: .3s cubic-bezier(…)` names no property, so it animates `all` —
       including this box growing from nothing to a viewport on first paint. */
    transition: none;
}

.section[b-p7m7hqbm15] {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

.section:nth-of-type(1)[b-p7m7hqbm15] { flex: 4 1 0; }   /* products */
.section:nth-of-type(2)[b-p7m7hqbm15] { flex: 4 1 0; }   /* events */
.section:nth-of-type(3)[b-p7m7hqbm15] { flex: 6 1 0; }   /* tasks — the working surface, so the larger share */

/* These are positional, so reordering the sections in the markup silently reassigns them: moving
   Products to the front moved every share along one. Change the order above and you must change
   these comments with it, or the next reader will trust a lie. */

/* Without a rule of its own a section falls to the flex default `0 1 auto` — content-sized, which
   looks right while collapsed and wrong the moment it opens. Products starts collapsed, so this is
   easy to add late and easy to miss entirely. */

.section.is-collapsed[b-p7m7hqbm15] {
    flex: 0 0 auto;
}

/* The row that survives collapsing: the disclosure button, then the add button beside it. They are
   siblings rather than nested, because a button inside a button is invalid markup and the inner one
   would toggle the section as well as fire. */
.section-header-row[b-p7m7hqbm15] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}

/* A real button, so focus, Enter/Space and aria-expanded all come from the element rather than from
   handlers. */
.section-header[b-p7m7hqbm15] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    /* Hugs its content, so the add button sits immediately after the count rather than being pushed
       to the far edge of the section. */
    flex: 0 1 auto;
    /* Load-bearing. MudBlazor's reset carries a bare `button { ... justify-content: center }`, and
       `text-align: left` does not govern a flex container — so the chevron and title sat in the
       middle of the row. Measured: 649px from the left edge before this line, 16px after. */
    justify-content: flex-start;
    padding: 0.6rem 1rem;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.section-header:hover[b-p7m7hqbm15] {
    background-color: var(--mud-palette-action-default-hover);
}

.section-header:focus-visible[b-p7m7hqbm15] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

.section-body[b-p7m7hqbm15] {
    flex: 1 1 auto;
    min-height: 0;
    border-top: 1px solid var(--mud-palette-lines-default);
}

/* Events scroll; the board does not — its lanes do. */
.section-body-scroll[b-p7m7hqbm15] {
    overflow-y: auto;
}

/* Nine columns, one template shared by the sticky header and every row, so they line up without a
   <table> — which Virtualize could not render into anyway, since it emits its spacers as siblings
   of the rows. The row is wide on purpose; below its min-width the section scrolls sideways rather
   than crushing the columns. */
.events-body[b-p7m7hqbm15] {
    /* Both axes, or the browser coerces overflow-x to auto on its own and the sticky header
       detaches from the rows when scrolled horizontally. */
    overflow: auto;
}

.event-row[b-p7m7hqbm15] {
    display: grid;
    grid-template-columns:
        minmax(9rem, 2fr)      /* Title    */
        minmax(7rem, 1.4fr)    /* Location */
        minmax(8rem, 1.4fr)    /* Product  */
        minmax(7rem, 1.2fr)    /* Assignee */
        7rem                   /* Date     */
        4rem                   /* Time     */
        5rem                   /* Duration */
        4rem                   /* Task #   */
        5rem;                  /* actions  */
    gap: 0.75rem;
    align-items: center;
    /* Fixed, and it must equal Virtualize's ItemSize and ClientDetail's EventRowHeight — the anchor
       is an offset in pixels, so a mismatch opens the table on the wrong row. */
    height: 56px;
    min-width: 58rem;
    padding: 0 1rem;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* The past scrolls up past this, so it has to stay put. */
.event-head[b-p7m7hqbm15] {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--mud-palette-surface);
    font-size: var(--mud-typography-overline-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mud-palette-text-secondary);
}

/* Long titles, places and product names truncate rather than widening the row. */
.events-body[b-p7m7hqbm15]  .event-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.events-body[b-p7m7hqbm15]  .event-product-link {
    min-width: 0;
    max-width: 100%;
    text-transform: none;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
}

.events-body[b-p7m7hqbm15]  .event-product-link .mud-button-label {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}



/* --- The board ------------------------------------------------------------------------------ */

/* From .board-body downwards every element is MudBlazor's own — the drop container, the lane
   MudPaper, the drop zone — and a child component's root element never carries this component's
   scope attribute. So .board-body is the last ancestor we render, and every board rule anchors on
   it through ::deep. Drop the ::deep from any one of these and it compiles to `.x[b-xxx]`, matches
   nothing, and fails *silently*: lanes fall back to `flex: 0 1 auto` and size to their content, or
   a lane stops scrolling and the document scrolls in its place. */
.board-body[b-p7m7hqbm15]  .board {
    display: flex;
    gap: 1rem;
    height: 100%;
    padding: 1rem;
    /* Lanes divide the width equally down to their floor, then this scrolls rather than squeezing
       them into slivers. overflow-y is pinned to hidden deliberately: setting one axis to a
       non-visible value makes the browser coerce the other from visible to auto, so declaring only
       overflow-x would quietly give the lane row a vertical scrollbar — the one thing the container
       must not have. */
    overflow-x: auto;
    overflow-y: hidden;
}

/* Was anchored on `.board`, which stopped being ours when the drop container took that class over.
   Everything hangs off .board-body now. */
.board-body[b-p7m7hqbm15]  .board-lane {
    /* Equal shares: same zero basis and same growth, so the width divides evenly however many
       lanes there are. A basis of `auto` would weight each lane by its content instead. */
    flex: 1 1 0;
    /* The floor. Below this the row scrolls sideways instead of shrinking further. See the
       narrow-viewport block below, which lowers it: four lanes at this floor need 912px, which no
       tablet has upright. */
    min-width: 13rem;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.board-body[b-p7m7hqbm15]  .board-lane-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.75rem 1rem 0.5rem;
}

/* Enough colour to categorise the column without tinting the whole card, which would fight with
   the task cards that will eventually sit inside it. */
.board-body[b-p7m7hqbm15]  .board-lane-rule {
    flex: 0 0 auto;
    height: 2px;
    opacity: 0.9;
}

.board-body[b-p7m7hqbm15]  .board-lane-rule-open { background-color: var(--mud-palette-tertiary); }
.board-body[b-p7m7hqbm15]  .board-lane-rule-inprogress { background-color: var(--mud-palette-primary); }
.board-body[b-p7m7hqbm15]  .board-lane-rule-blocked { background-color: var(--mud-palette-warning); }
.board-body[b-p7m7hqbm15]  .board-lane-rule-done { background-color: var(--mud-palette-success); }

/* Each lane scrolls on its own — the point of the whole arrangement. This is the drop zone's own
   root element now, hence ::deep like everything else here. */
.board-body[b-p7m7hqbm15]  .board-lane-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 1rem;
}

/* --- Small screens ---------------------------------------------------------------------------
   The locked layout needs a real budget: the client's header, the tab strip, three section headers
   and a board tall enough to drag a card in come to roughly 800px before anything is left over. So
   below that the lock is released and the page scrolls as a normal document. Collapsing still
   works — it just changes natural heights rather than shares.

   **Both conditions are about height, and the width one used to lie.** This read
   `(max-width: 900px)` and released the whole lock on any narrow viewport — so a tablet held
   upright lost it and the Tasks board stopped filling, despite portrait having *more* height to
   share than landscape, not less. Every declaration in this block answers a height problem; the
   width problem is handled where it belongs, on the lanes below. 600px survives only as a phone
   escape: at that width the header's own fields wrap far enough that sharing the viewport stops
   being worth it whatever the height.

   **820px rather than 700px, and the reason is browser chrome.** The target tablet (Redmi Pad 2
   Pro, 800x1280 CSS px) is 800 tall in landscape installed and about 680 in a browser tab, because
   Chrome's toolbar costs ~120px. A threshold anywhere between those two makes the installed app and
   the browser tab disagree on the same screen in the same orientation — which is what "it looks
   different as a PWA" was. Above both, they agree: upright is the locked working layout in either,
   on its side both scroll. Keep any future threshold clear of that band. */

@media (max-height: 820px), (max-width: 600px) {
    .client-detail[b-p7m7hqbm15] {
        height: auto;
    }

    /* The tab chain needs nothing here. With the lock released at the root there is no free space
       for a flex: 1 1 auto to claim, so every level below sizes to its content unaided. What has to
       survive is the *spacing* on .mud-tabs-panels — column and gap — and that is not sizing, so
       the base rule keeps it. */

    .section:nth-of-type(1)[b-p7m7hqbm15],
    .section:nth-of-type(2)[b-p7m7hqbm15],
    .section:nth-of-type(3)[b-p7m7hqbm15] {
        flex: 0 0 auto;
    }

    /* Still bounded, or an unpaged list would grow without limit. */
    .section-body-scroll[b-p7m7hqbm15] {
        max-height: 22rem;
    }

    .board-body[b-p7m7hqbm15]  .board {
        height: auto;
    }

    .board-body[b-p7m7hqbm15]  .board-lane {
        min-height: 12rem;
    }

    .board-body[b-p7m7hqbm15]  .board-lane-body {
        overflow-y: visible;
    }
}

/* --- The board on a narrow viewport ----------------------------------------------------------
   Four lanes at the 13rem floor need 4x208 + 3 gaps + padding = 912px, and a 12" tablet held
   upright gives the board 752 (800 CSS px less MudContainer's 24px gutters). So the row scrolled
   sideways and the fourth lane sat off screen — on the one layout where the board has the most
   height to work with.

   Tightening the board's own padding and gap first buys 40px, which is enough that the floor only
   has to come down to 10.5rem rather than further. At 800px that leaves 178px a lane: narrower than
   a desktop lane, still wide enough for a card's title and its meta line. Below 600px the lock is
   released anyway and the row is free to scroll. */

@media (min-width: 601px) and (max-width: 900px) {
    .board-body[b-p7m7hqbm15]  .board {
        padding: 0.5rem;
        gap: 0.5rem;
    }

    .board-body[b-p7m7hqbm15]  .board-lane {
        min-width: 10.5rem;
    }

    .board-body[b-p7m7hqbm15]  .board-lane-body {
        padding: 0.5rem;
    }
}

/* Kept as a group even though the lane's add button moved to the section header: it kicks
   .board-lane-header back into the two-part space-between row the count chip expects. */
.board-body[b-p7m7hqbm15]  .board-lane-title {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.board-body[b-p7m7hqbm15]  .task-card {
    border: 1px solid var(--mud-palette-lines-default);
    cursor: grab;
}

.board-body[b-p7m7hqbm15]  .task-card:active {
    cursor: grabbing;
}

/* --- Drop targets ----------------------------------------------------------------------------
   ApplyDropClassesOnDragStarted puts one of these on every lane the instant a drag begins rather
   than on hover, so all the available targets announce themselves at once. Which class a lane gets
   is decided by AppTask.CanMove, so the domain's transition rules are what the board shows. */

.board-body[b-p7m7hqbm15]  .lane-can-drop {
    outline: 2px dashed var(--mud-palette-primary);
    outline-offset: -4px;
    /* The gold at a whisper — enough to read as a target without competing with the cards in it. */
    background-color: rgb(from var(--mud-palette-primary) r g b / 8%);
}

/* Lanes that would refuse the card simply recede, the lane it came from among them: a card's own
   lane is not a destination, so it reads correctly rather than as a warning. */
.board-body[b-p7m7hqbm15]  .lane-no-drop {
    opacity: 0.45;
}

/* --- Products --------------------------------------------------------------------------------
   .products-body is the last element this component renders; the cards below it are MudPaper, so
   their roots never carry the scope attribute. Same ::deep anchoring as the board, and the same
   silent failure if it is dropped. */

.offer-grid[b-p7m7hqbm15] {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    padding: 1rem;
}

/* One rule for both the real cards and the add slot, so they cannot drift apart in size. The add
   slot is a <button> this component renders, hence the second selector without ::deep. */
.products-body[b-p7m7hqbm15]  .offer-card,
.offer-card[b-p7m7hqbm15] {
    display: flex;
    flex-direction: column;
    width: 14rem;
    min-height: 8.5rem;
}

/* One field on a card. No ::deep: these are this component's own elements inside the MudPaper, and
   only the paper's own root goes unscoped. Each stays on one line — a card is 14rem wide and a card
   that reflows on a long answer stops being scannable. */
.offer-field[b-p7m7hqbm15] {
    display: flex;
    gap: 0.375rem;
    font-size: var(--mud-typography-caption-size);
    line-height: 1.4;
    white-space: nowrap;
}

.offer-field > :last-child[b-p7m7hqbm15] {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The label recedes so the answers read as a column down the card. */
.offer-field-name[b-p7m7hqbm15] {
    color: var(--mud-palette-text-secondary);
    flex: 0 0 auto;
}

.offer-field-name[b-p7m7hqbm15]::after {
    content: ":";
}

/* A dashed outline so it reads as an empty slot rather than as another product. Button resets,
   because it is a real button. */
.offer-add[b-p7m7hqbm15] {
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    background: none;
    border: 2px dashed var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    color: var(--mud-palette-text-secondary);
    font: inherit;
    cursor: pointer;
}

.offer-add:hover[b-p7m7hqbm15] {
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary);
    background-color: rgb(from var(--mud-palette-primary) r g b / 6%);
}

.offer-add:focus-visible[b-p7m7hqbm15] {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* The product a task belongs to, on its card. A lane is narrow, so the name truncates rather than
   wrapping the card wider — the status chip beside it must keep its room. */
.board-body[b-p7m7hqbm15]  .task-card-product {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.board-body[b-p7m7hqbm15]  .task-card-product-link {
    min-width: 0;
    text-transform: none;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
}

/* MudButton wraps its label in a span of its own, so the ellipsis has to go on that rather than on
   the button — hence reaching past it here. */
.board-body[b-p7m7hqbm15]  .task-card-product-link .mud-button-label {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A completed event recedes but stays legible — it is done, not gone. */
.event-row.is-completed[b-p7m7hqbm15] {
    opacity: 0.55;
}

/* The check and the title share the title column, so the nine-column template is untouched and the
   rows stay aligned with the sticky header. */
.events-body[b-p7m7hqbm15]  .event-title {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-width: 0;
}

/* A sortable header is a real button, so focus and Enter/Space come from the element. It fills its
   grid cell so the whole label is the target, and resets the button chrome MudBlazor's reset adds
   — including the centred justify-content that pushed the section headers about. */
.events-body[b-p7m7hqbm15]  .event-sort {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.25rem;
    min-width: 0;
    padding: 0;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}

.events-body[b-p7m7hqbm15]  .event-sort:hover {
    color: var(--mud-palette-primary);
}

.events-body[b-p7m7hqbm15]  .event-sort:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* Which position this column holds in a multi-column sort. Only shown when there is more than one,
   because a lone "1" says nothing. */
.events-body[b-p7m7hqbm15]  .event-sort-rank {
    font-size: 0.7em;
    font-weight: 700;
    color: var(--mud-palette-primary);
}
/* /Components/Pages/Org/ClientNotes.razor.rz.scp.css */
/* Every element here is one this component renders, so nothing needs ::deep — which is the quiet
   advantage of the note card not being a MudBlazor component. The one exception is the colour
   picker's menu, and it is styled by MudBlazor rather than by us. */

/* The tab panel this sits in is `display: contents` — MudBlazor's own rule, at a specificity ::deep
   cannot outrank — so this element is a direct flex item of .mud-tabs-panels and has to carry the
   sizing itself. overflow-x is pinned deliberately: setting one axis to a non-visible value coerces
   the other from visible to auto, so declaring only overflow-y would give the board a horizontal
   scrollbar, the one thing the fractional x exists to prevent. */
.notes[b-nzpr7lwwnb] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

.notes-surface[b-nzpr7lwwnb] {
    /* What the cards are positioned against, and what the pointer coordinates are measured from. */
    position: relative;
    min-height: 100%;

    --note-width: 15rem;
    --note-height: 11rem;
}

.notes-invitation[b-nzpr7lwwnb] {
    margin: 0;
    padding: 1rem;
    color: var(--mud-palette-text-secondary);
    /* It must not swallow the tap that acts on it: the board is the control. */
    pointer-events: none;
}

/* left maps x across the *track* — the width a card can travel — rather than across the whole
   board. That is what makes x = 1 mean "flush right" instead of "one card-width off the edge", and
   it is why the fraction is safe at any width without measuring anything. */
.note[b-nzpr7lwwnb] {
    position: absolute;
    left: calc(var(--note-x) * (100% - var(--note-width)));
    top: var(--note-y);
    width: var(--note-width);
    height: var(--note-height);
    display: flex;
    flex-direction: column;
    border: 1px solid var(--note-edge);
    border-radius: var(--mud-default-borderradius);
    background-color: var(--note-fill);
    box-shadow: 0 1px 3px rgb(0 0 0 / 40%);
}

/* Lifted while it is being dragged, so it passes over its neighbours rather than under them.
   The class is added and removed by the module — nothing re-renders during a drag. */
.note.is-dragging[b-nzpr7lwwnb] {
    z-index: 2;
    box-shadow: 0 6px 16px rgb(0 0 0 / 55%);
}

.note-handle[b-nzpr7lwwnb] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem;
    border-bottom: 1px solid var(--note-edge);
}

/* The grip, and the only thing in the app that sets touch-action. Without it a finger drag here
   scrolls the board instead of moving the card; on the whole card, the board could not be scrolled
   by finger anywhere a card sits.

   It is a grip rather than the whole title bar because the bar is almost entirely controls, and
   starting a drag on one captures the pointer — which retargets the pointerup, so the click lands
   on the bar and the button never fires. 1.75rem square so it is a real target on a tablet. */
.note-grip[b-nzpr7lwwnb] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    color: var(--mud-palette-text-secondary);
    cursor: grab;
    touch-action: none;
}

.note.is-dragging .note-grip[b-nzpr7lwwnb] {
    cursor: grabbing;
}

/* Bare inputs rather than MudTextField: an outlined field with its label and helper space is taller
   than the whole card it would sit in. */
.note-title[b-nzpr7lwwnb],
.note-body[b-nzpr7lwwnb] {
    width: 100%;
    background: transparent;
    border: none;
    outline: none;
    color: var(--mud-palette-text-primary);
    font-family: inherit;
}

.note-title[b-nzpr7lwwnb] {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 500;
}

.note-body[b-nzpr7lwwnb] {
    flex: 1 1 auto;
    min-height: 0;
    padding: 0.5rem;
    resize: none;
    font-size: 0.875rem;
    line-height: 1.4;
    overflow-y: auto;
}

.note-remove[b-nzpr7lwwnb] {
    flex: 0 0 auto;
    background: none;
    border: none;
    padding: 0 0.25rem;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    color: var(--mud-palette-text-secondary);
}

.note-remove:hover[b-nzpr7lwwnb] {
    color: var(--mud-palette-error);
}

/* --- The palette -----------------------------------------------------------------------------
   Mixed from the theme rather than written as hex, so changing a colour in AppTheme carries here
   instead of drifting as a second copy — the argument the app bar's gold hairline already makes.
   Each card is a wash of its colour over the surface, not the colour itself: five saturated cards
   on one board would be unreadable. */
.note-gold[b-nzpr7lwwnb]   { --note-fill: color-mix(in srgb, var(--mud-palette-primary) 14%, var(--mud-palette-surface));
               --note-edge: color-mix(in srgb, var(--mud-palette-primary) 40%, transparent); }
.note-bronze[b-nzpr7lwwnb] { --note-fill: color-mix(in srgb, var(--mud-palette-secondary) 14%, var(--mud-palette-surface));
               --note-edge: color-mix(in srgb, var(--mud-palette-secondary) 40%, transparent); }
.note-slate[b-nzpr7lwwnb]  { --note-fill: color-mix(in srgb, var(--mud-palette-tertiary) 14%, var(--mud-palette-surface));
               --note-edge: color-mix(in srgb, var(--mud-palette-tertiary) 40%, transparent); }
.note-moss[b-nzpr7lwwnb]   { --note-fill: color-mix(in srgb, var(--mud-palette-success) 14%, var(--mud-palette-surface));
               --note-edge: color-mix(in srgb, var(--mud-palette-success) 40%, transparent); }
.note-amber[b-nzpr7lwwnb]  { --note-fill: color-mix(in srgb, var(--mud-palette-warning) 14%, var(--mud-palette-surface));
               --note-edge: color-mix(in srgb, var(--mud-palette-warning) 40%, transparent); }

/* The height lock is released at this breakpoint — which includes the target tablet on its side —
   so `flex: 1 1 auto` has no free space to claim and the board would collapse to nothing. The same
   floor the task board's lanes get in the same situation. */
@media (max-height: 820px), (max-width: 600px) {
    .notes[b-nzpr7lwwnb] {
        min-height: 28rem;
    }
}
/* /Components/Pages/Org/ClientProductDialog.razor.rz.scp.css */
/* The same treatment .task-description and .comment-body get: line breaks typed by hand are
   meaning, and an unbroken run must wrap rather than force a scrollbar. ::deep because MudText
   renders its own root element. */
[b-dedwtn30b1] .offer-description,
[b-dedwtn30b1] .entry-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

[b-dedwtn30b1] .entry {
    border: 1px solid var(--mud-palette-lines-default);
}

/* Narrow enough to leave the Post button its own room on one line. */
[b-dedwtn30b1] .offer-status-select {
    max-width: 14rem;
}

/* --- One scroller, and it is the timeline's ---------------------------------------------------
   The content is bounded here rather than left to grow, so MudBlazor's .mud-dialog-content never
   has anything to scroll: a scrollbar on the dialog moves the status, the fields and the comment
   box — exactly what somebody reading the conversation needs to stay put. A fixed cap on the
   timeline alone cannot promise that, because it says nothing about how tall everything above it
   is; that is how a second scrollbar appeared once the Fields section landed.

   The reserve covers the dialog's title, its actions, the content padding and its margin against
   the viewport. Below that the floor wins and the dialog scrolls after all — on a viewport that
   short there is nothing else to do. */
.offer-dialog[b-dedwtn30b1] {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 16rem);
    min-height: 12rem;
}

/* Everything above the conversation keeps its height — it is the part that must not move. */
.offer-dialog-head[b-dedwtn30b1] {
    flex: 0 0 auto;
}

/* And the timeline takes whatever is left. min-height: 0 is load-bearing: without it a flex child
   refuses to shrink below its content, so the list would push the wrapper past its bound and hand
   the scrollbar back to the dialog. */
.timeline[b-dedwtn30b1] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 0.25rem;
}
/* /Components/Pages/Org/CompleteEventDialog.razor.rz.scp.css */
/* Each linked task or product sits on its own ground, so the list reads as separate items rather
   than one block. ::deep because MudPaper renders its own root element. */
[b-yyjxrx3ctw] .linked {
    border: 1px solid var(--mud-palette-lines-default);
}
/* /Components/Pages/Org/EventOverviewDialog.razor.rz.scp.css */
/* Line breaks typed by hand are meaning, and an unbroken run must wrap rather than overflow — the
   same treatment .task-description and .comment-body get. */
[b-u008n5oezy] .event-description {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* The task dialog's comment rules, copied — the two threads look and behave the same. */
[b-u008n5oezy] .comment {
    border: 1px solid var(--mud-palette-lines-default);
}

[b-u008n5oezy] .comment-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Roughly four comments before it scrolls, so the dialog does not grow with the conversation and
   push its own fields off the top. No ::deep: this div is rendered by the component itself. */
.comment-list[b-u008n5oezy] {
    max-height: 22rem;
    overflow-y: auto;
    padding-right: 0.25rem;
}
/* /Components/Pages/Org/ProductDialog.razor.rz.scp.css */
/* Every rule here is anchored on .fields, the one plain element this component renders around the
   template. From MudForm down, everything is a MudBlazor component whose root element never
   carries this component's scope attribute — so a bare `::deep .x` compiles to `[b-xxx] .x`, finds
   no ancestor to match, and fails silently. ClientDetail's .board-body is the same arrangement for
   the same reason. */

.fields[b-yoyvhhudsp]  .field-row {
    border: 1px solid var(--mud-palette-lines-default);
}

/* Wide enough for "Choose several" without wrapping, narrow enough to leave the name the room. */
.fields[b-yoyvhhudsp]  .field-kind {
    max-width: 11rem;
}

/* Sits in the row beside the name and the kind, so it is capped for the same reason the kind is:
   an option is a dropdown label, and the name field should keep the slack. */
.fields[b-yoyvhhudsp]  .field-option-input {
    max-width: 14rem;
}

/* The committed options. No ::deep: this div is rendered by the component itself, so it carries
   the scope attribute — only the MudChips inside it would need one. Wraps, because a field can
   list more options than fit on one line. */
.field-options[b-yoyvhhudsp] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
}

/* --- Reordering ------------------------------------------------------------------------------
   The grip, and only the grip, starts a drag — MudDragHandle sees to that, which is what keeps
   dragging to select text inside a field from dragging the row instead. The cursors are the
   board's (ClientDetail.razor.css), so a draggable thing feels the same in both places. */

.fields[b-yoyvhhudsp]  .field-grip {
    display: flex;
    align-items: center;
    color: var(--mud-palette-text-secondary);
    cursor: grab;
}

.fields[b-yoyvhhudsp]  .field-grip:active {
    cursor: grabbing;
}

/* The row being moved, lifted off the list so it is obvious which one is travelling. */
.fields[b-yoyvhhudsp]  .field-row-dragging {
    opacity: 0.5;
    outline: 2px dashed var(--mud-palette-primary);
    outline-offset: -2px;
}
/* /Components/Pages/Org/TaskOverviewDialog.razor.rz.scp.css */
/* Line breaks in a description are meaning, not markup — the same treatment .client-notes gets.
   ::deep because MudText renders its own root element, which never carries this component's scope
   attribute. */
[b-5zpopju8yn] .task-description {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A comment sits on its own ground so the list reads as separate entries rather than one block.
   ::deep because MudPaper and MudText render their own root elements. */
[b-5zpopju8yn] .comment {
    border: 1px solid var(--mud-palette-lines-default);
}

[b-5zpopju8yn] .comment-body {
    white-space: pre-wrap;
    /* pre-wrap alone wraps at spaces, so a long run without any overflows instead — and
       .comment-list has overflow-y set, which makes the browser coerce overflow-x from visible to
       auto, so the overflow showed up as a horizontal scrollbar rather than as clipping.
       `anywhere` over `break-word`: both break a run that will not fit, and either would do here
       because these ancestors are explicitly sized. They part company only when an ancestor is
       sized by its content — `anywhere` shrinks min-content width, `break-word` does not — so it is
       the one that stays correct if this markup is ever reused somewhere shrink-to-fit. */
    overflow-wrap: anywhere;
}

/* Roughly four comments before it scrolls — the same 22rem the client page falls back to on a short
   viewport. Without this the dialog grows with the conversation and its own fields scroll away.
   No ::deep: the div this lands on is rendered by the component itself. */
.comment-list[b-5zpopju8yn] {
    max-height: 22rem;
    overflow-y: auto;
    /* Room for the scrollbar, so it never sits on top of a comment's delete button. */
    padding-right: 0.25rem;
}
/* /Components/Pages/OrgHome.razor.rz.scp.css */
/* The page fills the viewport exactly and never scrolls itself. Three regions share the height:
   the header stays put, the attention list is bounded to a share of what is left, and the two bands
   of tiles take the remainder. `min-height: 0` appears on every level that scrolls, and it is
   load-bearing in each case — without it a flex or grid child refuses to shrink below its content
   and the document scrolls instead of the region, which is the failure this layout exists to
   remove. */

.org-home[b-bpfy3x9c6z] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    /* The viewport, less the app bar and MudContainer's py-8 — the same budget OrganizationList and
       ClientDetail use. --mud-appbar-height is emitted at runtime by MudThemeProvider and is not in
       MudBlazor's stylesheet, hence the fallback. */
    height: calc(100dvh - var(--mud-appbar-height, 64px) - 4rem);
}

.org-home-header[b-bpfy3x9c6z] {
    flex: 0 0 auto;
}

/* The three section headings: an icon and the word, on one line. `flex: 0 0 auto` because a heading
   is the one thing in these columns that must never be squeezed — it used to be a bare MudText,
   which defaulted to `0 1 auto` and could shrink. Size.Small is 1.25rem, the same as Typo.h6, so
   the icon sits on the text's own line rather than riding above it. */
.org-home-heading[b-bpfy3x9c6z] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Sizes to its content but never past 40% of the page: what is waiting outranks where to navigate,
   so it comes first — but an unbounded list of overdue tasks would otherwise squeeze the bands
   below it to nothing. */
.org-home-attention[b-bpfy3x9c6z] {
    flex: 0 1 auto;
    min-height: 0;
    max-height: 40%;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.org-home-attention-body[b-bpfy3x9c6z] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Work takes the larger share, and not because it holds more tiles — it holds one. The Clients
   card is simply the big one: it carries a list of the clients wanting this person now, where the
   Administration cards carry a title and a count. */
.org-home-sections[b-bpfy3x9c6z] {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 1rem;
}

/* A grid item's automatic minimum size is its content, exactly as a flex child's is, so this
   min-height is needed here for the same reason it is needed above. */
.org-home-group[b-bpfy3x9c6z] {
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.org-home-group-body[b-bpfy3x9c6z] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* MudCard's root element is MudBlazor's and never carries this component's scope attribute, so the
   rule has to reach it through ::deep from a div we render ourselves. */
.org-home-group-body[b-bpfy3x9c6z]  .org-home-card {
    height: 100%;
}

/* The locked layout is a desktop affordance — the same release ClientDetail uses. In a short or
   narrow window three regions sharing one viewport become unusable strips, so the lock comes off
   and the page scrolls as an ordinary document. */
@media (max-height: 700px), (max-width: 900px) {
    .org-home[b-bpfy3x9c6z] {
        height: auto;
    }

    .org-home-attention[b-bpfy3x9c6z] {
        max-height: none;
    }

    .org-home-attention-body[b-bpfy3x9c6z],
    .org-home-group-body[b-bpfy3x9c6z] {
        overflow-y: visible;
    }

    .org-home-sections[b-bpfy3x9c6z] {
        grid-template-columns: 1fr;
    }
}

/* The rows themselves are plain divs this component renders, so they carry its scope attribute and
   need no ::deep. Their *contents* are MudText, whose rendered element belongs to MudBlazor and
   never carries it — hence the ::deep below. Without it that rule compiles to `* [b-xxx]`, matches
   nothing, and fails silently: the titles simply stop truncating. The height of the card around
   them is set inline for the same reason, there being no plain element to anchor a ::deep on. */

.action-row[b-bpfy3x9c6z] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* No rule under the last row: the card's own padding is the space there, and a line against it
   reads as a section that got cut off. */
.action-row:last-child[b-bpfy3x9c6z] {
    border-bottom: none;
    padding-bottom: 0;
}

/* A plain element of ours, so the rule needs no ::deep — and being a sibling of -main rather than
   a child, the truncation rule below cannot reach it either. */
.action-row-kind[b-bpfy3x9c6z] {
    flex: 0 0 auto;
    display: flex;
}

/* Takes the slack, so the meta and the button stay put and the title is what truncates. */
.action-row-main[b-bpfy3x9c6z] {
    flex: 1 1 auto;
    min-width: 0;
}

.action-row-main[b-bpfy3x9c6z]  * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Wraps rather than squeezing the title away on a narrow card, since both halves sit side by side
   only above the md breakpoint. */
.action-row-meta[b-bpfy3x9c6z] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 0 1 auto;
    flex-wrap: wrap;
    gap: 0.25rem;
    text-align: right;
}
