/* /Components/AppIcon.razor.rz.scp.css */
/* Size only. Colour comes from currentColor inside the markup, and the paths are a
   mix of stroked and filled - setting either here would break half the set. */
.app-icon[b-spmrhz3h7r] {
    width: 1.25rem;
    height: 1.25rem;
    /* Stops an icon being squashed when it sits in a flex row beside text. */
    flex: none;
}
/* /Components/Charts/AnalyticsBars.razor.rz.scp.css */
/* =============================================================================
   The ranked bar list
   -----------------------------------------------------------------------------
   FOUR FIXED COLUMNS, IDENTICAL ON EVERY ROW - label, bar, value, share. The bar
   is the only flexible one, so the label and both figures sit on the same
   vertical lines all the way down the list and the eye can run down a column
   instead of finding each figure separately. `auto` on the figure columns would
   size each row to its own content and leave the decimal points staggered, which
   is the one thing a ranked list of numbers must not do.

   NO COLOUR IS SET HERE. The fill wears a chart-cat-N class from app.css, which
   carries --chart-colour, and this file only spends it. That is what keeps
   Piping the same colour in this list, the pie and the heatmap.
   ============================================================================= */

.bars[b-n17a9k87gb] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The row is the grid; the <li> is only there to make the list a list. */
.bars__cells[b-n17a9k87gb] {
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr) 5rem 4rem;
    align-items: center;
    gap: var(--space-3);
    width: 100%;

    /* Every row is the same height whether it is a button or the plain folded row,
       so the fold does not put a step in the middle of the list. */
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    text-align: left;
}

/* A row that narrows the report. The declarations below are all undoing the
   application's default button - a bordered, centred, surface-coloured box - and
   nothing more: hover and press are deliberately left to base.css, whose
   translucent state layer works over a transparent background like any other, so
   this list cannot drift out of step with the rest of the application's controls. */
.bars__cells--select[b-n17a9k87gb] {
    display: grid;
    border-color: transparent;
    background-color: transparent;
    font: inherit;
    color: inherit;
}

/* Clipped rather than wrapped. A trade or a person's name that will not fit costs
   the reader the tail of a word they can recover from the title or the itemised
   table below; a name wrapped onto three lines costs them the alignment that makes
   the whole list readable, on every row at once. */
.bars__label[b-n17a9k87gb] {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* The track is the full width of its column, so a bar's length is read against the
   same distance on every row - without it the reader would be comparing lengths
   drawn to different scales. */
.bars__track[b-n17a9k87gb] {
    height: var(--space-3);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-inset);
    overflow: hidden;
}

.bars__fill[b-n17a9k87gb] {
    display: block;
    width: var(--bar-length);

    /* A row with hours in it always leaves a visible mark. Rounding a genuine but
       tiny share to a zero-width bar would read as "nothing here", which is the one
       thing it is not - and the row is only drawn at all when its value is above
       zero, so this can never invent a bar out of nothing. */
    min-width: var(--space-1);
    height: 100%;
    border-radius: var(--radius-full);
    background-color: var(--chart-colour);
}

.bars__value[b-n17a9k87gb],
.bars__share[b-n17a9k87gb] {
    /* Digits of one width, so the figures line up on the decimal point down the
       column and a longer number reads as a larger one. */
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.bars__value[b-n17a9k87gb] {
    font-weight: var(--font-weight-semibold);
}

/* Quieter than the value it stands beside: the share answers a second question,
   and at equal weight the two figures compete for the same glance. */
.bars__share[b-n17a9k87gb] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* -----------------------------------------------------------------------------
   Narrow screens - 48rem and 30rem, from the scale in tokens.css
   -----------------------------------------------------------------------------
   The columns never collapse and the rows never stack. What gives way is the
   label column and then the bar, in that order, because the ranking survives a
   bar squeezed to a stub and does not survive figures that no longer line up.
   ----------------------------------------------------------------------------- */

@media (max-width: 48rem) {
    .bars__cells[b-n17a9k87gb] {
        grid-template-columns: minmax(0, 8rem) minmax(0, 1fr) 4.5rem 3.5rem;
        gap: var(--space-2);
    }
}

@media (max-width: 30rem) {
    .bars__cells[b-n17a9k87gb] {
        grid-template-columns: minmax(0, 6rem) minmax(0, 1fr) 4rem 3rem;
        padding: var(--space-2);
        font-size: var(--font-size-sm);
    }

    .bars__share[b-n17a9k87gb] {
        font-size: var(--font-size-xs);
    }
}
/* /Components/Charts/AnalyticsCurve.razor.rz.scp.css */
/* Hours to date.

   DELIBERATELY THE TREND'S TWIN. The two charts sit one above the other on the reports screen and
   share an x-axis, so a reader matches a week in one against the same week in the other by eye. That
   only works if the plots are the same height, the ticks sit in the same places and the padding is
   identical - so the measurements here are the trend's measurements, and changing one without the
   other pulls the two axes out of step.

   The rules are duplicated rather than shared because component-scoped CSS cannot be imported, which
   is the same constraint ChartPalette works around in C#. Whatever moves here moves in
   AnalyticsLine.razor.css too. */

.curve[b-y882aniq6y] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.curve__frame[b-y882aniq6y] {
    padding: var(--space-4) var(--space-2) 0;
}

.curve__plot[b-y882aniq6y] {
    position: relative;
    height: calc(var(--space-8) * 3);
    border-bottom: var(--border-width) solid var(--color-border);
}

.curve__svg[b-y882aniq6y] {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;

    /* The curve reaches y=0 at the total, so the outer half of its stroke sits above the viewport.
       Visible lets it show in the frame's padding rather than being clipped flat. */
    overflow: visible;
}

.curve__area[b-y882aniq6y] {
    fill: var(--color-accent);
    opacity: 0.14;
}

.curve__stroke[b-y882aniq6y] {
    fill: none;
    stroke: var(--color-accent);
    stroke-width: calc(var(--border-width) * 2);
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}

/* A bucket the period only partly covers. Dashed, exactly as on the trend, so the pattern means one
   thing across both charts. */
.curve__stroke--partial[b-y882aniq6y] {
    stroke-dasharray: calc(var(--border-width) * 5) calc(var(--border-width) * 4);
}

/* THE EVEN-PACE REFERENCE, AND IT MUST NOT LOOK LIKE DATA. Hairline, muted, solid: thinner than the
   curve so it reads as a rule rather than a second series, muted so it never competes for the eye,
   and solid because dashes on this screen already mean "partly covered". It is not a plan and must
   never be styled as a target - there is no plan in this product to draw. */
.curve__pace[b-y882aniq6y] {
    fill: none;
    stroke: var(--color-text-muted);
    stroke-width: var(--border-width);
    opacity: 0.7;
}

.curve__gridline[b-y882aniq6y] {
    position: absolute;
    right: 0;
    left: 0;
    border-top: var(--border-width) dashed var(--color-border);
}

/* Always the period's total, because a cumulative curve cannot fall. */
.curve__gridline--peak[b-y882aniq6y] {
    top: 0;
}

.curve__gridline--half[b-y882aniq6y] {
    top: 50%;
}

/* LIFTED OVER THE DRAWING, AND RINGED IN THE PANEL'S OWN COLOUR - see the same rule in
   AnalyticsLine, which carries the long version. In short: the rules are drawn before the curve so
   that the curve covers them, and the number attached to a rule was swept along with it. The
   half-height one sits inside the plot and went under the fill; the peak one hangs above the plot and
   never showed the fault. It matters more here than on the trend, because a cumulative curve climbs
   left to right and therefore crosses its own half-height rule every time. */
.curve__gridline-value[b-y882aniq6y] {
    position: absolute;
    z-index: 1;
    bottom: 100%;
    left: 0;
    padding-bottom: var(--space-1);
    padding-inline-end: var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-container);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Terminates the curve at the total. Ringed in the panel surface so it stays a distinct dot where
   the curve runs steeply into it. Never hollowed - see the component: the figure it marks is the
   period's real total whether or not the last bucket is whole. */
.curve__marker[b-y882aniq6y] {
    position: absolute;
    width: var(--space-2);
    height: var(--space-2);
    box-sizing: border-box;
    border: var(--border-width) solid var(--color-surface-container);
    border-radius: var(--radius-full);
    background-color: var(--color-accent);
    transform: translate(-50%, 50%);
}

.curve__ticks[b-y882aniq6y] {
    position: relative;
    height: var(--space-5);
    margin-inline: var(--space-2);
}

.curve__tick[b-y882aniq6y] {
    position: absolute;
    top: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.curve__tick--first[b-y882aniq6y] {
    transform: none;
}

.curve__tick--middle[b-y882aniq6y] {
    transform: translateX(-50%);
}

.curve__tick--last[b-y882aniq6y] {
    transform: translateX(-100%);
}

.curve__note[b-y882aniq6y] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
}

@media (max-width: 30rem) {
    .curve__plot[b-y882aniq6y] {
        height: calc(var(--space-8) * 2);
    }
}

/* =============================================================================
   THE DAY THE MAP IS SHOWING
   -----------------------------------------------------------------------------
   The same three marks the trend carries, and see AnalyticsLine for why they are
   HTML rather than shapes in the viewBox. They matter more here: a cumulative
   curve answers "how much so far", and the scrim is what turns that from a
   finished picture into the period accumulating as it plays.
   ============================================================================= */

.curve__cursor[b-y882aniq6y] {
    position: absolute;
    inset-block: 0;
    width: var(--border-width);
    background-color: var(--color-text-secondary);
    transform: translateX(-50%);
}

/* Filled in the accent rather than ringed in the surface: it marks a point on the
   curve, where the end marker terminates it. The end marker's own rule is
   untouched - the period's real total is still a settled, solid dot. */
.curve__marker--at[b-y882aniq6y] {
    border-color: var(--color-accent);
    background-color: var(--color-accent);
}

.curve__ahead[b-y882aniq6y] {
    position: absolute;
    inset-block: 0;
    right: 0;
    background-color: var(--color-surface-container);
    opacity: 0.72;
}

.curve__reading[b-y882aniq6y] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
}

.curve__reading strong[b-y882aniq6y] {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

/* Reserved whether or not there is a reading in it. The line appears on the first
   frame of playback, and a panel that grows by a line at that moment pushes the
   drawing - and the Play button the reader has just pressed - down the page. */
.curve__reading[b-y882aniq6y] {
    min-height: calc(var(--font-size-sm) * var(--line-height-base));
}
/* /Components/Charts/AnalyticsHeatmap.razor.rz.scp.css */
/* =============================================================================
   THE HEATMAP
   -----------------------------------------------------------------------------
   A grid, not a table element: the label column has to stick to the left edge of
   a scrolling box and every cell has to be the same width whatever is printed in
   it, and CSS grid does both without a single measurement. It reflows on a phone
   by shrinking two custom properties at the bottom of this file and nothing else.

   THE LINES BETWEEN CELLS ARE THE GAP. The grid paints a border colour behind
   itself and the cells sit on top with opaque fills, so the one-pixel rules are
   the grid showing through rather than borders on every cell - which would double
   up along every shared edge and again against the container's own border.

   THE FILLS ARE THE FIVE RAMP TOKENS AND NOTHING ELSE. No opacity, no colour
   mixing: those five were chosen so --color-on-scale is readable on all of them
   in both themes, and anything computed lands the text on a shade nobody checked.
   ============================================================================= */

.heatmap[b-ar94bblxvg] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);

    /* The shell gives .app-main min-width: 0 so this can be narrower than its
       content; without it a wide grid would push the whole page sideways. */
    min-width: 0;
}

/* What the shading means, in words, because a ramp with no ends labelled is a
   decoration. The swatches repeat the fills the cells use, so the key cannot
   drift from the grid it explains. */
.heatmap__key[b-ar94bblxvg] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.heatmap__key-steps[b-ar94bblxvg] {
    display: flex;
    gap: var(--border-width);
}

.heatmap__key-step[b-ar94bblxvg] {
    width: 1.75rem;
    height: 0.75rem;
    border-radius: var(--radius-sm);
}

/* THE CONTAINER SCROLLS, THE PAGE NEVER DOES. Thirty-one columns of days will not
   fit a phone at any font size worth reading, so the overflow is owned here. */
.heatmap__scroller[b-ar94bblxvg] {
    overflow-x: auto;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.heatmap__grid[b-ar94bblxvg] {
    /* Two knobs, so the phone rules at the bottom are two lines rather than a
       second copy of this stylesheet. */
    --heatmap-label: 10rem;
    --heatmap-cell: 4.25rem;

    display: grid;

    /* A fixed label track and equal data tracks that grow into spare room. The
       fallback of 1 matters only if the component were ever drawn without its
       computed count: one wrong column beats a collapsed grid. */
    grid-template-columns:
        var(--heatmap-label)
        repeat(var(--heatmap-columns, 1), minmax(var(--heatmap-cell), 1fr));

    /* Wider than the scroller when the columns demand it, full width when they do
       not - which is what makes the tracks stretch on a desktop and scroll on a
       phone with no second layout. */
    min-width: max-content;

    gap: var(--border-width);
    background-color: var(--color-border-muted);
}

.heatmap__corner[b-ar94bblxvg],
.heatmap__head[b-ar94bblxvg],
.heatmap__label[b-ar94bblxvg],
.heatmap__cell[b-ar94bblxvg] {
    display: flex;
    align-items: center;
    padding: var(--space-2);
    min-width: 0;

    /* Each cell is one line, so this is a line rather than a column of boxes and
       centring is what lines the figures up with the labels beside them. */
    line-height: var(--line-height-tight);
}

.heatmap__corner[b-ar94bblxvg],
.heatmap__head[b-ar94bblxvg],
.heatmap__label[b-ar94bblxvg] {
    background-color: var(--color-surface-table-header);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
}

.heatmap__head[b-ar94bblxvg] {
    justify-content: center;
    text-align: center;

    /* A bucket label - "14 Aug", "wk 33" - is short and must stay on one line, or
       one long month name would set the height of the whole header row. */
    white-space: nowrap;
}

/* THE ROW LABELS STAY PUT. z-index lifts them above the cells sliding underneath,
   and the shadow draws the separating rule over that gap - without it a
   one-pixel sliver of moving numbers shows along the sticky column's edge. */
.heatmap__corner[b-ar94bblxvg],
.heatmap__label[b-ar94bblxvg] {
    position: sticky;
    inset-inline-start: 0;
    z-index: 1;
    box-shadow: var(--border-width) 0 0 0 var(--color-border);
}

.heatmap__label[b-ar94bblxvg] {
    gap: var(--space-2);
    color: var(--color-text);
    font-size: var(--font-size-sm);
}

/* The hue this row wears in the bar list and the pie, so a reader matching charts
   is matching a colour rather than re-reading a list of names. */
.heatmap__swatch[b-ar94bblxvg] {
    flex: none;
    width: 0.625rem;
    height: 0.625rem;
    border-radius: var(--radius-full);
    background-color: var(--chart-colour);
}

/* A long name is clipped rather than allowed to widen the sticky column, which is
   the one track that costs the reader screen space on every column they scroll
   to. The full text is in the label's title and in the table below the grid. */
.heatmap__name[b-ar94bblxvg] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.heatmap__cell[b-ar94bblxvg] {
    justify-content: center;
    font-size: var(--font-size-sm);

    /* Figures in a grid are read down a column as much as across a row, and only
       fixed-width digits line the decimal points up. */
    font-variant-numeric: tabular-nums;
}

/* Nothing happened here. The panel surface rather than the palest step, so an
   untouched cell reads as a hole in the grid, and the 0 is muted so the eye
   passes over it instead of counting it. */
.heatmap__cell--empty[b-ar94bblxvg] {
    background-color: var(--color-surface-container);
    color: var(--color-text-muted);
}

.heatmap__shade--1[b-ar94bblxvg],
.heatmap__shade--2[b-ar94bblxvg],
.heatmap__shade--3[b-ar94bblxvg],
.heatmap__shade--4[b-ar94bblxvg],
.heatmap__shade--5[b-ar94bblxvg] {
    color: var(--color-on-scale);
}

.heatmap__shade--1[b-ar94bblxvg] { background-color: var(--color-scale-1); }
.heatmap__shade--2[b-ar94bblxvg] { background-color: var(--color-scale-2); }
.heatmap__shade--3[b-ar94bblxvg] { background-color: var(--color-scale-3); }
.heatmap__shade--4[b-ar94bblxvg] { background-color: var(--color-scale-4); }
.heatmap__shade--5[b-ar94bblxvg] { background-color: var(--color-scale-5); }

/* A phone gives up label width and cell width before it gives up the printed
   figures - a heatmap you have to scroll twice as far across is still readable,
   one with the numbers dropped out of it is not. */
@media (max-width: 40rem) {
    .heatmap__grid[b-ar94bblxvg] {
        --heatmap-label: 7rem;
        --heatmap-cell: 3.25rem;
    }

    .heatmap__corner[b-ar94bblxvg],
    .heatmap__head[b-ar94bblxvg],
    .heatmap__label[b-ar94bblxvg],
    .heatmap__cell[b-ar94bblxvg] {
        padding: var(--space-1);
    }

    .heatmap__label[b-ar94bblxvg],
    .heatmap__cell[b-ar94bblxvg] {
        font-size: var(--font-size-xs);
    }
}

/* A column the period only partly covers. Marked on the heading rather than on the
   cells: the cells still hold true figures, and shading them differently would be a
   second encoding of something the numbers already say. The asterisk carries it for
   anybody who cannot see the muted colour, and the note below the grid explains it. */
.heatmap__head--partial[b-ar94bblxvg] {
    color: var(--color-text-muted);
    font-style: italic;
}

.heatmap__note[b-ar94bblxvg] {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}
/* /Components/Charts/AnalyticsHistogram.razor.rz.scp.css */
/* The distribution of job sizes. Columns in band order, height by job count, one colour.

   NO SVG AND NO CANVAS. A column chart is a row of boxes with a percentage height, which is a thing
   CSS grid already does - and doing it that way is what makes it reflow on a phone without a single
   media query or a line of measuring code. */

.histogram[b-so2vmy6z2g] {
    /* The plot's height, named once and derived from the spacing scale rather than picked. Everything
       else in the component is auto-sized around it, so this is the only number that decides how tall
       the chart reads. */
    --histogram-plot-height: calc(var(--space-8) * 3);

    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
}

/* Wide content scrolls inside its own container. A period that produced many bands must take its own
   overflow rather than pushing the page sideways on a 320px screen. */
.histogram__scroll[b-so2vmy6z2g] {
    overflow-x: auto;
}

/* One column per band, in band order, all starting at the same top edge - the layout rule from
   base.css, and here it is not merely tidy: columns that did not share a top would not share a
   baseline either, and heights drawn against different baselines cannot be compared by eye. */
.histogram__plot[b-so2vmy6z2g] {
    display: grid;
    grid-auto-flow: column;
    /* Columns share the width evenly but never squeeze below a readable minimum; past that the
       container above scrolls instead. */
    grid-auto-columns: minmax(var(--space-7), 1fr);
    align-items: stretch;
    gap: var(--space-2);
    height: var(--histogram-plot-height);
}

/* Count and hours on top, column in the middle, label underneath. The middle row takes the slack, so
   every figure sits on its own line whatever the heights are. */
.histogram__band[b-so2vmy6z2g] {
    display: grid;
    grid-template-rows: auto auto 1fr auto;
    gap: var(--space-1);
    min-width: 0;
}

.histogram__count[b-so2vmy6z2g] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    /* Figures in a row are being compared, so they line up digit under digit. */
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
    text-align: center;
}

/* The lane a column grows in. It carries the baseline, which is what makes an empty band read as a
   measured zero rather than as a bar somebody forgot to draw. */
.histogram__track[b-so2vmy6z2g] {
    position: relative;
    min-height: 0;
    border-bottom: var(--border-width) solid var(--color-border-strong);
}

/* Absolutely positioned rather than a flex child, so the percentage height in the markup resolves
   against a container whose height is already settled - a flex item's is not, and small columns would
   round to nothing in some browsers and not others. */
.histogram__fill[b-so2vmy6z2g] {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    min-height: var(--border-width);
    border-radius: var(--radius-sm) var(--radius-sm) var(--radius-none) var(--radius-none);
    background-color: var(--color-accent);
}

.histogram__label[b-so2vmy6z2g] {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-tight);
    text-align: center;
    /* "8 h or more" in a 3rem column has to break somewhere; breaking it is better than letting it
       widen the column and start the whole row scrolling. */
    overflow-wrap: anywhere;
}

/* The hours in the band, under the count that names how many jobs made them. Quieter than the count,
   because the count is what the column's height already says and the hours are the second question. */
.histogram__hours[b-so2vmy6z2g] {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
    text-align: center;
    white-space: nowrap;
}

/* =============================================================================
   SIX BANDS ON A PHONE
   -----------------------------------------------------------------------------
   This file had no media query at all, and the floor above is --space-7: six
   bands come to 6 x 48 + 5 x 8 = 328px, into the ~294px a panel gets at 360px.
   The band that scrolled off was the last one - "8 h or more" - which is the
   band the panel's own hint is written about.

   40px rather than anything tighter: .histogram__count is "1 284" at 12px, about
   35px, and a narrower track wraps the figure it exists to show. The gap closes
   to --space-1 in the same breath, because 6 x 40 + 5 x 8 is 280px and the box
   measures 279 - a column chart one pixel over its container is still a column
   chart that scrolls. At 6 x 40 + 5 x 4 = 260px it fits with room to spare.

   The plot also shortens to the height the trend and the curve use on a phone,
   so the three charts on that screen read as one family.
   ============================================================================= */
@media (max-width: 30rem) {
    .histogram[b-so2vmy6z2g] {
        --histogram-plot-height: calc(var(--space-8) * 2);
    }

    .histogram__plot[b-so2vmy6z2g] {
        grid-auto-columns: minmax(2.5rem, 1fr);
        gap: var(--space-1);
    }
}
/* /Components/Charts/AnalyticsLine.razor.rz.scp.css */
/* The trend line.

   NOTHING HERE HAS A SIZE OF ITS OWN except the plot's height, and that is composed from the spacing
   scale rather than typed as a number. Everything else is a percentage, which is what lets the same
   markup be 900px of desktop panel and 320px of phone without a media query deciding anything.

   THE FRAME'S PADDING IS LOAD-BEARING. The line reaches y=0 at its peak and the marker sits on the
   last point, so both overflow the plot box by half a stroke and half a dot. The padding is the room
   they overflow into; without it a peak in the final week is a dot with its top sliced off. The top
   is wider than the sides because the peak gridline's label hangs above the plot as well. */

.line[b-l014ihzzvb] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.line__frame[b-l014ihzzvb] {
    padding: var(--space-4) var(--space-2) 0;
}

/* The floor is the axis the area fill stands on, not a third gridline: a chart whose fill just stops
   in mid-air reads as clipped rather than finished. */
.line__plot[b-l014ihzzvb] {
    position: relative;
    height: calc(var(--space-8) * 3);
    border-bottom: var(--border-width) solid var(--color-border);
}

/* Positioned rather than in flow so that document order decides what covers what: gridlines first,
   then the line over them, then the marker over everything. An in-flow SVG would paint underneath
   both of its positioned siblings and the gridlines would cut across the data. */
.line__svg[b-l014ihzzvb] {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    /* The stroke at the peak is centred on the very top edge, and SVG clips to its viewport by
       default. Visible lets the outer half of it show in the frame's padding. */
    overflow: visible;
}

/* One accent colour at two weights. A second token for the fill would be a colour somebody has to
   keep in step with the line; an opacity cannot drift. */
.line__area[b-l014ihzzvb] {
    fill: var(--color-accent);
    opacity: 0.14;
}

.line__stroke[b-l014ihzzvb] {
    fill: none;
    stroke: var(--color-accent);
    /* Twice the hairline the rest of the application draws borders at - a trend is the subject of
       this panel, not a divider. non-scaling-stroke is what keeps it that thickness after
       preserveAspectRatio="none" has stretched the viewBox sideways. */
    stroke-width: calc(var(--border-width) * 2);
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}

/* The piece of the line whose bucket the period only partly covers. Dashed rather than a second
   colour: a colour on this chart means a category, and there is only one series here - a reader who
   saw two colours would go looking for the split that produced them. The pattern is composed from the
   hairline token like the stroke width above it, so the dashes stay in proportion to the line at any
   width; it is measured in the same units as the stroke, which non-scaling-stroke keeps constant. */
.line__stroke--partial[b-l014ihzzvb] {
    stroke-dasharray: calc(var(--border-width) * 5) calc(var(--border-width) * 4);
}

.line__gridline[b-l014ihzzvb] {
    position: absolute;
    right: 0;
    left: 0;
    border-top: var(--border-width) dashed var(--color-border);
}

.line__gridline--peak[b-l014ihzzvb] {
    top: 0;
}

.line__gridline--half[b-l014ihzzvb] {
    top: 50%;
}

/* Above its own rule and hard left, which is where a reader looks for a scale. Sitting on top of the
   rule rather than in a gutter of its own keeps the full width of the panel for the data - a gutter
   costs the same 4rem on a phone as on a desktop, where it hurts far more.

   LIFTED OVER THE DRAWING, AND RINGED IN THE PANEL'S OWN COLOUR. The rules below are drawn before the
   line so that the line covers them, which is right for a rule and was wrong for the number attached
   to it: the half-height label sits inside the plot, so it went under the area fill with everything
   else on that layer and could not be read. The peak label never showed the fault, because it hangs
   above the plot where there is nothing to cover it - which is why this only ever looked like one
   missing number rather than a broken axis.

   z-index rather than moving it in the markup: the label has to stay a child of the rule it names, or
   its position stops following it. The backdrop is the same trick the marker uses a few rules down,
   for the same reason - a number over a two-pixel stroke is a number with a line through it. */
.line__gridline-value[b-l014ihzzvb] {
    position: absolute;
    z-index: 1;
    bottom: 100%;
    left: 0;
    padding-bottom: var(--space-1);
    padding-inline-end: var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-container);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Ringed in the panel's own surface colour so it stays a distinct dot where the line runs steeply
   into it, instead of merging with the stroke it terminates. */
.line__marker[b-l014ihzzvb] {
    position: absolute;
    width: var(--space-2);
    height: var(--space-2);
    box-sizing: border-box;
    border: var(--border-width) solid var(--color-surface-container);
    border-radius: var(--radius-full);
    background-color: var(--color-accent);
    transform: translate(-50%, 50%);
}

/* Hollow when the period covers only part of that last bucket - the two colours of the solid dot
   swapped over rather than a shape or a size of its own, so the dot stays exactly where it was and
   the same size, and only its weight changes. An outline reads as provisional where a filled disc
   reads as settled, which is the distinction being drawn. */
.line__marker--partial[b-l014ihzzvb] {
    border-color: var(--color-accent);
    background-color: var(--color-surface-container);
}

/* Margin, not padding: the ticks are absolutely positioned, and an absolute child measures its
   percentages against the padding box - so padding here would leave them out of step with the plot
   they label, while a margin moves the box itself. */
.line__ticks[b-l014ihzzvb] {
    position: relative;
    height: var(--space-5);
    margin-inline: var(--space-2);
}

.line__tick[b-l014ihzzvb] {
    position: absolute;
    top: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Each label is anchored so it stays inside the plot's width: the first grows rightwards from the
   first point, the last grows leftwards from the last, and only the middle one is centred on its
   own point. Centring all three would push half of the first and half of the last off the panel. */
.line__tick--first[b-l014ihzzvb] {
    transform: none;
}

.line__tick--middle[b-l014ihzzvb] {
    transform: translateX(-50%);
}

.line__tick--last[b-l014ihzzvb] {
    transform: translateX(-100%);
}

/* What the dashes mean, in words. Muted and small because it is a caveat rather than a finding, but
   ordinary text rather than a title attribute: the reader it is written for is the one drawing the
   wrong conclusion from the picture, and they are not going to hover over anything to find it. The
   margin is zeroed because the flex gap on .line already spaces it. */
.line__note[b-l014ihzzvb] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
}

/* A phone gives the panel about a third of the width, and the same height would make the line a
   near-vertical scribble. Shorter keeps the slope readable. */
@media (max-width: 30rem) {
    .line__plot[b-l014ihzzvb] {
        height: calc(var(--space-8) * 2);
    }
}

/* =============================================================================
   THE DAY THE MAP IS SHOWING
   -----------------------------------------------------------------------------
   Drawn only while the reader is playing or scrubbing the drawing further down
   the page. All three marks are HTML over the plot rather than shapes inside the
   viewBox, for the reason the end marker gives: preserveAspectRatio="none"
   stretches the viewBox sideways, so a circle drawn in it is an ellipse whose
   shape depends on the window.

   They sit under .line__gridline-value, which carries z-index 1 - the peak and
   half-peak figures have to stay readable through the scrim, or playing the
   period costs the reader the scale.
   ============================================================================= */

/* Neutral, and never dashed. Colour on this page means a category and a dash on
   this chart means a partial bucket; a cursor is neither, so it takes the one
   weight left that says "a position" rather than "a value". */
.line__cursor[b-l014ihzzvb] {
    position: absolute;
    inset-block: 0;
    width: var(--border-width);
    background-color: var(--color-text-secondary);
    transform: translateX(-50%);
}

/* The same dot as the end marker, in the accent's own colour rather than ringed
   in the surface - it marks a point on the line rather than terminating it. */
.line__marker--at[b-l014ihzzvb] {
    border-color: var(--color-accent);
    background-color: var(--color-accent);
}

/* WHAT HAS NOT HAPPENED YET. The half of this the reader asked for: the period
   fills in as it plays instead of a cursor sliding over a finished picture. One
   span, so the three polylines the partial-bucket arithmetic cuts are untouched,
   and the area fill dims with the stroke for free.

   Not opaque. The destination stays faintly visible, because a line whose end is
   hidden is a line nobody can judge the pace of - and on the cumulative curve
   beside it, the end is the total. */
.line__ahead[b-l014ihzzvb] {
    position: absolute;
    inset-block: 0;
    right: 0;
    background-color: var(--color-surface-container);
    opacity: 0.72;
}

/* The figure under the cursor, in words, because at 360px a month of buckets
   gives about ten pixels each: the mark is legible there and its value is not. */
.line__reading[b-l014ihzzvb] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
}

.line__reading strong[b-l014ihzzvb] {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

/* Reserved whether or not there is a reading in it. The line appears on the first
   frame of playback, and a panel that grows by a line at that moment pushes the
   drawing - and the Play button the reader has just pressed - down the page. */
.line__reading[b-l014ihzzvb] {
    min-height: calc(var(--font-size-sm) * var(--line-height-base));
}
/* /Components/Charts/AnalyticsPie.razor.rz.scp.css */
/* The circle and the legend are two columns that both start at the top of the panel,
   because they are boxes with height rather than a line of controls - a legend of two
   rows floating against the middle of the pie would leave no line for the eye to start
   from. `align-items: start` also stops the legend stretching its rows to the height of
   the circle beside it. */
.pie[b-vtv8tsq8ib] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: var(--space-5);
}

/* Capped in absolute terms rather than as a fraction of the panel: past about this size
   a pie stops telling the reader anything more and only pushes the legend - the part
   with the numbers in it - off the side. */
.pie__figure[b-vtv8tsq8ib] {
    width: min(11rem, 100%);
}

/* The viewBox does the scaling, so height follows width and the disc stays a disc at
   every width without a media query. */
.pie__svg[b-vtv8tsq8ib] {
    display: block;
    width: 100%;
    height: auto;
}

/* The whole reason this is drawn as separate elements: each wedge takes its colour from
   the chart-cat-n class beside it, which is the same class the bars and the heatmap use.
   No colour is named here, and none may be. */
.pie__slice[b-vtv8tsq8ib] {
    fill: none;
    stroke: var(--chart-colour);
}

.pie__legend[b-vtv8tsq8ib] {
    display: grid;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One row, four columns, and the two figures at the right where a column of numbers can
   be compared down the page. minmax(0, 1fr) on the label is what lets it ellipsis rather
   than push the numbers out of the panel - a person's full name in a Person grouping is
   longer than any legend has room for. */
.pie__entry[b-vtv8tsq8ib] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-1) var(--space-2);
    text-align: left;
}

/* The clickable version. It is a real button, so it already carries the shared hover,
   press and focus treatment from base.css - only the chrome a button brings by default
   has to go, or every legend row would look like a control to press rather than a line
   to read. */
.pie__entry--pick[b-vtv8tsq8ib] {
    min-height: var(--layout-touch-target-min);
    border-color: transparent;
    border-radius: var(--radius-sm);
    background-color: transparent;
    color: var(--color-text);
}

.pie__entry--pick:hover:not(:disabled)[b-vtv8tsq8ib] {
    border-color: transparent;
}

.pie__swatch[b-vtv8tsq8ib] {
    width: var(--space-3);
    height: var(--space-3);
    border-radius: var(--radius-sm);
    background-color: var(--chart-colour);
}

.pie__label[b-vtv8tsq8ib] {
    overflow: hidden;
    color: var(--color-text);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Both figures line up digit under digit, which is the only way a column of shares can be
   scanned rather than read one at a time. */
.pie__hours[b-vtv8tsq8ib],
.pie__share[b-vtv8tsq8ib] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pie__share[b-vtv8tsq8ib] {
    min-width: 4ch;
    color: var(--color-text);
    text-align: right;
}

/* On a phone the two columns become one and the pie sits above its legend, centred over
   it. Below this width a circle beside a legend leaves neither enough room: the labels
   wrap to two lines each and the pie shrinks to a badge. */
@media (max-width: 48rem) {
    .pie[b-vtv8tsq8ib] {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-4);
    }

    .pie__figure[b-vtv8tsq8ib] {
        justify-self: center;
    }
}
/* /Components/Charts/ChartUnavailable.razor.rz.scp.css */
/* Fills the space the chart would have taken, so the page does not reflow when a
   filter empties one panel. min-height rather than a fixed height: the message is
   two short lines and the charts differ in size, so this only stops the panel
   collapsing to nothing. */
.chart-unavailable[b-inokcadbs8] {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-2);
    min-height: 8rem;
    padding: var(--space-5);
    border: var(--border-width) dashed var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
    text-align: center;
}

.chart-unavailable__head[b-inokcadbs8] {
    margin: 0;
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-medium);
}

.chart-unavailable__why[b-inokcadbs8] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}
/* /Components/CompactChoice.razor.rz.scp.css */
.compact-choice[b-01f9gkzbjp] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

/* The collapsed row reads as a form value rather than as a button: the question on the left, the answer
   on the right, a chevron saying it opens. Overrides the centred inline-flex base.css gives every
   button, because a label and its value must not both drift to the middle. */
.compact-choice__summary[b-01f9gkzbjp] {
    display: grid;
    /* The question takes the slack and truncates under pressure; the answer is sized to itself and
       never is. A row where the value had been cut down to "Contra..." would be worse than useless. */
    grid-template-columns: minmax(0, 1fr) minmax(0, auto) auto;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-input);
    text-align: left;
}

.compact-choice__label[b-01f9gkzbjp] {
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-medium);

    /* A long question is trimmed rather than allowed to push the answer off a 320px screen. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.compact-choice__required[b-01f9gkzbjp] {
    margin-left: var(--space-1);
    color: var(--color-danger-text);
}

/* The answer, and the loudest thing on the row - it is the only part the reader is checking when they
   scan a filled-in form. Right-aligned so a column of these lines up down the form. */
.compact-choice__value[b-01f9gkzbjp] {
    min-width: 0;
    justify-self: end;
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Nothing chosen yet on a question that has to be answered. Three marks, and only one of them is a
   colour: the word "Choose" where a value would be, the asterisk beside the label, and this border. */
.compact-choice--unanswered .compact-choice__summary[b-01f9gkzbjp],
.compact-choice--unanswered .compact-choice__options[b-01f9gkzbjp] {
    border-color: var(--color-warning);
}

.compact-choice--unanswered .compact-choice__value[b-01f9gkzbjp] {
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
}

/* THE OTHER SHAPE, AND IT IS THE LAYOUT'S TO CHOOSE. Hidden here, shown by a caller with a pane wide
   enough to hold every option at once - which then hides the row above and leaves this as the field's
   label. Both are always in the markup so that a stylesheet can decide; see JobPanel.razor.css. */
.compact-choice__asked[b-01f9gkzbjp] {
    display: none;
    font-weight: var(--font-weight-medium);
}

.compact-choice__chevron[b-01f9gkzbjp] {
    display: flex;
    align-items: center;
    color: var(--color-text-muted);
}

/* The list, inset so it reads as belonging to the row above rather than as the next field. Always in
   the markup and hidden until the row is opened - which is what lets aria-controls name a region that
   is always on the page, and what lets a wide layout show it without any state changing. */
.compact-choice__options[b-01f9gkzbjp] {
    display: none;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.compact-choice__options--open[b-01f9gkzbjp] {
    display: flex;
}

.compact-choice__hint[b-01f9gkzbjp] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}
/* /Components/Dialog.razor.rz.scp.css */
/* The dialog element itself is the backdrop's anchor. It carries no padding or border of its own so
   the panel inside can own the whole shape - a <dialog> has a browser default border in some engines
   that would otherwise draw a second edge. */
.dialog[b-nekjmyqltp] {
    max-width: min(42rem, calc(100vw - var(--space-6)));
    max-height: calc(100dvh - var(--space-6));
    width: 100%;
    padding: 0;
    border: 0;
    border-radius: var(--radius-xl);
    background-color: transparent;
    overflow: visible;
}

.dialog[b-nekjmyqltp]::backdrop {
    background-color: var(--color-overlay);
}

/* On a phone the dialog goes to the bottom and fills the width - a sheet rather than a centred box.
   A centred dialog on a 320px screen is a small screen inside a small screen, and its top edge is
   the hardest part of the display for a thumb to reach. */
@media (max-width: 48rem) {
    .dialog[b-nekjmyqltp] {
        max-width: 100vw;
        width: 100vw;
        margin: auto auto 0;
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;

        /* Never taller than the viewport minus the notch, so the close button stays reachable. */
        max-height: calc(100dvh - var(--layout-safe-top) - var(--space-6));
    }
}

.dialog__panel[b-nekjmyqltp] {
    display: flex;
    flex-direction: column;
    max-height: inherit;
    border: var(--border-width) solid var(--color-border);
    border-radius: inherit;
    background-color: var(--color-surface-overlay);
    box-shadow: var(--shadow-xl);
    overflow: hidden;
}

/* Sticky, so scrolling a long day's crew list never scrolls the close button off. */
.dialog__header[b-nekjmyqltp] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-5);
    border-bottom: var(--border-width) solid var(--color-border);
    background-color: var(--color-surface-overlay);
}

.dialog__heading[b-nekjmyqltp] {
    min-width: 0;
}

.dialog__title[b-nekjmyqltp] {
    margin: 0;
    font-size: var(--font-size-xl);
    overflow-wrap: anywhere;
}

.dialog__subtitle[b-nekjmyqltp] {
    margin: var(--space-1) 0 0;
    color: var(--color-text-secondary);
}

.dialog__close[b-nekjmyqltp] {
    flex-shrink: 0;
}

.dialog__body[b-nekjmyqltp] {
    padding: var(--space-5);
    overflow-y: auto;

    /* Same reason as the drawer: reaching the bottom of a long crew list must not
       start scrolling the calendar behind the dialog. */
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

.dialog__footer[b-nekjmyqltp] {
    padding: var(--space-4) var(--space-5);
    border-top: var(--border-width) solid var(--color-border);
    background-color: var(--color-surface-inset);

    /* Clears the home indicator on a phone, where the sheet sits against the bottom edge. */
    padding-bottom: calc(var(--space-4) + var(--layout-safe-bottom));
}
/* /Components/FormField.razor.rz.scp.css */
/* A field is a vertical stack: label, hint, control, message. Spacing lives here
   rather than as margins on inputs, so every form in the application lines up
   without each one restating it. */
.field[b-qxp940v392] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

/* base.css already gives <label> a bottom margin for standalone use; inside this
   stack the gap owns the spacing. */
.field label[b-qxp940v392] {
    margin-bottom: 0;
}

.field__required[b-qxp940v392] {
    margin-left: var(--space-1);
    color: var(--color-danger-text);
}

.field__hint[b-qxp940v392] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* ::deep: the control is the caller's markup and never carries this file's scope
   attribute (see NavMenu.razor.css). Inputs are full-width inside a field, which is
   the only sane default at phone width. */
.field[b-qxp940v392]  input,
.field[b-qxp940v392]  select,
.field[b-qxp940v392]  textarea {
    width: 100%;
}

.field[b-qxp940v392]  input[type="checkbox"],
.field[b-qxp940v392]  input[type="radio"] {
    width: auto;
}
/* /Components/InlineConfirm.razor.rz.scp.css */
.inline-confirm[b-ntzm9l5yqt] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.inline-confirm--danger[b-ntzm9l5yqt] {
    border-color: var(--color-danger);
    background-color: var(--color-danger-subtle);
}

.inline-confirm__message[b-ntzm9l5yqt] {
    /* Long enough to say what will happen, short enough to stay readable. */
    max-width: 42rem;
    min-width: min(18rem, 100%);
    flex: 1 1 20rem;
}

/* ::deep - the message is the caller's markup, which does not carry this file's
   scope attribute (see NavMenu.razor.css). */
.inline-confirm__message[b-ntzm9l5yqt]  p:last-child {
    margin-bottom: 0;
}

.inline-confirm__actions[b-ntzm9l5yqt] {
    flex: 0 0 auto;
}
/* /Components/InlinePanel.razor.rz.scp.css */
.inline-panel[b-dlw3399iol] {
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    box-shadow: var(--shadow-container);
}

/* The panel is focused when it opens; that is orientation, not an error, so it
   should not also draw the keyboard focus ring around the whole box. */
.inline-panel:focus[b-dlw3399iol] {
    outline: none;
    box-shadow: var(--shadow-container);
}

.inline-panel__header[b-dlw3399iol] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}

.inline-panel__title[b-dlw3399iol] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.inline-panel__close[b-dlw3399iol] {
    width: var(--layout-touch-target-min);
    min-width: var(--layout-touch-target-min);
    padding: 0;
    /* Pulled into the panel's own padding so the icon lines up with the edge of the
       text rather than sitting a whole gap short of it. */
    margin: calc(var(--space-2) * -1) calc(var(--space-2) * -1) 0 0;
}

.inline-panel__description[b-dlw3399iol] {
    margin: var(--space-2) 0 0;
    max-width: 46rem;
    color: var(--color-text-secondary);
}

.inline-panel__body[b-dlw3399iol] {
    margin-top: var(--space-4);
}

@media (max-width: 48rem) {
    .inline-panel[b-dlw3399iol] {
        padding: var(--space-4);
    }
}
/* /Components/LoadingIndicator.razor.rz.scp.css */
.loading[b-kj0isn1mag] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-5) 0;
    color: var(--color-text-muted);
}

.loading__spinner[b-kj0isn1mag] {
    width: var(--space-5);
    height: var(--space-5);
    border: 2px solid var(--color-border-strong);
    border-top-color: var(--color-primary);
    border-radius: var(--radius-full);
    animation: loading-spin-b-kj0isn1mag 900ms linear infinite;
}

@keyframes loading-spin-b-kj0isn1mag {
    to { transform: rotate(360deg); }
}
/* /Components/Notice.razor.rz.scp.css */
/* Colour comes from the status token trio: the -subtle background carries the
   -text tone, which is the pairing measured to clear AA in both themes. Never the
   fill token (--color-danger and friends) for text. */
.notice[b-6jnj0miw39] {
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-inset);
    color: var(--color-text);
}

.notice--info[b-6jnj0miw39] {
    background-color: var(--color-info-subtle);
    border-color: var(--color-info);
}

.notice--success[b-6jnj0miw39] {
    background-color: var(--color-success-subtle);
    border-color: var(--color-success);
}

.notice--warning[b-6jnj0miw39] {
    background-color: var(--color-warning-subtle);
    border-color: var(--color-warning);
}

.notice--danger[b-6jnj0miw39] {
    background-color: var(--color-danger-subtle);
    border-color: var(--color-danger);
}

.notice__title[b-6jnj0miw39] {
    margin: 0 0 var(--space-1);
    font-weight: var(--font-weight-semibold);
}

.notice__body[b-6jnj0miw39] {
    max-width: 46rem;
}

/* ::deep because the body is the caller's markup, which never carries this file's
   scope attribute - see the explanation at the top of NavMenu.razor.css. Without
   it the trailing margin on the last paragraph would leave a gap inside the box. */
.notice__body[b-6jnj0miw39]  p:last-child {
    margin-bottom: 0;
}

.notice__body[b-6jnj0miw39]  ul {
    margin: 0;
    padding-left: var(--space-5);
}

.notice__actions[b-6jnj0miw39] {
    margin-top: var(--space-3);
}
/* /Components/PageHeader.razor.rz.scp.css */
.page-header[b-8j95ek63gq] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-width) solid var(--color-border);
}

.page-header__text[b-8j95ek63gq] {
    min-width: 0;
}

.page-header__subtitle[b-8j95ek63gq] {
    margin: 0;
    color: var(--color-text-muted);
}

.page-header__actions[b-8j95ek63gq] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
/* /Components/Pager.razor.rz.scp.css */
.pager[b-xapq2unnpv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.pager__summary[b-xapq2unnpv] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.pager__position[b-xapq2unnpv] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}
/* /Components/RecordTable.razor.rz.scp.css */
/* The table pattern itself lives in base.css (.data-table); this file only adds
   what a list screen needs around it. */

.record-table[b-pb32658fig] {
    min-width: 0;
}

/* Fetching the next page or the next search dims the rows instead of removing
   them, so the list keeps its place while the connection catches up. */
.record-table table[aria-busy="true"][b-pb32658fig] {
    opacity: 0.6;
    transition: opacity var(--motion-duration-base) var(--motion-easing-standard);
}

/* An expanded panel belongs to the row above it, so it shares that row's inset
   background instead of reading as another record. */
.record-table__detail > td[b-pb32658fig] {
    padding: 0 var(--space-3) var(--space-4);
    background-color: var(--color-surface-inset);
}

@media (max-width: 48rem) {
    /* Below the breakpoint every row is its own card, which would make an expanded
       panel look like a second, unrelated record. These four rules fuse the two
       cards into one: the detail is pulled up against the row above, loses its own
       top edge, and the two share a single outline.

       :has() is what lets the row above drop its bottom corners. It is unsupported
       only in browsers this application does not target, and where it is missing
       the seam simply shows - untidy rather than broken. app.css already relies on
       it the same way. */
    .record-table__detail[b-pb32658fig] {
        margin-top: calc(var(--space-4) * -1);
        border-top: 0;
        border-top-left-radius: 0;
        border-top-right-radius: 0;
    }

    .data-table tr:has(+ .record-table__detail)[b-pb32658fig] {
        margin-bottom: 0;
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }

    .record-table__detail > td[b-pb32658fig] {
        padding: var(--space-2) 0 var(--space-3);
        border-bottom: 0;
        background-color: transparent;
    }
}
/* /Components/RichTextEditor.razor.rz.scp.css */
/* The field reads as one control - toolbar and typing area inside a single border - rather than as a
   row of buttons that happen to sit above a box. */
.rich-text[b-kj5xiz3qz0] {
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-input);
    overflow: hidden;
}

/* The focus ring belongs to the whole control, because the thing that takes focus is the editable
   area inside it and a ring drawn around only that would sit inside the border. :focus-within is what
   moves it out to the edge. */
.rich-text:focus-within[b-kj5xiz3qz0] {
    box-shadow: var(--shadow-focus);
}

.rich-text:hover:not(.rich-text--disabled)[b-kj5xiz3qz0] {
    border-color: var(--color-text-muted);
}

.rich-text--disabled[b-kj5xiz3qz0] {
    background-color: var(--color-surface-inset);
    opacity: 0.7;
}

.rich-text__toolbar[b-kj5xiz3qz0] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    padding: var(--space-1);
    border-bottom: var(--border-width) solid var(--color-border-muted);
    background-color: var(--color-surface-inset);
}

/* Overrides the global button minimum: these five sit in a row above a text field, and a 2.75rem
   toolbar on a phone would take a quarter of the visible form. They stay comfortably tappable at
   2.25rem because they are square rather than the usual wide-and-short. */
.rich-text__button[b-kj5xiz3qz0] {
    min-height: 2.25rem;
    min-width: 2.25rem;
    padding: 0;
    border-color: transparent;
    background-color: transparent;
    color: var(--color-text-secondary);
}

.rich-text__button--on[b-kj5xiz3qz0] {
    background-color: var(--color-state-selected);
    border-color: var(--color-border);
    color: var(--color-text);
}

.rich-text__glyph[b-kj5xiz3qz0] {
    font-size: var(--font-size-sm);
    line-height: 1;
}

/* The three letter marks carry their own meaning, so each is drawn the way it names. */
.rich-text__glyph--bold[b-kj5xiz3qz0] {
    font-weight: var(--font-weight-bold);
}

.rich-text__glyph--italic[b-kj5xiz3qz0] {
    font-style: italic;
}

.rich-text__glyph--underline[b-kj5xiz3qz0] {
    text-decoration: underline;
}

/* The two list marks are characters rather than letters and need no emphasis; they only need to sit
   on the same optical line as the other three. */
.rich-text__glyph--bullets[b-kj5xiz3qz0],
.rich-text__glyph--numbers[b-kj5xiz3qz0] {
    letter-spacing: -0.05em;
}

.rich-text__input[b-kj5xiz3qz0] {
    min-height: 6rem;
    max-height: 22rem;
    overflow-y: auto;
    padding: var(--space-3);
    line-height: var(--line-height-base);

    /* A long tag or pasted URL must wrap rather than widen the panel it sits in. */
    overflow-wrap: break-word;
}

/* =============================================================================
   THE TALL VARIANT
   -----------------------------------------------------------------------------
   For the one field on a screen that is asking for a paragraph rather than a
   line. The size of a box is the clearest thing a form says about how much it
   expects, and six lines says "a sentence will do" - which is what the daily
   report's description was getting.

   A modifier here rather than a height on the caller's side, because the height
   belongs to the editable region inside this component and the class the caller
   passes lands on the wrapper. Still capped by the max-height above, so a long
   description scrolls inside the field instead of pushing the form's buttons off
   the bottom of a phone.

   THE ELEVEN REMS ARE A FALLBACK, NOT A CEILING. --rich-text-min-height is a
   seam: a caller that knows better - because it has measured its own container
   rather than the window - sets that property on any ancestor and this uses it.
   The modifier is what makes the field tall by default; the property is what
   lets the daily report's two-pane layout make it taller still, from inside the
   container query that knows the pane is wide enough to deserve it.
   ============================================================================= */

.rich-text--tall .rich-text__input[b-kj5xiz3qz0] {
    min-height: var(--rich-text-min-height, 11rem);
}

.rich-text__input:focus-visible[b-kj5xiz3qz0] {
    /* The ring is on the container. A second one here would draw two. */
    outline: none;
    box-shadow: none;
}

/* Driven by a class rather than :empty, because a contenteditable region keeps a stray line break
   after the last character is deleted and :empty would stop matching while the field looked blank. */
.rich-text__input--empty[b-kj5xiz3qz0]::before {
    content: attr(data-placeholder);
    color: var(--color-text-muted);

    /* So the caret sits at the start of the line rather than after the placeholder text, and so a
       click anywhere in the field reaches the editable area rather than this pseudo-element. */
    pointer-events: none;
    display: block;
}

/* The editable area renders the same eight tags the server keeps. Margins are tightened from the
   document defaults: this is a field inside a form, not a page of prose, and a paragraph's default
   1em bottom margin leaves a gap that reads as an empty line. */
.rich-text__input > :first-child[b-kj5xiz3qz0] {
    margin-top: 0;
}

.rich-text__input > :last-child[b-kj5xiz3qz0] {
    margin-bottom: 0;
}

.rich-text__input p[b-kj5xiz3qz0] {
    margin: 0 0 var(--space-2);
}

.rich-text__input ul[b-kj5xiz3qz0],
.rich-text__input ol[b-kj5xiz3qz0] {
    margin: 0 0 var(--space-2);
    padding-left: var(--space-5);
}

.rich-text__input li[b-kj5xiz3qz0] {
    margin-bottom: var(--space-1);
}
/* /Components/RichTextView.razor.rz.scp.css */
/* Matches the editor's rhythm, so text does not shift when a job moves between being edited and being
   read. Same reasoning: this is a paragraph inside a card, not a page of prose, and the document
   default bottom margin reads as a blank line. */
.rich-text-view[b-5928s0pkvw] {
    color: var(--color-text-secondary);
    overflow-wrap: break-word;
}

.rich-text-view > :first-child[b-5928s0pkvw] {
    margin-top: 0;
}

.rich-text-view > :last-child[b-5928s0pkvw] {
    margin-bottom: 0;
}

.rich-text-view p[b-5928s0pkvw] {
    margin: 0 0 var(--space-2);
}

.rich-text-view ul[b-5928s0pkvw],
.rich-text-view ol[b-5928s0pkvw] {
    margin: 0 0 var(--space-2);
    padding-left: var(--space-5);
}

.rich-text-view li[b-5928s0pkvw] {
    margin-bottom: var(--space-1);
}
/* /Components/SearchBox.razor.rz.scp.css */
.search-box[b-4834zvsgrk] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    /* Wide enough for a full name, and allowed to shrink on a phone. */
    flex: 1 1 min(22rem, 100%);

    /* FLEX-BASIS IS A WIDTH IN A ROW AND A HEIGHT IN A COLUMN, and this control is used in both.
       In a filter strip it sits in a horizontal .cluster, where the 22rem above is the intended
       width. Inside the place picker's panel it does not: that panel is flex-direction: column, so
       the same declaration asked for twenty-two rems of HEIGHT and put a screenful of nothing
       between the search box and the list of places underneath it.

       max-width cannot clamp that; it is the cross axis there. max-content on the main axis can, and
       it is inert in a row, where the main size is already decided by the basis above. The exact
       same fix, for the exact same reason, is written out in SegmentedChoice.razor.css. */
    max-height: max-content;
}

.search-box label[b-4834zvsgrk] {
    margin-bottom: 0;
}

.search-box__hint[b-4834zvsgrk] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.search-box__control[b-4834zvsgrk] {
    position: relative;
    display: flex;
    align-items: center;
}

/* The icon sits inside the field, so padding on the input reserves room for it
   rather than the icon overlapping typed text.

   ::deep because AppIcon renders the <svg> itself, and CSS isolation never stamps
   this file's scope attribute onto another component's markup - see the note at the
   top of NavMenu.razor.css. .search-box__control IS in this file's markup, so it
   keeps the attribute and the descendant selector matches. */
.search-box__control[b-4834zvsgrk]  .search-box__icon {
    position: absolute;
    left: var(--space-3);
    color: var(--color-text-muted);
    pointer-events: none;
}

.search-box__input[b-4834zvsgrk] {
    width: 100%;
    padding-left: calc(var(--space-3) + 1.25rem + var(--space-2));
    padding-right: var(--layout-touch-target-min);
}

/* Safari draws its own clear affordance on type="search" and it is neither
   themeable nor big enough to hit with a glove. Ours replaces it. */
.search-box__input[b-4834zvsgrk]::-webkit-search-decoration,
.search-box__input[b-4834zvsgrk]::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.search-box__clear[b-4834zvsgrk] {
    position: absolute;
    right: 0;
    width: var(--layout-touch-target-min);
    min-width: var(--layout-touch-target-min);
    padding: 0;
}
/* /Components/SegmentedChoice.razor.rz.scp.css */
.segmented-choice[b-09kj02swtv] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);

    /* Grows to fill the row it is in, because the grid below needs a definite width
       before it can decide how many columns fit - left to size itself to its own
       content it would never wrap, and four labels would run off a phone.

       The cap is by option count rather than a fixed value: eleven rem a choice is
       comfortable for the longest label any of these carry, and it stops a
       two-option control stretching as wide as a four-option one. */
    flex: 1 1 18rem;
    min-width: 0;
    max-width: calc(var(--segment-count, 4) * 11rem);

    /* FLEX-BASIS IS A WIDTH IN A ROW AND A HEIGHT IN A COLUMN, and this control is
       used in both. Seven of its call sites sit in a horizontal .cluster, where the
       18rem above is the intended width. Inside a FormField it does not: .field is
       flex-direction: column, so the same declaration asked for eighteen rems of
       HEIGHT and the cost-type picker stood 288px tall around a 148px button grid -
       read as a large empty gap under the labels on the daily report form.

       max-width cannot clamp that; it is the cross axis there. max-content on the
       main axis can, and it is inert in a row, where the main size is already
       decided by flex-basis and the cap above. */
    max-height: max-content;
}

.segmented-choice__label[b-09kj02swtv] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* EQUAL COLUMNS, AND EVERY LABEL ON ONE LINE.
   -----------------------------------------------------------------------------
   This was a flex row of buttons sized to their own text, joined by shared
   borders. It read badly the moment the labels differed in length: "All" and
   "Approved" sat on one line while "Not submitted" and "Sent back" wrapped to
   two, so four controls that do the same job looked like four different sizes.

   A grid of equal columns fixes both halves of that. auto-fit with a floor of
   8rem means four options sit in one row wherever there is room and fall to two
   rows of two on a phone - every cell the same width, every label on one line,
   and all four still visible. Wrapping into a tidy 2x2 is the point: the reader
   liked having the choices in front of them, so hiding two behind a scroll would
   have solved the wrong problem.

   The joined look went with it, deliberately. Shared borders cannot survive a
   wrap - the seam between two cells is the first cell's right edge, and CSS has
   no way to ask "is this the first in its row". Separated pills with one gap
   read as one control anyway, because the shared label above them says so. */
.segmented-choice__options[b-09kj02swtv] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(8rem, 100%), 1fr));
    gap: var(--space-2);
}

/* Stays the inline-flex base.css gives every button, so the label keeps its
   centring and its minimum touch height. Only the width behaviour changes. */
.segmented-choice__option[b-09kj02swtv] {
    /* Zero minimum, or a long label widens its own column and breaks the equal
       split the whole arrangement depends on. */
    min-width: 0;
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
    color: var(--color-text-secondary);
}

/* WRAPS RATHER THAN TRIMS, WHICH IS THE OPPOSITE OF WHAT THIS SAID.
   -----------------------------------------------------------------------------
   It used to trim to an ellipsis, on the argument that a ragged column of one-
   and two-line buttons was exactly what the grid replaced. The argument outlived
   the layout it was written for. When these were a flex row, a wrapped label
   made its own button taller than its neighbours and the row really did go
   ragged. They are grid cells now, and cells in a row stretch to the tallest of
   them - so a wrapped label costs the row a line and leaves it level.

   What the trim cost was the labels themselves: "Contractor c...", "Support
   sub-..." and "Commissioni..." all reached the reader cut off, in a picker
   whose entire job is to be read at a glance. A title attribute is no answer on
   a phone, which is the device this form is built for and which has no hover.

   balance keeps a two-line label from breaking as eight words and one; the
   fallback for browsers without it is the ordinary break, which is what this
   did before. */
.segmented-choice__text[b-09kj02swtv] {
    min-width: 0;
    text-wrap: balance;

    /* A label with no space in it - a single long word - still has to yield
       rather than push its cell wider and break the equal split. */
    overflow-wrap: anywhere;
}

.segmented-choice__option--selected[b-09kj02swtv] {
    /* Filled rather than tinted. With the cells separated, a background a shade
       different from its neighbour is not enough to carry "this is the one" - the
       border and the weight have to agree with it. */
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-semibold);
}

/* base.css layers hover and press over whatever fill a button already has, so the
   selected cell needs no hover rule of its own - it darkens like every other. */
/* /Components/StatusBadge.razor.rz.scp.css */
.status-badge[b-uuzb319wig] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-full);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    /* Never wraps mid-word into two lines of one letter. */
    white-space: nowrap;
}

/* The -subtle background with the -text tone is the pairing measured to clear AA
   in both themes; the bare fill token would not. */
.status-badge--info[b-uuzb319wig] {
    background-color: var(--color-info-subtle);
    border-color: var(--color-info);
    color: var(--color-info-text);
}

.status-badge--success[b-uuzb319wig] {
    background-color: var(--color-success-subtle);
    border-color: var(--color-success);
    color: var(--color-success-text);
}

.status-badge--warning[b-uuzb319wig] {
    background-color: var(--color-warning-subtle);
    border-color: var(--color-warning);
    color: var(--color-warning-text);
}

.status-badge--danger[b-uuzb319wig] {
    background-color: var(--color-danger-subtle);
    border-color: var(--color-danger);
    color: var(--color-danger-text);
}
/* /Components/ThemeToggle.razor.rz.scp.css */
.theme-toggle[b-b1hev5pmmu] {
    /* Square, so the icon sits centred at the minimum touch target rather than in
       a wide pill that steals width from the account name beside it. */
    width: var(--layout-touch-target-min);
    min-width: var(--layout-touch-target-min);
    padding: 0;
    border-radius: var(--radius-full);
}

.theme-toggle__icon[b-b1hev5pmmu] {
    width: 1.25rem;
    height: 1.25rem;
    /* currentColor, so the icon inherits the button's hover and focus states
       instead of needing its own. */
    stroke: currentColor;
    fill: none;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* /Features/Admin/Companies/CompanyChain.razor.rz.scp.css */
/* Every element the chain draws is written in this component, so no ::deep is
   needed - the one child component it renders (PermissionView) draws nothing of
   its own. */

.chain__list[b-zak7ngf9ao] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Indentation is what makes "engaged by" visible, and it is applied by the nested
   list rather than by depth-specific classes - a contract chain has no fixed
   depth, and depth classes would cap it in CSS. */
.chain__list .chain__list[b-zak7ngf9ao] {
    margin-top: var(--space-1);
    padding-inline-start: var(--space-4);
    /* A guide line down each branch, so a deep chain stays followable. */
    border-inline-start: var(--border-width) solid var(--color-border);
}

.chain__row[b-zak7ngf9ao] {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    min-height: 2.75rem;
}

.chain__row:hover[b-zak7ngf9ao] {
    background-color: var(--color-state-hover);
}

/* An engagement that is over is dimmed AND says "Ended" - never colour alone. */
.chain__item--past > .chain__row .chain__name[b-zak7ngf9ao] {
    color: var(--color-text-muted);
}

.chain__body[b-zak7ngf9ao] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    flex: 1 1 auto;
}

.chain__head[b-zak7ngf9ao] {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.chain__name[b-zak7ngf9ao] {
    font-weight: var(--font-weight-medium);
}

/* What they are doing here, not who they are: quiet, because the name is the
   answer and the role is the qualifier. */
.chain__role[b-zak7ngf9ao] {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* The second line: the register number, the window, and the head count. */
.chain__detail[b-zak7ngf9ao] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* Read digit by digit rather than as a word, so it takes the mono face - the same
   treatment a site code gets. */
.chain__number[b-zak7ngf9ao] {
    font-family: var(--font-family-mono);
}

.chain__muted[b-zak7ngf9ao] {
    color: var(--color-text-muted);
}

.chain__actions[b-zak7ngf9ao] {
    --cluster-gap: var(--space-1);
    margin-inline-start: auto;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.chain__panel[b-zak7ngf9ao] {
    padding-inline-start: var(--space-4);
}

@media (max-width: 48rem) {
    /* Below the breakpoint a row becomes two: the firm, then its actions, because
       four buttons and a company name do not fit on one line on a phone. */
    .chain__row[b-zak7ngf9ao] {
        flex-wrap: wrap;
    }

    .chain__actions[b-zak7ngf9ao] {
        margin-inline-start: 0;
        justify-content: flex-start;
        width: 100%;
    }
}
/* /Features/Admin/Companies/EditCompanyPanel.razor.rz.scp.css */
/* Two fields and a pair of buttons. Laid out side by side where there is room,
   because the name and the organisation number are read together - they are the
   two halves of "is this the right legal entity?". */

.edit-company__fields[b-bickz2bawu] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.edit-company__actions[b-bickz2bawu] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/Companies/EditEngagementPanel.razor.rz.scp.css */
/* The parent picker, then the two dates. The dates share a row - they are one
   answer with two halves - while the picker takes the full width, because a path
   like "Havbruk / Nordic Bygg / Nordvik" needs it. */

.edit-engagement__fields[b-irrybvp0ie] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.edit-engagement__dates[b-irrybvp0ie] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.edit-engagement__note[b-irrybvp0ie] {
    color: var(--color-text-secondary);
    margin: 0;
}

.edit-engagement__actions[b-irrybvp0ie] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/Companies/EngageCompanyPanel.razor.rz.scp.css */
/* Three questions, asked in order: which firm, doing what, for how long. Each is a
   <fieldset> so the grouping is real to a screen reader and not only visual. */

.engage__fields[b-pdm0cenum0] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.engage__group[b-pdm0cenum0] {
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    /* A fieldset carries a default min-width that stops its contents shrinking,
       which makes the panel push the page sideways on a phone. */
    min-width: 0;
}

.engage__group > legend[b-pdm0cenum0] {
    font-weight: var(--font-weight-semibold);
    padding-inline: var(--space-2);
}

.engage__note[b-pdm0cenum0] {
    color: var(--color-text-secondary);
    margin: 0;
}

/* ---------------------------------------------------------------- which firm */

.engage__chosen[b-pdm0cenum0] {
    --cluster-gap: var(--space-3);
    align-items: baseline;
}

.engage__chosen-name[b-pdm0cenum0] {
    font-weight: var(--font-weight-medium);
}

.engage__chosen-number[b-pdm0cenum0] {
    font-family: var(--font-family-mono);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.engage__matches[b-pdm0cenum0] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* A whole row is the target, not a link inside it: this is used on a phone,
   outdoors, by someone wearing gloves. */
.engage__match[b-pdm0cenum0] {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    align-items: flex-start;
    text-align: start;
    background: none;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    color: inherit;
}

.engage__match:hover:enabled[b-pdm0cenum0] {
    background-color: var(--color-state-hover);
}

.engage__match:active:enabled[b-pdm0cenum0] {
    background-color: var(--color-state-pressed);
}

/* A match that cannot be chosen - already on this site, or deactivated - is still
   shown, because seeing it is what stops the firm being entered a second time. The
   row says which of the two it is; this only stops it looking clickable. */
.engage__match:disabled[b-pdm0cenum0] {
    cursor: not-allowed;
    opacity: 0.65;
}

.engage__match-name[b-pdm0cenum0] {
    font-weight: var(--font-weight-medium);
}

.engage__match-detail[b-pdm0cenum0] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.engage__match-detail > span:first-child[b-pdm0cenum0] {
    font-family: var(--font-family-mono);
}

/* Set apart from the matches above it, so "add it as new" reads as the other
   ending of the flow rather than as one more match. */
.engage__new[b-pdm0cenum0] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    border-top: var(--border-width) solid var(--color-border);
    padding-top: var(--space-3);
}

.engage__new-fields[b-pdm0cenum0] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

/* ---------------------------------------------------------------- doing what */

.engage__roles[b-pdm0cenum0] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The label is the whole card, so the description is part of what the reader
   clicks - the choice and its explanation are one thing. */
.engage__role[b-pdm0cenum0] {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    cursor: pointer;
}

.engage__role:hover[b-pdm0cenum0] {
    background-color: var(--color-state-hover);
}

.engage__role--chosen[b-pdm0cenum0] {
    border-color: var(--color-primary);
    background-color: var(--color-surface-inset);
}

.engage__role-body[b-pdm0cenum0] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.engage__role-name[b-pdm0cenum0] {
    font-weight: var(--font-weight-semibold);
}

.engage__role-description[b-pdm0cenum0] {
    color: var(--color-text-secondary);
}

/* ---------------------------------------------------------------- for how long */

.engage__dates[b-pdm0cenum0] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.engage__actions[b-pdm0cenum0] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/Pages/AdminOverview.razor.rz.scp.css */
.admin__site[b-hbe4zosjks] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.admin__site-text[b-hbe4zosjks] {
    min-width: 0;
}

.admin__site-name[b-hbe4zosjks] {
    margin: 0;
    font-size: var(--font-size-lg);
    overflow-wrap: anywhere;
}

.admin__site-state[b-hbe4zosjks] {
    margin: var(--space-1) 0 0;
    color: var(--color-text-secondary);
}

/* The sequence. A numbered list with its own markers suppressed, because the marker carries state -
   a tick when done, the number otherwise - and a browser's own counter cannot do that. */
.setup[b-hbe4zosjks] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: none;
}

.setup__step[b-hbe4zosjks] {
    display: flex;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

/* The next thing to do gets the only accent on the screen. Exactly one step is ever in this state,
   which is what makes it a signal rather than decoration. */
.setup__step--todo[b-hbe4zosjks] {
    border-color: var(--color-accent);
    box-shadow: var(--shadow-sm);
}

/* A step that cannot be done yet recedes. It is still readable - knowing what is coming is half the
   point of showing the sequence - but it must not compete with the step that can be done. */
.setup__step--blocked[b-hbe4zosjks],
.setup__step--hidden[b-hbe4zosjks] {
    background-color: var(--color-surface-inset);
    opacity: 0.75;
}

.setup__marker[b-hbe4zosjks] {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-full);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.setup__step--done .setup__marker[b-hbe4zosjks] {
    background-color: var(--color-success-subtle);
    color: var(--color-success-text);
}

.setup__step--todo .setup__marker[b-hbe4zosjks] {
    background-color: var(--color-primary);
    color: var(--color-on-primary);
}

.setup__body[b-hbe4zosjks] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
    min-width: 0;
}

.setup__title[b-hbe4zosjks] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin: 0;
    font-size: var(--font-size-base);
}

/* The "why", and the reason this screen exists. Deliberately full-weight body text rather than a
   muted caption - it is the part a first-time reader actually needs. */
.setup__purpose[b-hbe4zosjks] {
    margin: 0;
    color: var(--color-text-secondary);
}

.setup__detail[b-hbe4zosjks] {
    margin: 0;
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-sm);
}

.setup__blocked[b-hbe4zosjks] {
    margin: 0;
    color: var(--color-warning-text);
    font-size: var(--font-size-sm);
}

.setup__hidden[b-hbe4zosjks] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* A link by default: most steps are already done and re-opening one is a navigation, not an action.
   The step that is next gets the button treatment instead. */
.setup__action[b-hbe4zosjks] {
    font-weight: var(--font-weight-medium);
}

.setup__action--next[b-hbe4zosjks] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-5);
    border: var(--border-width) solid var(--color-primary);
    border-radius: var(--radius-md);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    text-decoration: none;
}

.setup__action--next:hover[b-hbe4zosjks],
.setup__action--next:focus-visible[b-hbe4zosjks] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
    color: var(--color-on-primary);
    text-decoration: none;
}

/* Separated from the sequence by a rule, so it cannot read as a fifth step. */
.admin__wide[b-hbe4zosjks] {
    padding-top: var(--space-5);
    border-top: var(--border-width) solid var(--color-border);
}

.admin__wide-heading[b-hbe4zosjks] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.admin__wide-text[b-hbe4zosjks] {
    margin: var(--space-1) 0 var(--space-4);
    color: var(--color-text-secondary);
}

.admin__wide-list[b-hbe4zosjks] {
    --grid-min: 16rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.admin__wide-list li[b-hbe4zosjks] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.admin__wide-list a[b-hbe4zosjks] {
    font-weight: var(--font-weight-semibold);
}

.admin__wide-list span[b-hbe4zosjks] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* On a phone the marker moves above the text: a 2rem circle plus a gap plus a sentence leaves too
   little for the sentence at 320px. */
@media (max-width: 30rem) {
    .setup__step[b-hbe4zosjks] {
        flex-direction: column;
        gap: var(--space-2);
        padding: var(--space-4);
    }
}
/* /Features/Admin/Pages/ApplicationAccess.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, grant panel, filters, list -
   so spacing comes from the .stack primitive in base.css rather than from margins
   on each block. Only what that primitive cannot say lives here. */

.application-access[b-6s9p6tkz37] {
    --stack-gap: var(--space-4);
}

/* Search and the Current/All filter sit on one line and wrap onto two on a phone,
   with the search box taking the room that is left. */
.application-access__filters[b-6s9p6tkz37] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that grant rather than to the table as a whole. */
.application-access__confirm[b-6s9p6tkz37] {
    --stack-gap: var(--space-3);
    padding-top: var(--space-3);
}

@media (max-width: 48rem) {
    /* Below the breakpoint the two controls are full width and stacked, because a
       half-width search box is not a search box. */
    .application-access__filters[b-6s9p6tkz37] {
        align-items: stretch;
    }
}
/* /Features/Admin/Pages/Audit.razor.rz.scp.css */
.audit__limits[b-8zpqm5hoe1] {
    margin-bottom: 0;
}

/* Wraps to one control per line on a phone rather than scrolling sideways - three filters at 320px
   would otherwise each be too narrow to read their own label. */
.audit__filters[b-8zpqm5hoe1] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4);
}

.audit__select[b-8zpqm5hoe1],
.audit__date[b-8zpqm5hoe1] {
    min-width: 12rem;
}

.audit__clear[b-8zpqm5hoe1] {
    margin-bottom: var(--space-1);
}

.audit__list[b-8zpqm5hoe1] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A left edge coloured by kind, so a column of entries is scannable by category without reading each
   one. The kind is also written in words on every row - the colour is a second channel, never the
   only one. */
.entry[b-8zpqm5hoe1] {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-1) var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-left: 3px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

@media (min-width: 48rem) {
    .entry[b-8zpqm5hoe1] {
        grid-template-columns: minmax(9rem, auto) 1fr;
        align-items: baseline;
    }
}

/* Access is the category people come here for, so it gets the strongest signal. Granting and removing
   are deliberately different colours: they are opposite acts and confusing them is the whole risk. */
.entry--access-granted[b-8zpqm5hoe1] {
    border-left-color: var(--color-success);
}

.entry--access-revoked[b-8zpqm5hoe1] {
    border-left-color: var(--color-danger);
}

.entry--report-approved[b-8zpqm5hoe1] {
    border-left-color: var(--color-success);
}

.entry--report-disputed[b-8zpqm5hoe1] {
    border-left-color: var(--color-warning);
}

.entry--report-submitted[b-8zpqm5hoe1],
.entry--role-created[b-8zpqm5hoe1],
.entry--role-changed[b-8zpqm5hoe1] {
    border-left-color: var(--color-marine-strong);
}

.entry__when[b-8zpqm5hoe1] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
}

.entry__time[b-8zpqm5hoe1] {
    color: var(--color-text-muted);
}

.entry__what[b-8zpqm5hoe1] {
    min-width: 0;
}

.entry__headline[b-8zpqm5hoe1] {
    margin: 0;
    overflow-wrap: anywhere;
}

.entry__kind[b-8zpqm5hoe1] {
    margin-right: var(--space-2);
    color: var(--color-text-secondary);
}

.entry__detail[b-8zpqm5hoe1] {
    color: var(--color-text-secondary);
}

.entry__by[b-8zpqm5hoe1] {
    margin: var(--space-1) 0 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* Italic and muted: a gap in the record rather than somebody called "nobody recorded". */
.entry__unattributed[b-8zpqm5hoe1] {
    font-style: italic;
}
/* /Features/Admin/Pages/Companies.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, panel, filters, chain - so
   spacing comes from the .stack primitive in base.css. */

.companies[b-vsnuaqyovs] {
    --stack-gap: var(--space-4);
}

.companies__filters[b-vsnuaqyovs] {
    align-items: center;
    --cluster-gap: var(--space-4);
}

.companies__count[b-vsnuaqyovs] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that engagement rather than to the chain as a whole. */
.companies__confirm[b-vsnuaqyovs] {
    --stack-gap: var(--space-3);
    padding: var(--space-3) 0;
}

/* The chain can be wide once it is several contracts deep, and a phone is narrow.
   Scrolling it inside its own box is what keeps the page body from scrolling
   sideways. */
.companies__chain[b-vsnuaqyovs] {
    overflow-x: auto;
}
/* /Features/Admin/Pages/People.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, add panel, filters, list -
   so spacing comes from the .stack primitive in base.css rather than from margins
   on each block. Only what that primitive cannot say lives here. */

.people[b-5x3ehupkad] {
    --stack-gap: var(--space-4);
}

/* Search and the Active/All filter sit on one line and wrap onto two on a phone,
   with the search box taking the room that is left. */
.people__filters[b-5x3ehupkad] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that person rather than to the table as a whole. */
.people__confirm[b-5x3ehupkad] {
    --stack-gap: var(--space-3);
    padding-top: var(--space-3);
}

@media (max-width: 48rem) {
    /* Below the breakpoint the two controls are full width and stacked, because a
       half-width search box is not a search box. */
    .people__filters[b-5x3ehupkad] {
        align-items: stretch;
    }
}
/* /Features/Admin/Pages/RolesAndPermissions.razor.rz.scp.css */
.roles__list[b-yu2bcgmzub] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.role[b-yu2bcgmzub] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    box-shadow: var(--shadow-sm);
}

/* A role that grants nothing recedes without disappearing - it still has to be findable in order to
   be switched back on. */
.role--off[b-yu2bcgmzub] {
    background-color: var(--color-surface-inset);
    opacity: 0.8;
}

.role__header[b-yu2bcgmzub] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.role__name[b-yu2bcgmzub] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin: 0;
    font-size: var(--font-size-lg);
}

/* The number that decides whether switching a role off is safe. Kept beside the name rather than in
   the confirmation alone, so it is visible before anybody reaches for the button. */
.role__held[b-yu2bcgmzub] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

.role__description[b-yu2bcgmzub] {
    margin: 0;
    color: var(--color-text-secondary);
}

.role__permissions[b-yu2bcgmzub] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
}

/* Chips rather than a comma-separated sentence: a role with twenty permissions is scannable as chips
   and unreadable as prose. Neutral-toned because a permission is a capability, not a status. */
.role__permission[b-yu2bcgmzub] {
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.role__none[b-yu2bcgmzub] {
    color: var(--color-warning-text);
    font-size: var(--font-size-sm);
}

.role__actions[b-yu2bcgmzub] {
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border-muted);
}
/* /Features/Admin/Pages/SiteAccess.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, grant panel, filters, list -
   so spacing comes from the .stack primitive in base.css rather than from margins
   on each block. Only what that primitive cannot say lives here. */

.site-access[b-du9tnw7r7x] {
    --stack-gap: var(--space-4);
}

/* Search and the Current/All filter sit on one line and wrap onto two on a phone,
   with the search box taking the room that is left. */
.site-access__filters[b-du9tnw7r7x] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that grant rather than to the table as a whole. */
.site-access__confirm[b-du9tnw7r7x] {
    --stack-gap: var(--space-3);
    padding-top: var(--space-3);
}

@media (max-width: 48rem) {
    /* Below the breakpoint the two controls are full width and stacked, because a
       half-width search box is not a search box. */
    .site-access__filters[b-du9tnw7r7x] {
        align-items: stretch;
    }
}
/* /Features/Admin/Pages/Sites.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, add panel, filters, list -
   so spacing comes from the .stack primitive in base.css rather than from margins
   on each block. */

.sites[b-ym9wfzn5zz] {
    --stack-gap: var(--space-4);
}

.sites__filters[b-ym9wfzn5zz] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that site rather than to the table as a whole. */
.sites__confirm[b-ym9wfzn5zz] {
    --stack-gap: var(--space-3);
    padding-top: var(--space-3);
}

@media (max-width: 48rem) {
    /* Below the breakpoint the two controls are full width and stacked, because a
       half-width search box is not a search box. */
    .sites__filters[b-ym9wfzn5zz] {
        align-items: stretch;
    }
}
/* /Features/Admin/Pages/WorkStructure.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, panels, filters, tree -
   so spacing comes from the .stack primitive in base.css. */

.structure[b-zeu4tsymle] {
    --stack-gap: var(--space-4);
}

.structure__filters[b-zeu4tsymle] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* Grows into whatever the two choice controls leave, and drops to its own line on a phone rather than
   squeezing to a box too narrow to read a place name in. */
.structure__search[b-zeu4tsymle] {
    flex: 1 1 14rem;
    min-width: 0;
}

/* The controls in this row line up on their bottom edges, because their labels are different heights.
   The count has no label, so it centres against them instead of sitting on the floor of the row. */
.structure__count[b-zeu4tsymle] {
    align-self: center;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* -----------------------------------------------------------------------------
   The chosen place, in the columns view
   -----------------------------------------------------------------------------
   Everything a row in the tree carries - the path, the level, and the four or
   five things that can be done to it - said once, for the one place that is
   chosen, instead of on every row of every column.
   ----------------------------------------------------------------------------- */

.structure__chosen[b-zeu4tsymle] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-inset);
}

.structure__chosen-text[b-zeu4tsymle] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.structure__chosen-path[b-zeu4tsymle] {
    font-weight: var(--font-weight-semibold);
    overflow-wrap: anywhere;
}

.structure__chosen-level[b-zeu4tsymle] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.structure__chosen-actions[b-zeu4tsymle] {
    --cluster-gap: var(--space-2);
}

/* The panel a column's action opened. Inset from the columns above it so it reads as belonging to the
   place named in the bar rather than to the view as a whole. */
.structure__panel[b-zeu4tsymle] {
    padding-inline-start: var(--space-4);
}

@media (max-width: 48rem) {
    .structure__panel[b-zeu4tsymle] {
        padding-inline-start: 0;
    }
}

/* A row's confirmation is inset from the row above it so it clearly belongs to
   that place rather than to the tree as a whole. */
.structure__confirm[b-zeu4tsymle] {
    --stack-gap: var(--space-3);
    padding: var(--space-3) 0;
}

/* The tree can be wide once it is several levels deep, and a phone is narrow.
   Scrolling it inside its own box is what keeps the page body from scrolling
   sideways. */
.structure__tree[b-zeu4tsymle] {
    overflow-x: auto;
}
/* /Features/Admin/People/AddPersonPanel.razor.rz.scp.css */
.add-person__heading[b-rhl79bvr4a] {
    margin-bottom: var(--space-1);
    font-size: var(--font-size-base);
    /* Uppercase and tracked, like a column heading: this is a section marker inside
       a panel, not a heading competing with the panel's own title. */
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.add-person__heading-hint[b-rhl79bvr4a] {
    margin: 0 0 var(--space-3);
    max-width: 46rem;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.add-person__list[b-rhl79bvr4a] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.add-person__result[b-rhl79bvr4a] {
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

/* Inside the duplicate question the rows are being read, not acted on, so they
   lose the box and become a plain list. */
.add-person__list--plain .add-person__result[b-rhl79bvr4a] {
    padding: var(--space-2) 0;
    border: 0;
    background-color: transparent;
}

.add-person__result-row[b-rhl79bvr4a] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

/* ::deep - the summary block is produced by a RenderFragment in the @code block,
   which CSS isolation treats the same as any other markup this file emits, but the
   StatusBadge inside it is another component. Keeping the whole subtree behind
   ::deep is simpler than reasoning about which half carries the attribute. */
.add-person__result-row[b-rhl79bvr4a]  .add-person__summary,
.add-person__list[b-rhl79bvr4a]  .add-person__summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: min(16rem, 100%);
    flex: 1 1 20rem;
}

.add-person__list[b-rhl79bvr4a]  .add-person__summary-name {
    margin: 0;
    font-weight: var(--font-weight-semibold);
}

.add-person__list[b-rhl79bvr4a]  .add-person__summary-detail {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    /* An e-mail address is long enough to push the badge off a phone screen. */
    overflow-wrap: anywhere;
}

.add-person__result-actions[b-rhl79bvr4a] {
    --cluster-gap: var(--space-2);
    flex: 0 0 auto;
}

.add-person__result-form[b-rhl79bvr4a] {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border);
}

.add-person__more[b-rhl79bvr4a],
.add-person__none[b-rhl79bvr4a] {
    margin: var(--space-3) 0 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.add-person__new-link[b-rhl79bvr4a] {
    margin: 0;
}

/* A link, not a button: it is a way through to another path rather than an action,
   and the primary button on this panel must stay the one that adds somebody. */
.add-person__link[b-rhl79bvr4a] {
    padding: 0;
    min-height: var(--layout-touch-target-min);
    color: var(--color-link);
    text-decoration: underline;
}

.add-person__link:hover:not(:disabled)[b-rhl79bvr4a] {
    background-image: none;
    color: var(--color-link-hover);
}

.add-person__new[b-rhl79bvr4a] {
    padding-top: var(--space-4);
    border-top: var(--border-width) solid var(--color-border);
}

.add-person__fields[b-rhl79bvr4a] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.add-person__form-actions[b-rhl79bvr4a] {
    margin-top: var(--space-4);
}

.add-person__checkbox[b-rhl79bvr4a] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.add-person__checkbox label[b-rhl79bvr4a] {
    margin-bottom: 0;
    font-weight: var(--font-weight-regular);
}

.add-person__answer[b-rhl79bvr4a] {
    margin: var(--space-3) 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.add-person__answer legend[b-rhl79bvr4a] {
    margin-bottom: var(--space-2);
}

/* Full-height rows: the label is part of the target, which is what makes a radio
   hittable with a glove. */
.add-person__choice[b-rhl79bvr4a] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--layout-touch-target-min);
}

.add-person__choice label[b-rhl79bvr4a] {
    margin-bottom: 0;
    font-weight: var(--font-weight-regular);
}
/* /Features/Admin/People/EditPersonPanel.razor.rz.scp.css */
/* Fields flow into as many columns as fit and collapse to one on a phone, using
   the .grid-auto primitive's arithmetic rather than a media query. Written out
   here rather than reusing the class because a field is narrower than a card:
   min(20rem, 100%) is what keeps two columns on a tablet and one on a phone. */
.edit-person__fields[b-pp2gds85fz] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: var(--space-4);
}

.edit-person__actions[b-pp2gds85fz] {
    margin-top: var(--space-5);
}

/* Read-only, so it is separated from the form by a rule rather than by whitespace:
   nothing below this line is editable, and that has to be visible at a glance. */
.edit-person__jobs[b-pp2gds85fz] {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: var(--border-width) solid var(--color-border);
}

.edit-person__jobs-heading[b-pp2gds85fz] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
}

.edit-person__jobs-list[b-pp2gds85fz] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Wraps rather than truncates: a company name and a job title are what tell two
   records apart, and a thumb-width column on a phone must not hide either. */
.edit-person__job[b-pp2gds85fz] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
}

.edit-person__job-company[b-pp2gds85fz] {
    font-weight: var(--font-weight-medium);
}

.edit-person__job-title[b-pp2gds85fz] {
    color: var(--color-text-secondary);
}

.edit-person__jobs-note[b-pp2gds85fz] {
    margin: var(--space-2) 0 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}
/* /Features/Admin/People/PeopleTable.razor.rz.scp.css */
/* Only what a person row needs; the table itself is styled by base.css and
   RecordTable.

   ::deep throughout, descending from .people-table: every cell is rendered by
   <RecordCell>, and CSS isolation never stamps this file's scope attribute onto
   another component's markup. .people-table is the one element written in this
   file, so it is what the attribute lands on - see the note at the top of
   NavMenu.razor.css. */

.people-table[b-w3cxza0hym]  .people-table__name {
    font-weight: var(--font-weight-medium);
    /* The name and any badge beside it sit on one line and wrap together. */
    margin-right: var(--space-2);
}

.people-table[b-w3cxza0hym]  .people-table__muted {
    color: var(--color-text-muted);
}

.people-table[b-w3cxza0hym]  .people-table__contact {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* An address is long, and secondary to the phone number - which is what somebody
   on site actually uses. */
.people-table[b-w3cxza0hym]  .people-table__email {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.people-table[b-w3cxza0hym]  .people-table__actions {
    --cluster-gap: var(--space-2);
    justify-content: flex-end;
}

@media (max-width: 48rem) {
    /* Inside a row-as-card the actions are the last thing in the card, so they read
       from the leading edge like everything above them rather than being pushed to
       the far right on their own. */
    .people-table[b-w3cxza0hym]  .people-table__actions {
        justify-content: flex-start;
    }
}
/* /Features/Admin/Roles/RolePanel.razor.rz.scp.css */
.role-panel__fields[b-tw9598offv] {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.role-panel__locked[b-tw9598offv] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.role-panel__actions[b-tw9598offv] {
    margin-top: var(--space-5);
}

.permissions[b-tw9598offv] {
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: var(--border-width) solid var(--color-border);
}

.permissions__header[b-tw9598offv] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.permissions__title[b-tw9598offv] {
    margin: 0;
}

.permissions__count[b-tw9598offv] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.permissions__group[b-tw9598offv] {
    margin: 0 0 var(--space-5);
}

.permissions__legend[b-tw9598offv] {
    margin-bottom: var(--space-2);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
}

/* The whole row is the label, so tapping anywhere on it toggles the box - which on a phone is the
   difference between a target the width of the screen and one 1.15rem wide. */
.permission[b-tw9598offv] {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    margin-bottom: 0;
    padding: var(--space-3);
    border-radius: var(--radius-md);
    font-weight: var(--font-weight-regular);
    cursor: pointer;
}

.permission:hover[b-tw9598offv] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
}

/* Nudged down onto the first line of text rather than centred against the whole block, which would
   float it beside the description on a two-line row. */
.permission input[b-tw9598offv] {
    margin-top: 0.2rem;
    flex-shrink: 0;
}

.permission__text[b-tw9598offv] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.permission__name[b-tw9598offv] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-weight: var(--font-weight-medium);
}

.permission__description[b-tw9598offv] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* The code itself, quietly. It is the verifiable detail under the prose - what actually gets stored
   and what a support conversation ends up quoting. */
.permission__code[b-tw9598offv] {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    overflow-wrap: anywhere;
}
/* /Features/Admin/SiteAccess/GrantAccessPanel.razor.rz.scp.css */
/* Three questions, asked in order: who, what, how long. Each is a <fieldset> so the
   grouping is real to a screen reader and not only visual. */

.grant-access__fields[b-sexfvyfme8] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.grant-access__group[b-sexfvyfme8] {
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    /* A fieldset carries a default min-width that stops its contents shrinking,
       which makes the panel push the page sideways on a phone. */
    min-width: 0;
}

.grant-access__group > legend[b-sexfvyfme8] {
    font-weight: var(--font-weight-semibold);
    padding-inline: var(--space-2);
}

.grant-access__note[b-sexfvyfme8] {
    color: var(--color-text-secondary);
    margin: 0;
}

/* ---------------------------------------------------------------- who */

.grant-access__chosen[b-sexfvyfme8] {
    --cluster-gap: var(--space-3);
    align-items: baseline;
}

.grant-access__chosen-name[b-sexfvyfme8] {
    font-weight: var(--font-weight-medium);
}

.grant-access__chosen-company[b-sexfvyfme8] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.grant-access__candidates[b-sexfvyfme8] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* A whole row is the target, not a link inside it: this is used on a phone, outdoors,
   by someone wearing gloves. */
.grant-access__candidate[b-sexfvyfme8] {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    align-items: flex-start;
    text-align: start;
    background: none;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    color: inherit;
}

.grant-access__candidate:hover[b-sexfvyfme8] {
    background-color: var(--color-state-hover);
}

.grant-access__candidate:active[b-sexfvyfme8] {
    background-color: var(--color-state-pressed);
}

.grant-access__candidate-name[b-sexfvyfme8] {
    font-weight: var(--font-weight-medium);
}

.grant-access__candidate-company[b-sexfvyfme8] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* ---------------------------------------------------------------- which role */

.grant-access__roles[b-sexfvyfme8] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The label is the whole card, so the description and the permission list are part
   of what the reader clicks - the choice and its explanation are one thing. */
.grant-access__role[b-sexfvyfme8] {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    cursor: pointer;
}

.grant-access__role:hover[b-sexfvyfme8] {
    background-color: var(--color-state-hover);
}

.grant-access__role--chosen[b-sexfvyfme8] {
    border-color: var(--color-primary);
    background-color: var(--color-surface-inset);
}

.grant-access__role-body[b-sexfvyfme8] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.grant-access__role-name[b-sexfvyfme8] {
    font-weight: var(--font-weight-semibold);
}

.grant-access__role-description[b-sexfvyfme8] {
    color: var(--color-text-secondary);
}

/* Collapsed by default. The description above says what the role is for; this is the
   verifiable detail for whoever wants to check it, and it is codes rather than prose
   because the descriptive catalogue is not shared with this client. */
.grant-access__role-permissions > summary[b-sexfvyfme8] {
    color: var(--color-link);
    cursor: pointer;
    font-size: var(--font-size-sm);
}

.grant-access__role-permissions > ul[b-sexfvyfme8] {
    margin: var(--space-2) 0 0;
    padding-inline-start: var(--space-4);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.grant-access__role-permissions code[b-sexfvyfme8] {
    font-family: var(--font-family-mono);
}

/* ---------------------------------------------------------------- for how long */

.grant-access__dates[b-sexfvyfme8] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.grant-access__actions[b-sexfvyfme8] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/SiteAccess/SiteAccessTable.razor.rz.scp.css */
/* Only what a grant row needs; the table itself is styled by base.css and
   RecordTable.

   ::deep throughout, descending from .site-access-table: every cell is rendered by
   <RecordCell>, and CSS isolation never stamps this file's scope attribute onto
   another component's markup. .site-access-table is the one element written in this
   file, so it is what the attribute lands on. */

.site-access-table[b-m329frnu1o]  .site-access-table__name {
    font-weight: var(--font-weight-medium);
}

.site-access-table[b-m329frnu1o]  .site-access-table__role {
    font-weight: var(--font-weight-medium);
}

.site-access-table[b-m329frnu1o]  .site-access-table__muted {
    color: var(--color-text-muted);
}

/* Two dates on their own lines: read together they are one period, and side by side
   they wrap into something that reads as two unrelated values. */
.site-access-table[b-m329frnu1o]  .site-access-table__period,
.site-access-table[b-m329frnu1o]  .site-access-table__given {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Who gave the access is the answer somebody is looking for; when they gave it is
   context for that answer. */
.site-access-table[b-m329frnu1o]  .site-access-table__given-when {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.site-access-table[b-m329frnu1o]  .site-access-table__actions {
    --cluster-gap: var(--space-2);
    justify-content: flex-end;
}

@media (max-width: 48rem) {
    /* Inside a row-as-card the actions are the last thing in the card, so they read
       from the leading edge like everything above them. */
    .site-access-table[b-m329frnu1o]  .site-access-table__actions {
        justify-content: flex-start;
    }
}
/* /Features/Admin/Sites/AddSitePanel.razor.rz.scp.css */
.add-site__fields[b-w63bsltso7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* The two planned dates belong together and wrap onto separate lines on a phone. */
.add-site__dates[b-w63bsltso7] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.add-site__actions[b-w63bsltso7] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/Sites/EditSitePanel.razor.rz.scp.css */
.edit-site__fields[b-a1753cosmp] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.edit-site__dates[b-a1753cosmp] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.edit-site__actions[b-a1753cosmp] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}

/* The code section is separated by a rule rather than merely by spacing: it is a
   different kind of act from the form above it, and the boundary should be visible
   before somebody starts typing in it. */
.edit-site__code[b-a1753cosmp] {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: var(--border-width) solid var(--color-border);
}

.edit-site__code-heading[b-a1753cosmp] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-base);
}

.edit-site__code-note[b-a1753cosmp] {
    color: var(--color-text-secondary);
    margin: 0 0 var(--space-3);
}
/* /Features/Admin/Sites/SitesTable.razor.rz.scp.css */
/* Only what a site row needs; the table itself is styled by base.css and
   RecordTable.

   ::deep throughout, descending from .sites-table: every cell is rendered by
   <RecordCell>, and CSS isolation never stamps this file's scope attribute onto
   another component's markup. .sites-table is the one element written in this
   file, so it is what the attribute lands on. */

/* The code is the identifier people quote, so it is set in the mono face - it is
   read character by character rather than as a word. */
.sites-table[b-9esdjtdjom]  .sites-table__code {
    font-family: var(--font-family-mono);
    font-weight: var(--font-weight-medium);
}

.sites-table[b-9esdjtdjom]  .sites-table__name {
    font-weight: var(--font-weight-medium);
    display: block;
}

.sites-table[b-9esdjtdjom]  .sites-table__description {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    display: block;
    /* Two lines at most: a description can be two thousand characters and a row is
       not where anybody reads it. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.sites-table[b-9esdjtdjom]  .sites-table__muted {
    color: var(--color-text-muted);
}

/* Two dates on their own lines: read together they are one period, and side by
   side they wrap into something that reads as two unrelated values. */
.sites-table[b-9esdjtdjom]  .sites-table__planned {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.sites-table[b-9esdjtdjom]  .sites-table__actions {
    --cluster-gap: var(--space-2);
    justify-content: flex-end;
    flex-wrap: wrap;
}

@media (max-width: 48rem) {
    /* Inside a row-as-card the actions are the last thing in the card, so they read
       from the leading edge like everything above them. */
    .sites-table[b-9esdjtdjom]  .sites-table__actions {
        justify-content: flex-start;
    }
}
/* /Features/Admin/WorkStructure/LevelNamesPanel.razor.rz.scp.css */
/* One box per depth, in a column: they are read as an ordered list - level 1, then
   2, then 3 - and a grid would invite reading across. */
.level-names__fields[b-yc99wsm74k] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-width: 28rem;
}

.level-names__actions[b-yc99wsm74k] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/WorkStructure/MovePlacePanel.razor.rz.scp.css */
.move-place__fields[b-s59pzbqaf3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.move-place__actions[b-s59pzbqaf3] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/WorkStructure/PlacePanel.razor.rz.scp.css */
.place-panel__fields[b-clcm4rma7y] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* The tag and the order belong together and wrap onto separate lines on a phone. */
.place-panel__row[b-clcm4rma7y] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.place-panel__actions[b-clcm4rma7y] {
    --cluster-gap: var(--space-2);
    margin-top: var(--space-4);
}
/* /Features/Admin/WorkStructure/SiteMapEditor.razor.rz.scp.css */
/* Drawing the site.

   THE DRAWING SURFACE IS METRE SPACE, and the box around it carries the frame's own aspect ratio -
   set inline, because only the component knows what that ratio is. That equality is what lets
   preserveAspectRatio="none" distort nothing, and it is what lets a name be positioned as a plain
   percentage over the top.

   NOTHING HERE IS A PIXEL SIZE except the stroke widths, and those are non-scaling so they stay a
   hairline at every zoom. A site four hundred metres across and a pump room four metres across get
   the same handles. */

.mapedit[b-zpqtnfr7cj] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* ------------------------------------------------------------------ the bar above the drawing */

.mapedit__bar[b-zpqtnfr7cj] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

.mapedit__spacer[b-zpqtnfr7cj] {
    flex: 1 1 auto;
}

/* A segmented group: one visible control made of buttons, so which tool is live is read from the
   shape of the group rather than from four independent buttons that happen to differ. */
.mapedit__tools[b-zpqtnfr7cj] {
    display: inline-flex;
    padding: 2px;
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.mapedit__tool[b-zpqtnfr7cj] {
    padding: var(--space-2) var(--space-3);
    border: none;
    border-radius: calc(var(--radius-md) - 2px);
    background: none;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    transition: background-color var(--motion-duration-base) var(--motion-easing-standard),
                color var(--motion-duration-base) var(--motion-easing-standard);
}

.mapedit__tool:hover:not(:disabled)[b-zpqtnfr7cj] {
    color: var(--color-text);
}

.mapedit__tool:disabled[b-zpqtnfr7cj] {
    opacity: 0.45;
    cursor: not-allowed;
}

.mapedit__tool--on[b-zpqtnfr7cj] {
    background-color: var(--color-surface-container);
    color: var(--color-text);
    box-shadow: var(--shadow-sm);
}

.mapedit__target[b-zpqtnfr7cj] {
    display: inline-flex;
    gap: var(--space-2);
}

/* What the next shape becomes. Two chips rather than a dropdown, because the answer has to be
   readable without opening anything - a decoration saved onto a place looks right and is not. */
.mapedit__chip[b-zpqtnfr7cj] {
    padding: var(--space-1) var(--space-3);
    max-width: 14rem;
    overflow: hidden;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-full);
    background-color: transparent;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    white-space: nowrap;
    text-overflow: ellipsis;
    cursor: pointer;
}

.mapedit__chip--on[b-zpqtnfr7cj] {
    border-color: var(--color-primary);
    background-color: var(--color-primary-subtle);
    color: var(--color-primary-active);
    font-weight: var(--font-weight-medium);
}

.mapedit__chip:disabled[b-zpqtnfr7cj] {
    opacity: 0.5;
    cursor: not-allowed;
}

.mapedit__view[b-zpqtnfr7cj] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
}

/* Zoom. One control rather than two buttons and a stray number, so the reading belongs to the pair
   either side of it. */
.mapedit__zoom[b-zpqtnfr7cj] {
    display: inline-flex;
    align-items: center;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.mapedit__step[b-zpqtnfr7cj] {
    width: 1.9rem;
    padding: var(--space-1) 0;
    border: none;
    background: none;
    color: var(--color-text-secondary);
    font-size: var(--font-size-base);
    line-height: 1;
    cursor: pointer;
}

.mapedit__step:hover[b-zpqtnfr7cj] {
    background-color: var(--color-surface-inset);
    color: var(--color-text);
}

.mapedit__zoom-level[b-zpqtnfr7cj] {
    min-width: 2.6rem;
    padding: 0 var(--space-1);
    border-inline: var(--border-width) solid var(--color-border);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.mapedit__toggle[b-zpqtnfr7cj] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* What to do next, in one sentence, changing with the state rather than being a fixed instruction
   nobody reads twice. */
.mapedit__hint[b-zpqtnfr7cj] {
    margin: 0;
    min-height: 1.25rem;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* ------------------------------------------------------------------ the drawing and its list */

.mapedit__body[b-zpqtnfr7cj] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: var(--space-4);
    align-items: start;
}

.mapedit__board[b-zpqtnfr7cj] {
    min-width: 0;
}

/* The frame. aspect-ratio comes from the component, so the box is exactly the shape of the site and
   there is no letterboxing to correct for anywhere. */
.mapedit__canvas[b-zpqtnfr7cj] {
    position: relative;
    width: 100%;
    overflow: hidden;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

.mapedit__paper[b-zpqtnfr7cj] {
    display: block;
    width: 100%;
    height: 100%;

    /* Stops a tablet treating a press on the drawing as the start of a scroll, which swallowed the
       second click of a pair on exactly the devices this screen is most likely to be used on. */
    touch-action: none;
    cursor: crosshair;
}

.mapedit__paper:focus-visible[b-zpqtnfr7cj] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: -3px;
}

/* The grid. Faint enough to be ground rather than content: it must read as the surface a plan is
   drawn on, never as something drawn. */
.mapedit__rule-line[b-zpqtnfr7cj] {
    stroke: var(--color-border-muted);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    opacity: 0.55;
}

/* The traced photograph, held back so the shapes over it stay the subject. */
.mapedit__photo[b-zpqtnfr7cj] {
    opacity: 0.55;
}

/* EVERY SHAPE RULE BELOW NEEDS ::deep, AND THE REASON IS WORTH KNOWING because the failure is
   silent and looks like a completely different bug. The boxes and circles are rendered by
   <DrawnShape>, so they carry THAT component's scope attribute and not this file's. Without ::deep
   the selectors match nothing at all - and an SVG shape with no fill declared is not unstyled, it is
   BLACK. A plan of solid black rectangles reads as a rendering failure, not as a missing stylesheet.
   ::deep puts this file's scope on .mapedit__paper, which the shapes are inside. */

/* A place on the plan. Filled faintly rather than outlined only, so a building reads as a thing
   rather than as four lines - and still lets the photograph beneath it show through, since the
   photograph is what somebody is aiming at. */
.mapedit__paper[b-zpqtnfr7cj]  .mapedit__place {
    fill: var(--color-primary);
    fill-opacity: 0.1;
    stroke: var(--color-primary);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
}

/* Scenery, which is ground rather than plant: no fill worth the name and a dashed edge, so it can
   never be mistaken for somewhere work is booked. */
.mapedit__paper[b-zpqtnfr7cj]  .mapedit__scenery {
    fill: var(--color-text-secondary);
    fill-opacity: 0.05;
    stroke: var(--color-text-secondary);
    stroke-width: 1.25;
    stroke-dasharray: 5 4;
    vector-effect: non-scaling-stroke;
    opacity: 0.75;
}

/* Whatever is picked up. Louder in both directions, because it answers "which of these am I about
   to move", and that has to be legible against a busy photograph. */
.mapedit__paper[b-zpqtnfr7cj]  .mapedit__shape--picked {
    fill-opacity: 0.24;
    stroke: var(--color-primary-active);
    stroke-width: 3;
    stroke-dasharray: none;
    opacity: 1;
}

/* The shape between the first click and the pointer. Dashed so it reads as provisional. */
.mapedit__paper[b-zpqtnfr7cj]  .mapedit__ghost {
    fill: var(--color-primary);
    fill-opacity: 0.08;
    stroke: var(--color-primary);
    stroke-width: 2;
    stroke-dasharray: 6 4;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

/* A CORNER OF THE PICKED SHAPE. Solid rather than outlined, and in the strong primary, because it
   has to be findable over a busy photograph AND over the shape's own edge, which it sits on. */
.mapedit__handle[b-zpqtnfr7cj] {
    fill: var(--color-primary-active);
    stroke: var(--color-surface-container);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
    cursor: nwse-resize;
}

/* The calibration line. A different colour from anything that will be saved, because it will not be:
   it exists for as long as it takes to type a number. */
.mapedit__tape[b-zpqtnfr7cj] {
    stroke: var(--color-warning);
    stroke-width: 3;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

.mapedit__end[b-zpqtnfr7cj] {
    fill: var(--color-warning);
    stroke: var(--color-surface-container);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

/* NAMES AS HTML OVER THE SVG. Text inside a viewBox is scaled by it, so a name would be a headline
   across a site and illegible inside a pump room. Percentages work because the box has the frame's
   own aspect ratio. */
.mapedit__names[b-zpqtnfr7cj] {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.mapedit__name[b-zpqtnfr7cj] {
    position: absolute;
    transform: translate(-50%, -50%);
    max-width: 40%;
    overflow: hidden;
    color: var(--color-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    line-height: 1;
    white-space: nowrap;
    text-overflow: ellipsis;

    /* A halo rather than a background box: a plate behind every name would hide the drawing it is
       naming, and on a photograph a name with neither is unreadable half the time. */
    paint-order: stroke;
    -webkit-text-stroke: 3px var(--color-surface-container);
}

.mapedit__name--scenery[b-zpqtnfr7cj] {
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-regular);
    font-style: italic;
}

/* A PLACE WITH THINGS DRAWN INSIDE IT IS NAMED ON ITS OWN TOP EDGE and along its left one, the way a
   title block reads, so its whole interior stays free for the halls and tanks in it. Half a line above
   the edge and half below, rather than clear of the shape altogether: a name floating above a hall
   reads as the label of whatever is drawn there, which on a stacked plan is the hall above. The
   reports map letters the same plan with the same three anchors, so a hall placed here is found in the
   same place there. */
.mapedit__name--area[b-zpqtnfr7cj] {
    transform: translate(0, -50%);
}

/* The one case where that name leaves its own top edge: when the shape it is drawn inside already has
   its name at that height, which is what a building traced two metres outside its hall does - two
   metres on a 175 m site is two pixels, and the pair rendered as one word made of both names. Must
   stay after the rule above, which it beats by source order rather than by weight. */
.mapedit__name--stacked[b-zpqtnfr7cj] {
    transform: translate(0, calc(-50% + 1.25em));
}

.mapedit__scalebar[b-zpqtnfr7cj] {
    position: absolute;
    bottom: var(--space-2);
    left: var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    background-color: color-mix(in srgb, var(--color-surface-container) 82%, transparent);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

/* A surveyor's bar: a rule with a tick at each end, so its length is unambiguous. Drawn with borders
   on a box of a stated height rather than as a zero-height line with side borders - which is what it
   was, and a zero-height box paints nothing however many borders it is given. */
.mapedit__scalebar-line[b-zpqtnfr7cj] {
    display: block;
    height: 0.4rem;
    min-width: 1rem;
    border: 1px solid var(--color-text-secondary);
    border-top-width: 2px;
    border-bottom: none;
    box-sizing: border-box;
}

/* Loaded only to be measured. Off-screen rather than display:none, because a browser is entitled to
   skip decoding an image it will never paint. */
.mapedit__probe[b-zpqtnfr7cj] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* ------------------------------------------------------------------ what is on the plan */

.mapedit__list[b-zpqtnfr7cj] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
}

.mapedit__group[b-zpqtnfr7cj] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.mapedit__group-head[b-zpqtnfr7cj] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.mapedit__count[b-zpqtnfr7cj] {
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
}

.mapedit__empty[b-zpqtnfr7cj] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.mapedit__rows[b-zpqtnfr7cj] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: 15rem;
    overflow-y: auto;

    /* NEVER SIDEWAYS. The row carries a name, a tag, a size and two buttons in nineteen rems, and
       the moment the total exceeds that a horizontal scrollbar appears and takes the BUTTONS out of
       view - which is exactly the pair somebody is looking for. The name truncates instead; it is
       the one part of the row that can lose its tail and still be read. */
    overflow-x: hidden;
}

.mapedit__row[b-zpqtnfr7cj] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    border-radius: var(--radius-sm);
}

.mapedit__row:hover[b-zpqtnfr7cj] {
    background-color: var(--color-surface-inset);
}

.mapedit__row--picked[b-zpqtnfr7cj] {
    background-color: var(--color-primary-subtle);
}

.mapedit__row-pick[b-zpqtnfr7cj] {
    flex: 1 1 auto;
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    min-width: 0;
    padding: var(--space-1) var(--space-2);
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.mapedit__glyph[b-zpqtnfr7cj] {
    flex: none;
    color: var(--color-primary);
    font-size: 0.6em;
    line-height: 1;
}

.mapedit__row-name[b-zpqtnfr7cj] {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    font-size: var(--font-size-sm);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.mapedit__row-size[b-zpqtnfr7cj] {
    flex: none;
    white-space: nowrap;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
}

/* The delete on each row, ALWAYS VISIBLE. It used to appear only on hover, on the reasoning that a
   column of red crosses reads as a list of problems - which is true, and beside the point: a
   destructive action nobody can find is not restrained, it is missing. The report back was "I can
   only clear the whole drawing", from somebody looking straight at a per-shape delete. Quiet enough
   to recede, present enough to be seen. */
.mapedit__row-drop[b-zpqtnfr7cj] {
    /* PADDING AND MIN-HEIGHT MUST BE BEATEN, and forgetting to is why this button was invisible for
       so long. base.css gives every button a touch-target min-height and padding of two space-4s -
       right for a labelled button, fatal for a 1.75rem icon one: the content box goes to zero, and
       the global "svg { max-width: 100% }" then clamps the icon itself to nothing. The button was
       there, sized, clickable and completely blank. */
    padding: 0;
    min-height: 0;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--color-text-secondary);
    opacity: 0.55;
    cursor: pointer;
    transition: opacity var(--motion-duration-base) var(--motion-easing-standard),
                color var(--motion-duration-base) var(--motion-easing-standard);
}

.mapedit__row:hover .mapedit__row-drop[b-zpqtnfr7cj],
.mapedit__row-drop:focus-visible[b-zpqtnfr7cj] {
    opacity: 1;
}

.mapedit__row-drop:disabled[b-zpqtnfr7cj] {
    opacity: 0.25;
    cursor: not-allowed;
}

.mapedit__row-drop:hover[b-zpqtnfr7cj] {
    color: var(--color-danger);
}

/* Exact numbers for whatever is picked up. Two by two, because they are two pairs - where it is and
   how big it is - and a single column of four reads as a form rather than as a position. */
.mapedit__grid[b-zpqtnfr7cj] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
}

.mapedit__number[b-zpqtnfr7cj] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
}

.mapedit__number input[b-zpqtnfr7cj] {
    width: 100%;
    padding: var(--space-1) var(--space-2);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-input);
    color: var(--color-text);
    font: inherit;
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
}

.mapedit__tip[b-zpqtnfr7cj] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
}

.mapedit__ask[b-zpqtnfr7cj] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

/* On a narrow screen the list goes under the drawing rather than beside it. Both halves are usable
   at 320px: the board keeps its own proportions, and the rows are full width. */
@media (max-width: 60rem) {
    .mapedit__body[b-zpqtnfr7cj] {
        grid-template-columns: minmax(0, 1fr);
    }

    .mapedit__canvas[b-zpqtnfr7cj] {
        max-width: 100% !important;
    }

}

@media (max-width: 40rem) {
    .mapedit__bar[b-zpqtnfr7cj] {
        flex-direction: column;
        align-items: stretch;
    }

    .mapedit__tools[b-zpqtnfr7cj] {
        justify-content: space-between;
    }

    .mapedit__tool[b-zpqtnfr7cj] {
        flex: 1 1 0;
    }
}

/* The reference designation beside the name in the list. Somebody drawing from a CAD sheet is
   reading tags, not descriptions - "1A-FTA-01" is what is written on the drawing in their hand - so
   the list has to be searchable by eye on the same thing. */
.mapedit__row-tag[b-zpqtnfr7cj] {
    flex: none;
    max-width: 6rem;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
}

/* What re-measuring will cost, said before it happens rather than discovered afterwards. Basis-100%
   so it takes its own line above the field, where it is read rather than glanced past. */
.mapedit__warn[b-zpqtnfr7cj] {
    flex: 1 0 100%;
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* The chosen place is already on the plan, so drawing again will MOVE it. Warning-coloured rather
   than danger: moving a shape is a legitimate correction, it is only a surprise when it was not the
   place somebody meant. */
.mapedit__chip--again[b-zpqtnfr7cj] {
    border-color: var(--color-warning);
    background-color: var(--color-warning-subtle);
    color: var(--color-warning-text);
}

/* The pin beside each row. Same weight as the cross so the pair reads as one set of row controls,
   and clearly "on" when set - a pin nobody can see the state of is a pin nobody trusts. */
.mapedit__row-lock[b-zpqtnfr7cj] {
    /* PADDING AND MIN-HEIGHT MUST BE BEATEN, and forgetting to is why this button was invisible for
       so long. base.css gives every button a touch-target min-height and padding of two space-4s -
       right for a labelled button, fatal for a 1.75rem icon one: the content box goes to zero, and
       the global "svg { max-width: 100% }" then clamps the icon itself to nothing. The button was
       there, sized, clickable and completely blank. */
    padding: 0;
    min-height: 0;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--color-text-secondary);
    opacity: 0.55;
    cursor: pointer;
    transition: opacity var(--motion-duration-base) var(--motion-easing-standard),
                color var(--motion-duration-base) var(--motion-easing-standard);
}

.mapedit__row:hover .mapedit__row-lock[b-zpqtnfr7cj],
.mapedit__row-lock:focus-visible[b-zpqtnfr7cj] {
    opacity: 1;
}

/* Pinned. A filled chip rather than a change of colour alone: at twenty pixels the difference
   between a closed and an open shackle is a few pixels of stroke, and the state has to be readable
   down a column of sixty rows without comparing them to each other. */
.mapedit__row-lock--on[b-zpqtnfr7cj] {
    opacity: 1;
    background-color: var(--color-primary-subtle);
    color: var(--color-primary-active);
}

/* A pinned shape on the drawing. Solid rather than dashed and slightly stronger than an unpinned
   one: it reads as settled, which is what it is. */
.mapedit__paper[b-zpqtnfr7cj]  .mapedit__shape--pinned {
    stroke-dasharray: none;
    stroke-opacity: 1;
}

/* Remove, in the panel that belongs to whatever is picked up. The row cross is the same act; this is
   where somebody already is once they have selected something on the drawing itself. */
.mapedit__drop[b-zpqtnfr7cj] {
    align-self: flex-start;
    color: var(--color-danger);
}

/* The pin and remove pair for whatever is picked up. */
.mapedit__picked-acts[b-zpqtnfr7cj] {
    display: flex;
    gap: var(--space-3);
}
/* /Features/Admin/WorkStructure/StructureColumns.razor.rz.scp.css */
.structure-columns[b-0fwowt1mc7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* -----------------------------------------------------------------------------
   The breadcrumb
   -----------------------------------------------------------------------------
   Hidden wherever the columns themselves are visible, because a laptop already
   shows the chosen row in every column and a second copy of the same chain is
   chrome. Below the breakpoint it is the only way back.
   ----------------------------------------------------------------------------- */

.structure-columns__crumbs[b-0fwowt1mc7] {
    display: none;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
}

/* Full touch height, and no exception made for it: this is the ONLY way back up the structure once the
   columns are hidden, and it exists at exactly the widths where a thumb is the pointer. The compact
   padding and small type keep the chain from reading heavy. */
.structure-columns__crumb[b-0fwowt1mc7] {
    min-height: var(--layout-touch-target-min);
    padding: var(--space-1) var(--space-2);
    border-color: transparent;
    background-color: transparent;
    color: var(--color-link);
    font-size: var(--font-size-sm);
}

/* The crumb the reader is already at. Present rather than absent so the chain reads whole, and styled
   as text so it does not look like a control that has stopped working - but still focusable, which is
   why this is keyed off aria-current rather than off :disabled. */
.structure-columns__crumb[aria-current="true"][b-0fwowt1mc7] {
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
    cursor: default;
}

.structure-columns__crumb-separator[b-0fwowt1mc7] {
    color: var(--color-text-muted);
}

/* -----------------------------------------------------------------------------
   The columns
   -----------------------------------------------------------------------------
   Side by side, scrolling sideways inside their own box once there are more
   levels than fit. The page body must never scroll horizontally - that is the
   rule the whole application is built to, and a structure eight deep would break
   it otherwise.
   ----------------------------------------------------------------------------- */

.structure-columns__scroll[b-0fwowt1mc7] {
    display: flex;
    align-items: stretch;
    gap: var(--space-3);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;

    /* A sideways flick that reaches the end of the columns must not turn into the browser's own
       back gesture, which on a phone loses whatever the reader was in the middle of. */
    overscroll-behavior-x: contain;
    padding-bottom: var(--space-2);
}

.structure-columns__column[b-0fwowt1mc7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);

    /* Wide enough for a place name and its tag, narrow enough that three fit on a laptop. */
    flex: 0 0 16rem;
    max-height: 28rem;
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.structure-columns__head[b-0fwowt1mc7] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
}

/* The site's own word for this depth, set as a column heading rather than as a pill on every row -
   which is the saving that makes a column quieter than a branch of the tree. */
.structure-columns__title[b-0fwowt1mc7] {
    margin: 0;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.structure-columns__count[b-0fwowt1mc7] {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
}

.structure-columns__list[b-0fwowt1mc7] {
    list-style: none;
    margin: 0;
    padding: 0;

    /* The column scrolls, not the page: a zone with sixty systems in it must not make the two columns
       beside it sixty rows tall. */
    overflow-y: auto;
    overscroll-behavior: contain;
    flex: 1 1 auto;
}

.structure-columns__empty[b-0fwowt1mc7] {
    margin: 0;
    flex: 1 1 auto;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.structure-columns__place[b-0fwowt1mc7] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2);
    border-color: transparent;
    background-color: transparent;
    text-align: left;
}

.structure-columns__place--chosen[b-0fwowt1mc7] {
    background-color: var(--color-state-selected);
    border-color: var(--color-border);
}

/* A retired place is dimmed AND says "Retired" - never colour alone. */
.structure-columns__place--retired .structure-columns__place-name[b-0fwowt1mc7] {
    color: var(--color-text-muted);
}

.structure-columns__place-text[b-0fwowt1mc7] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    min-width: 0;
}

.structure-columns__place-name[b-0fwowt1mc7] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

/* A tag is read character by character rather than as a word, so it takes the mono face. */
.structure-columns__code[b-0fwowt1mc7] {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
}

/* How many places are inside, and the arrow saying the next column will show them. Absent entirely on
   a place with nothing inside, so the column reads as a list of ends and a list of ways on. */
.structure-columns__inside[b-0fwowt1mc7] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
}

.structure-columns__inside-count[b-0fwowt1mc7] {
    font-variant-numeric: tabular-nums;
}

.structure-columns__add[b-0fwowt1mc7] {
    justify-content: flex-start;
    border-top: var(--border-width) solid var(--color-border-muted);
    border-radius: 0;
    color: var(--color-link);
}

@media (max-width: 48rem) {
    .structure-columns__crumbs[b-0fwowt1mc7] {
        display: flex;
    }

    /* One column, full width, and it is the deepest one - so choosing walks forward and the breadcrumb
       walks back. Every column is still rendered; only the last is shown. */
    .structure-columns__column[b-0fwowt1mc7] {
        display: none;
        flex-basis: 100%;
        max-height: none;
    }

    .structure-columns__column:last-child[b-0fwowt1mc7] {
        display: flex;
    }

    .structure-columns__scroll[b-0fwowt1mc7] {
        overflow-x: visible;
    }
}
/* /Features/Admin/WorkStructure/StructureTree.razor.rz.scp.css */
/* =============================================================================
   THE SHAPE HAS TO BE THE FIRST THING YOU SEE
   -----------------------------------------------------------------------------
   This tree read as a wall. Two causes, and they compound:

   1. One rem of indent per level is not enough to see a shape in. At that step a
      three-deep branch spans 48px, which is less than the width of one of the
      words on the row - so the eye finds no column to follow.

   2. Every row carried up to six action buttons, always visible. Twenty-four
      places is well over a hundred buttons on screen, and the names - the only
      thing anybody is actually reading - were the quietest thing on the row.

   So: a bigger step with a guide line and a tick into each row, type that gets
   quieter with depth, and the actions revealed on hover or focus where there is
   a pointer. On touch they stay put, because there is no hover to reveal them
   with and a control you cannot discover is worse than a busy row.
   ============================================================================= */

.structure-tree__list[b-ijnd46kvex] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Indentation is the only thing that shows the shape, so it is generous enough to
   read at a glance and applied by the nested list rather than by depth-specific
   classes - which would cap the depth in CSS. */
.structure-tree__list .structure-tree__list[b-ijnd46kvex] {
    margin-top: var(--space-1);
    padding-inline-start: var(--space-5);
    position: relative;
}

/* The branch line, drawn as an element rather than a border so it can stop short
   of the last child - a line running past the final row points at nothing and is
   the main reason an indented list still reads as a flat one. */
.structure-tree__list .structure-tree__list[b-ijnd46kvex]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: var(--space-2);
    width: var(--border-width);
    background-color: var(--color-border);
}

/* The tick from the branch line into each row, so a name is visibly attached to
   the line above it rather than merely near it. */
.structure-tree__list .structure-tree__list > .structure-tree__item[b-ijnd46kvex] {
    position: relative;
}

.structure-tree__list .structure-tree__list > .structure-tree__item > .structure-tree__row[b-ijnd46kvex]::before {
    content: "";
    position: absolute;
    inset-inline-start: calc(var(--space-5) * -1 + var(--space-2));
    width: calc(var(--space-3));
    height: var(--border-width);
    background-color: var(--color-border);
    top: 1.35rem;
}

.structure-tree__row[b-ijnd46kvex] {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md);
    min-height: 2.75rem;
}

.structure-tree__row:hover[b-ijnd46kvex],
.structure-tree__row:focus-within[b-ijnd46kvex] {
    background-color: var(--color-state-hover);
}

/* A retired place is dimmed AND says "Retired" - never colour alone. */
.structure-tree__item--retired > .structure-tree__row .structure-tree__name[b-ijnd46kvex] {
    color: var(--color-text-muted);
}

/* Fixed width whether or not there is a toggle, so names line up down a branch. */
.structure-tree__toggle[b-ijnd46kvex] {
    flex: 0 0 1.5rem;
    display: flex;
    justify-content: center;
}

.structure-tree__toggle-button[b-ijnd46kvex] {
    padding: var(--space-1);
    line-height: 1;
}

.structure-tree__label[b-ijnd46kvex] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    min-width: 0;
    flex: 1 1 auto;
}

/* -----------------------------------------------------------------------------
   Depth carries weight
   -----------------------------------------------------------------------------
   A zone and a piece of equipment inside it were set identically, so the only
   thing separating them was 16px of indent. Scaling the name down as the tree
   goes deeper means a branch reads as a hierarchy even where the indentation is
   clipped - on a phone, or inside a deeply nested subtree.

   Three steps and then it stops: past depth three the difference stops being
   legible and starts being small text.
   ----------------------------------------------------------------------------- */

.structure-tree__name[b-ijnd46kvex] {
    font-weight: var(--font-weight-semibold);
    overflow-wrap: anywhere;
}

.structure-tree__list > .structure-tree__item > .structure-tree__row .structure-tree__name[b-ijnd46kvex] {
    font-size: var(--font-size-lg);
}

.structure-tree__list .structure-tree__list > .structure-tree__item > .structure-tree__row .structure-tree__name[b-ijnd46kvex] {
    font-size: var(--font-size-base);
}

.structure-tree__list .structure-tree__list .structure-tree__list
    > .structure-tree__item > .structure-tree__row .structure-tree__name[b-ijnd46kvex] {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* The tag is read character by character rather than as a word, so it takes the
   mono face - the same treatment a site code gets. */
.structure-tree__code[b-ijnd46kvex] {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
}

/* The site's own word for this depth, as a quiet pill in a fixed position rather
   than another word in the same run of text - so the eye can skip it when it is
   reading names and find it when it is reading levels. */
.structure-tree__level[b-ijnd46kvex] {
    padding: 0 var(--space-2);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-full);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
    white-space: nowrap;
}

.structure-tree__hidden[b-ijnd46kvex] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.structure-tree__actions[b-ijnd46kvex] {
    --cluster-gap: var(--space-1);
    margin-inline-start: auto;
    flex-wrap: nowrap;
    justify-content: flex-end;
}

/* Where there is a real pointer, the actions stay out of the way until the row is
   pointed at or focused. That is what turns a hundred buttons back into a tree.
   Opacity rather than display, so the buttons keep their place in the tab order
   and :focus-within brings them back the instant a keyboard reaches one. */
@media (hover: hover) and (pointer: fine) {
    .structure-tree__actions[b-ijnd46kvex] {
        opacity: 0;
        transition: opacity var(--motion-duration-fast) var(--motion-easing-standard);
    }

    .structure-tree__row:hover .structure-tree__actions[b-ijnd46kvex],
    .structure-tree__row:focus-within .structure-tree__actions[b-ijnd46kvex] {
        opacity: 1;
    }
}

.structure-tree__detail[b-ijnd46kvex] {
    padding-inline-start: var(--space-5);
}

@media (max-width: 48rem) {
    /* Below the breakpoint a row becomes two: the label, then its actions, because
       five buttons and a name do not fit on one line on a phone. They stay visible -
       there is no hover to reveal them with. */
    .structure-tree__row[b-ijnd46kvex] {
        flex-wrap: wrap;
    }

    .structure-tree__actions[b-ijnd46kvex] {
        margin-inline-start: 0;
        justify-content: flex-start;
        width: 100%;
        flex-wrap: wrap;
        padding-top: var(--space-1);
    }

    /* A tighter step, because seven levels of 1.5rem would push a name off the
       right-hand edge of a phone before the tree ran out of depth. */
    .structure-tree__list .structure-tree__list[b-ijnd46kvex] {
        padding-inline-start: var(--space-4);
    }

    .structure-tree__list .structure-tree__list > .structure-tree__item > .structure-tree__row[b-ijnd46kvex]::before {
        inset-inline-start: calc(var(--space-4) * -1 + var(--space-2));
        width: var(--space-2);
    }
}
/* /Features/DailyReports/HoursField.razor.rz.scp.css */
/* CAPPED, BECAUSE THE ANSWER IS TWO CHARACTERS LONG.
   -----------------------------------------------------------------------------
   This control had no width of its own and took whatever it was given. In a
   narrow column that was right. Once the form went to one column at every width
   it meant the full width of the panel: a minus, a plus and six pills stretched
   across a desktop to ask for "7.5", which reads as the most important question
   on the form and is one of the smallest.

   The cap is sized to the row beneath it rather than to the row above - three
   preset columns at their floor plus their gaps. The stepper row needs about
   fifteen rems of that and has the rest as slack, so the two rows sit in a block
   the same width instead of one trailing off past the other. */
.hours-field[b-n4mtxfhr5p] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-width: 18rem;
}

.hours-field__row[b-n4mtxfhr5p] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* Square and large. These are the two controls most likely to be pressed with a glove on, and a wide
   short button is harder to hit than a square one of the same area. */
.hours-field__step[b-n4mtxfhr5p] {
    flex-shrink: 0;
    width: var(--layout-touch-target-min);
    min-width: var(--layout-touch-target-min);
    padding: 0;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    line-height: 1;
}

/* Takes the slack in the row, which is now a bounded amount - the cap on the field is what stopped
   this being "a full-width box for a two-character value", the objection that used to keep it at a
   fixed 5.5rem. Filling what is left instead squares the stepper row off against the preset grid
   below it, so the two read as one control rather than as a short row above a wider one. The floor is
   the old fixed width, so it can never be squeezed narrower than "24" with room to spare.
   Centred, because the value is the whole content. */
.hours-field__input[b-n4mtxfhr5p] {
    flex: 1 1 auto;
    min-width: 5.5rem;
    text-align: center;
    font-size: var(--font-size-lg);
    font-variant-numeric: tabular-nums;
}

/* NEVER SHRINKS. The box beside it takes the slack in this row, and a flex item's default is to give
   way - so the word was squeezed to its narrowest column and broke down the page one letter at a
   time, "ho / ur / s". It is four characters and it is the unit the number is in; it yields nothing. */
.hours-field__unit[b-n4mtxfhr5p] {
    flex-shrink: 0;
    white-space: nowrap;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* A grid rather than a wrap, so every preset is reachable at 320px without a horizontal gesture inside
   a vertically scrolling form - and so the six of them land as three and three rather than as four and
   a ragged two.

   THREE COLUMNS STATED RATHER THAN INFERRED. This was auto-fit with a 4.5rem floor, which produced
   three at 320px by arithmetic: three fit and four did not. That held only while the control was
   narrow. The moment it had room - and the cap above is deliberately wide enough for four - auto-fit
   would have re-laid them as four and two, which is the ragged shape the floor was chosen to avoid.
   Six presets in two rows of three is the arrangement wanted at every width, so it is written down. */
.hours-field__presets[b-n4mtxfhr5p] {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
}

/* FULL TOUCH HEIGHT, WHICH IT WAS NOT.
   -----------------------------------------------------------------------------
   These were 2.25rem, on the argument that they are a shortcut rather than the
   field itself and that six full-size buttons would take more of a phone screen
   than the form they belong to. The first half is still true and the conclusion
   was still wrong: nine times in ten the hours are entered by pressing one of
   these and the box beside them is never touched, which makes them the most
   pressed controls on the whole screen - and they were under the minimum this
   application sets for a gloved thumb.

   They cost one more row of a phone than they did. That is what they are worth.
   The rich text toolbar is still 2.25rem and stays there: those five are square,
   they are used a fraction as often, and a full-height toolbar above a text box
   would take a quarter of the visible form. */
.hours-field__preset[b-n4mtxfhr5p] {
    min-height: var(--layout-touch-target-min);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--font-size-base);
    font-variant-numeric: tabular-nums;
}

.hours-field__preset--on[b-n4mtxfhr5p] {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-medium);
}
/* /Features/DailyReports/JobList.razor.rz.scp.css */
.job-list[b-sdwtgunmy3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.job[b-sdwtgunmy3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    box-shadow: var(--shadow-sm);
}

/* Place on the left, hours on the right, and they swap to stacked only if the place name is long
   enough to need it - flex-wrap rather than a media query, because what decides it is the content
   rather than the viewport. */
.job__header[b-sdwtgunmy3] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}

.job__place[b-sdwtgunmy3] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.job__above[b-sdwtgunmy3] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    overflow-wrap: anywhere;
}

.job__name[b-sdwtgunmy3] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--font-size-base);
    overflow-wrap: anywhere;
}

/* The number is the thing being checked when somebody totals their week, so it is set larger than the
   text around it and in tabular figures - which is what makes a column of them line up. */
.job__hours[b-sdwtgunmy3] {
    display: flex;
    align-items: baseline;
    gap: var(--space-1);
    margin: 0;
    flex-shrink: 0;
}

.job__hours-number[b-sdwtgunmy3] {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
}

.job__hours-unit[b-sdwtgunmy3] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* Wraps, because a job now carries up to three of these and a phone has room for two. */
.job__tags[b-sdwtgunmy3] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
}

/* A quiet chip. These are classifications rather than statuses - nothing is right or wrong about a
   cost type or a trade - so they take the neutral contrast surface rather than one of the status
   colours, which would imply a judgement the fields do not carry. Work status is the exception and
   is a StatusBadge for exactly that reason. */
.job__tag[b-sdwtgunmy3] {
    display: inline-block;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.job__description[b-sdwtgunmy3] {
    font-size: var(--font-size-sm);
}

/* Separated from the content above by a rule, so a long description does not run straight into the
   buttons that act on it. */
.job__actions[b-sdwtgunmy3] {
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border-muted);
}
/* /Features/DailyReports/JobPanel.razor.rz.scp.css */
/* The layout is measured against the panel rather than against the window, because the panel is the
   window minus a sidebar that exists on a laptop and does not on a tablet - and a media query cannot
   tell those apart. Where container queries are unsupported the rules below never apply and the form
   stays one column, which is where it started. */
.job-panel[b-p42c0r1g97] {
    container-type: inline-size;
}

/* ONE COLUMN, IN THE ORDER THE FIELDS ARE WRITTEN: where, what kind, how long, and then what was done.
   That is the order somebody recounts an afternoon in, and it is what puts every tap above the one
   field that needs a keyboard. The wide layout below rearranges it by grid placement rather than by a
   second copy of the markup, so there is one reading order to get right rather than two. */
.job-panel__layout[b-p42c0r1g97] {
    display: grid;

    /* ONE COLUMN THAT CANNOT BE PUSHED WIDER THAN THE FORM. An implicit grid track is auto-sized, and
       auto's floor is the min-content width of what sits in it - so a single field holding anything
       that will not wrap drags the whole layout past the edge of a phone and scrolls the page
       sideways. minmax(0, 1fr) is the same guard the wide layout below already sets on both of its
       columns, for the same reason; the phone column only ever lacked it because nothing had tested
       it. It costs nothing: with one column, 1fr is the full width either way. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
}

/* The four classifications sit tighter than the fields around them, so they read as one block of
   settings rather than as four more questions of the same weight as the place and the hours. */
.job-panel__classifications[b-p42c0r1g97] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);

}

/* FULL WIDTH, AND THE ROWS PINNED RATHER THAN LEFT TO ARITHMETIC.
   -----------------------------------------------------------------------------
   The block was capped at four columns' worth, which left the right half of a
   desktop panel empty and made the form read as a narrow strip down one side.
   It takes the whole width now.

   That breaks what the cap was protecting. SegmentedChoice sizes its columns by
   auto-fit against an 8rem floor, so at full width the kinds of work would land
   eight across in a row and a half - and those are ORDERED: the trades first,
   then what checks and supports them, and last the ones that are not work on
   the plant. That tail only reads as a group while it is a row of its own.

   So each choice states its own column count instead. Twelve kinds as four rows
   of three keeps travel, admin and the break together on the last row; the
   five-option choices take three and fall two and three, which is tidier than a
   row of five short pills stretched across a laptop; the three-option one takes
   three and is one row. ::deep because the grid belongs to SegmentedChoice. */
.job-panel__classifications[b-p42c0r1g97]  .segmented-choice {
    max-width: none;
}

.job-panel__classifications[b-p42c0r1g97]  .segmented-choice__options {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Below that, three columns of anything is too narrow to read, so the floor
   takes over again and the rows fall where they fall. */
@container (max-width: 34rem) {
    .job-panel__classifications[b-p42c0r1g97]  .segmented-choice__options {
        grid-template-columns: repeat(auto-fit, minmax(min(8rem, 100%), 1fr));
    }
}

.job-panel__write[b-p42c0r1g97] {
    display: flex;
    flex-direction: column;
}

/* ::deep: the field is FormField's markup and never carries this file's scope attribute. The label is
   set larger than every other label on the form on purpose - it is the one question whose answer
   nobody can reconstruct later, and the form should look like it is asking for a paragraph. */
.job-panel__write[b-p42c0r1g97]  .field {
    flex: 1 1 auto;
}

.job-panel__write[b-p42c0r1g97]  label {
    font-size: var(--font-size-lg);
}

/* =============================================================================
   ONE COLUMN EVERYWHERE, AND THE OPTIONS OPENED OUT
   -----------------------------------------------------------------------------
   This was two columns on a wide panel - place and hours on the left, the four
   classifications on the right, the answer spanning both. It read as two forms
   side by side rather than one form. The eye had to cross the panel and come
   back for every field, and the two columns were filled in different orders by
   different people, which is how a form ends up with a question missed.

   So the wide panel now keeps the phone's single column and its source order:
   where, what kind, how long, what was done. That is the order somebody recounts
   an afternoon in, and there is now exactly one reading order rather than two.

   WHAT THE WIDE PANEL STILL CHANGES is what it has the room for rather than how
   it is arranged: every option visible instead of a row that opens, and a text
   box tall enough to write a paragraph in. Both are about width, which is why
   they stay behind the container query that the column count has left.
   ============================================================================= */

@container (min-width: 52rem) {
    /* The row that opens the options is what a phone needs and what this pane does not: there is room
       for the choices themselves, so the label stands alone above them and every option is visible
       without a press. ::deep because both belong to CompactChoice's own markup. */
    .job-panel__classifications[b-p42c0r1g97]  .compact-choice__summary {
        display: none;
    }

    .job-panel__classifications[b-p42c0r1g97]  .compact-choice__asked {
        display: block;
    }

    .job-panel__classifications[b-p42c0r1g97]  .compact-choice__options {
        display: flex;
    }

    /* The editor's own stylesheet reads this and grows to it. Set here rather than there, and by a
       container query rather than a media query, because the thing that decides whether there is room
       for a tall text box is the width of this panel - not the width of the window, which is the same
       on a laptop with a sidebar and a tablet without one. */
    .job-panel__write[b-p42c0r1g97] {
        --rich-text-min-height: 14rem;
    }
}

.job-panel__actions[b-p42c0r1g97] {
    margin-top: var(--space-5);
}

/* Pushed to the far end of the row on a wide panel, and simply next in the wrap on a phone. Quiet: it
   is a reassurance rather than an instruction, and it must not compete with the button beside it. */
.job-panel__so-far[b-p42c0r1g97] {
    margin: 0;
    margin-inline-start: auto;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}
/* /Features/DailyReports/Pages/DailyReportDay.razor.rz.scp.css */
.day__back[b-f7x1822fd7] {
    white-space: nowrap;
}

/* The five facts. auto-fit rather than a fixed column count, so this is one row on a laptop, two on a
   tablet and a stack on a phone with no media query - and so adding a sixth fact later needs no change
   here. The floor is wide enough for a native date picker's own chrome, which is the widest thing in
   the row. */
.day__facts[b-f7x1822fd7] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
    gap: var(--space-4);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    align-items: start;
}

.day__fact[b-f7x1822fd7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.day__fact-label[b-f7x1822fd7] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.day__fact-value[b-f7x1822fd7] {
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

/* Muted and italic: it is a gap in the record rather than a value, and it must not be mistaken for the
   name of a company called something odd. */
.day__fact-missing[b-f7x1822fd7] {
    color: var(--color-text-muted);
    font-style: italic;
    font-weight: var(--font-weight-regular);
}

/* The running total, which is the number somebody checks before handing the day in. Tabular figures so
   it does not shift as it changes. */
.day__total[b-f7x1822fd7] {
    font-size: var(--font-size-lg);
    font-variant-numeric: tabular-nums;
}

/* Preserves the line breaks somebody typed into a dispute reason. It is plain text - the reason field
   is not rich text - so the alternative is running their paragraphs together. */
.day__reason[b-f7x1822fd7] {
    white-space: pre-wrap;
    font-weight: var(--font-weight-medium);
}

/* THE DAY, AS ONE OF THE FACTS. It carries a FormField rather than the label/value pair its neighbours
   use, because it is editable - so its label has to be a real <label> bound to the input. These three
   rules are what make it look like the other four anyway.

   ::deep, because FormField's markup is FormField's and never carries this file's scope attribute. That
   is also why the max-width below had no effect where it used to sit: `.day__date-input` was set on an
   <input> rendered by InputDate, and the scoped rule could never match it, so the field ran the full
   width of the block it was in. */
.day__fact--date[b-f7x1822fd7]  label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.day__fact--date[b-f7x1822fd7]  .field__hint {
    font-size: var(--font-size-xs);
}

.day__fact--date[b-f7x1822fd7]  input {
    /* Wide enough for the native picker's own chrome on every browser, and no wider: a full-width date
       field on a laptop looks like a text box that has been left unfinished. */
    max-width: 16rem;
}

.day__jobs[b-f7x1822fd7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.day__jobs-header[b-f7x1822fd7] {
    justify-content: space-between;
}

.day__jobs-title[b-f7x1822fd7] {
    margin: 0;
}

/* The hand-in block. Bordered and set apart so it does not read as one more action on the last job -
   this is the one control on the screen that cannot be undone by the person pressing it. */
.day__submit[b-f7x1822fd7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-inset);
}

.day__submit-title[b-f7x1822fd7] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.day__submit-text[b-f7x1822fd7] {
    margin: 0;
    color: var(--color-text-secondary);
}

.day__submit-blocked[b-f7x1822fd7] {
    margin: 0;
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
}

/* Full width on a phone, where it is the last thing on the screen and the reader's thumb is nowhere
   near a precise target; its natural width from the tablet breakpoint up. */
.day__submit-button[b-f7x1822fd7] {
    width: 100%;
}

@media (min-width: 48rem) {
    .day__submit-button[b-f7x1822fd7] {
        width: auto;
    }
}
/* /Features/DailyReports/Pages/MyDailyReports.razor.rz.scp.css */
/* The action block. Bordered and on the container surface so it reads as the thing to do rather than
   as a caption above the list. */
.reports__start[b-nyzcbk7s8b] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    box-shadow: var(--shadow-sm);
}

.reports__start-title[b-nyzcbk7s8b] {
    margin: 0;
    font-size: var(--font-size-lg);
}

/* Stacked on a phone, side by side from the tablet breakpoint. The "today" button keeps the whole width
   at every size, because it is what nine visits in ten are for and a thumb should not have to aim. */
.reports__start-controls[b-nyzcbk7s8b] {
    display: grid;
    gap: var(--space-5);
}

/* THE PRIMARY ACTION TAKES WHATEVER ROOM IS LEFT. Sized to its own text it was a small slab against
   the left edge of a wide card with half a screen of nothing beside it, which reads as the least
   important control on the page rather than the most. One flexible column for the verb, and an auto
   column for the date picker, which is for the tenth visit and is sized by its own contents. */
@media (min-width: 48rem) {
    .reports__start-controls[b-nyzcbk7s8b] {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: var(--space-6);
    }
}

/* The verb over the date, rather than one sentence left to wrap wherever the width runs out. Column
   direction with a tight gap keeps the two lines reading as one label instead of as two. */
.reports__today[b-nyzcbk7s8b] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: 100%;
    min-height: 3.25rem;
    padding: var(--space-3) var(--space-5);
    line-height: var(--line-height-tight);
}

.reports__today-action[b-nyzcbk7s8b] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
}

/* The confirmation of which day is about to be opened, not a second instruction - so it is quieter
   than the verb above it while staying comfortably readable. */
.reports__today-date[b-nyzcbk7s8b] {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    opacity: 0.85;
}

/* Taller as well as wider once there is room: a control this wide at phone height reads as a banner
   rather than as a button. */
@media (min-width: 48rem) {
    .reports__today[b-nyzcbk7s8b] {
        min-height: 3.75rem;
    }
}

/* Separated from the primary action by a rule on a phone, where they stack and would otherwise read as
   one group of three controls. */
.reports__other[b-nyzcbk7s8b] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-4);
    border-top: var(--border-width) solid var(--color-border-muted);
}

@media (min-width: 48rem) {
    .reports__other[b-nyzcbk7s8b] {
        padding-top: 0;
        border-top: 0;
    }
}

/* ::deep, because the box is rendered by InputDate and never carries this file's scope attribute - a
   rule written against the class passed to that component could never match it. */
.reports__other[b-nyzcbk7s8b]  input {
    max-width: 14rem;
}

.reports__no-create[b-nyzcbk7s8b] {
    margin: 0;
    color: var(--color-text-secondary);
}

.reports__list[b-nyzcbk7s8b] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The whole row is the link, not a "view" button on the end of it. On a phone that is the difference
   between a target the width of the screen and one the width of a word. */
.report-row[b-nyzcbk7s8b] {
    display: grid;
    gap: var(--space-1) var(--space-4);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    color: var(--color-text);
    text-decoration: none;

    /* Phone: date, then status, then hours, then any reason - one under the other, read top to bottom. */
    grid-template-columns: 1fr;
    grid-template-areas:
        "date"
        "status"
        "hours"
        "reason";
}

.report-row:hover[b-nyzcbk7s8b],
.report-row:focus-visible[b-nyzcbk7s8b] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
    border-color: var(--color-border-outline);
    color: var(--color-text);
    text-decoration: none;
}

/* From the tablet breakpoint the three facts sit on one line, with the reason spanning underneath. The
   hours column is fixed so a column of them lines up down the list. */
@media (min-width: 48rem) {
    .report-row[b-nyzcbk7s8b] {
        grid-template-columns: minmax(9rem, auto) 1fr minmax(7rem, auto);
        grid-template-areas:
            "date status hours"
            "reason reason reason";
        align-items: center;
    }
}

.report-row__date[b-nyzcbk7s8b] {
    grid-area: date;
    font-weight: var(--font-weight-semibold);
}

.report-row__status[b-nyzcbk7s8b] {
    grid-area: status;
}

.report-row__hours[b-nyzcbk7s8b] {
    grid-area: hours;
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

@media (min-width: 48rem) {
    .report-row__hours[b-nyzcbk7s8b] {
        justify-content: flex-end;
    }
}

.report-row__hours-number[b-nyzcbk7s8b] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.report-row__hours-unit[b-nyzcbk7s8b] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* The reason a day came back. Warning-coloured and set apart, because it is the only thing in the list
   that asks the reader to do something. */
.report-row__reason[b-nyzcbk7s8b] {
    grid-area: reason;
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: var(--border-width) solid var(--color-border-muted);
    color: var(--color-warning-text);
    font-size: var(--font-size-sm);

    /* Preserves the line breaks somebody typed. The reason is plain text, not rich text. */
    white-space: pre-wrap;
}

/* The same slot used for "nothing on this day yet", which is information rather than a call to act. */
.report-row__reason--quiet[b-nyzcbk7s8b] {
    color: var(--color-text-muted);
    white-space: normal;
}
/* /Features/DailyReports/PersonDaysPanel.razor.rz.scp.css */
/* =============================================================================
   One person's days, as tiles

   A GRID RATHER THAN A TABLE. The cells are read by scanning for colour - which
   days are settled, which are not - and only then read in detail. A table of the
   same data puts every day on an equal footing and makes the two states that
   matter look like the four that do not.
   ============================================================================= */

.person-days[b-i5dibxeojb] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.person-days__empty[b-i5dibxeojb] {
    margin: 0;
    color: var(--color-text-secondary);
}

/* The totals, on one line above the grid. Wraps to two on a phone rather than
   truncating: every figure here is the answer to somebody's question. */
.person-days__summary[b-i5dibxeojb] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.person-days__figure[b-i5dibxeojb] {
    font-variant-numeric: tabular-nums;
}

/* The one figure that is a prompt rather than a reading. */
.person-days__figure--warning[b-i5dibxeojb] {
    color: var(--color-warning-text);
    font-weight: var(--font-weight-semibold);
}

/* auto-fill rather than auto-fit: a person with three days should get three
   tiles at their proper width, not three tiles stretched across the dialog. */
.person-days__grid[b-i5dibxeojb] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.person-day[b-i5dibxeojb] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-2);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

/* The date reads as a date at a glance - weekday, then the number large enough to
   find, then the month so a tile lifted out of its row still says when it is. */
.person-day__date[b-i5dibxeojb] {
    display: flex;
    align-items: baseline;
    gap: var(--space-1);
    margin: 0;
    line-height: var(--line-height-tight);
}

.person-day__weekday[b-i5dibxeojb],
.person-day__month[b-i5dibxeojb] {
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
    color: var(--color-text-secondary);
}

.person-day__number[b-i5dibxeojb] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.person-day__state[b-i5dibxeojb] {
    margin: 0;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-tight);
}

.person-day__figures[b-i5dibxeojb] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
    margin: 0;
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

.person-day__hours[b-i5dibxeojb] {
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

/* Sits at the bottom of the tile and is pushed there, so the flag lines up across
   a row whatever else each tile happens to carry. */
.person-day__flag[b-i5dibxeojb] {
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-xs);
    line-height: var(--line-height-tight);
    color: var(--color-danger-text);
}

.person-day__flag--quiet[b-i5dibxeojb] {
    color: var(--color-text-muted);
}

/* ------------------------------------------------------------------ the states */

/* THE SAME VOCABULARY THE REST OF THE APPLICATION USES, including the line
   ReportStatusView draws: a day sent back is a warning because its author can put
   it right, and danger is kept for what did not happen at all - which on this card
   is a real thing rather than a hypothetical one, so Missing is the only cell that
   gets it. */

/* The ends of the rotation. Quieter than anything else on the grid - no fill, a
   muted border and muted text - because these cells exist to be counted rather
   than read: they say where the stretch stops, and then get out of the way. */
.person-day--off-site[b-i5dibxeojb] {
    border-color: var(--color-border-muted);
    background-color: transparent;
    color: var(--color-text-muted);
}

.person-day--off-site .person-day__number[b-i5dibxeojb],
.person-day--off-site .person-day__state[b-i5dibxeojb] {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-regular);
}

/* Nothing is due yet, so the tile is drawn as an outline rather than a state. The
   dashed border is the whole signal: this day has not happened. */
.person-day--planned[b-i5dibxeojb] {
    border-style: dashed;
    background-color: transparent;
}

.person-day--planned .person-day__state[b-i5dibxeojb] {
    color: var(--color-text-muted);
}

.person-day--approved[b-i5dibxeojb] {
    border-color: var(--color-success);
    background-color: var(--color-success-subtle);
}

.person-day--approved .person-day__state[b-i5dibxeojb] {
    color: var(--color-success-text);
}

.person-day--submitted[b-i5dibxeojb] {
    border-color: var(--color-info);
    background-color: var(--color-info-subtle);
}

.person-day--submitted .person-day__state[b-i5dibxeojb] {
    color: var(--color-info-text);
}

/* Draft and sent back are both the author's to act on, so they share a tone. The
   labels say which, and the border weight says which is worse. */
.person-day--draft[b-i5dibxeojb] {
    background-color: var(--color-warning-subtle);
}

.person-day--draft .person-day__state[b-i5dibxeojb],
.person-day--sent-back .person-day__state[b-i5dibxeojb] {
    color: var(--color-warning-text);
}

.person-day--sent-back[b-i5dibxeojb] {
    border-color: var(--color-warning);
    background-color: var(--color-warning-subtle);
}

.person-day--missing[b-i5dibxeojb] {
    border-color: var(--color-danger);
    background-color: var(--color-danger-subtle);
}

.person-day--missing .person-day__state[b-i5dibxeojb] {
    color: var(--color-danger-text);
}
/* /Features/DailyReports/PlaceColumns.razor.rz.scp.css */
.place-columns[b-zh3g4v1zlv] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* THE ONLY THING ON THIS SCREEN THAT SCROLLS SIDEWAYS, and it scrolls at every width - which is where
   this parts company with Site layout, whose columns collapse to one on a phone behind a breadcrumb.
   A breadcrumb summarises the chain; it cannot show that the chain had alternatives, and that is the
   whole reason for drawing columns. So the phone drags the strip instead.

   The page body must never scroll horizontally - the rule the whole application is built to - so the
   overflow is owned here, and overscroll-behavior stops a flick that reaches the last column turning
   into the browser's own back gesture, which on a phone loses the half-filled job behind this panel. */
.place-columns__scroll[b-zh3g4v1zlv] {
    display: flex;
    align-items: stretch;
    gap: var(--space-3);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    padding-bottom: var(--space-2);

    /* A column comes to rest against the left edge rather than halfway across, so a drag that lands
       between two columns settles on one of them. */
    scroll-snap-type: x proximity;
}

.place-columns__column[b-zh3g4v1zlv] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    scroll-snap-align: start;

    /* Wide enough for a place name and its tag, narrow enough that three fit on a laptop. The floor
       and the fixed basis are the same number on purpose: these must not shrink to fit, because a
       strip of squeezed columns is the thing the sideways scroll exists to avoid. */
    flex: 0 0 15rem;
    min-width: 15rem;
    max-height: 22rem;
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.place-columns__head[b-zh3g4v1zlv] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
}

/* The site's own word for this depth, once as a column heading rather than as a pill on every row.
   That saving is what makes a column quieter than the list it replaced. */
.place-columns__title[b-zh3g4v1zlv] {
    margin: 0;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
    overflow-wrap: anywhere;
}

.place-columns__count[b-zh3g4v1zlv] {
    flex-shrink: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
}

/* The one control in this view that files against a place with things inside it, and the reason a
   container never has to be chosen from the row that opened it.

   It sits OUTSIDE the list rather than at the top of it, which is what keeps it in reach without any
   stickiness: the list is the scroll box, so a zone with forty systems in it scrolls its rows under
   this button rather than carrying it away. As the first child of the list it would have needed
   position: sticky to do the same job, and sticky inside a scroller that also scrolls sideways is a
   repaint bug waiting for a phone to find it. */
.place-columns__self[b-zh3g4v1zlv] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2);
    border: var(--border-width) dashed var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface);
    text-align: left;
    font-size: var(--font-size-sm);
}

.place-columns__self--chosen[b-zh3g4v1zlv] {
    border-style: solid;
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-medium);
}

.place-columns__tick[b-zh3g4v1zlv] {
    display: flex;
    flex-shrink: 0;
    opacity: 0;
}

.place-columns__self--chosen .place-columns__tick[b-zh3g4v1zlv] { opacity: 1; }

.place-columns__self-text[b-zh3g4v1zlv] {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* The column scrolls, not the page: a zone with sixty systems in it must not make the two columns
   beside it sixty rows tall. */
.place-columns__list[b-zh3g4v1zlv] {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    flex: 1 1 auto;
}

.place-columns__empty[b-zh3g4v1zlv] {
    margin: 0;
    flex: 1 1 auto;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.place-columns__place[b-zh3g4v1zlv] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    width: 100%;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2);
    border-color: transparent;
    background-color: transparent;
    text-align: left;
}

/* TWO STATES THAT MEAN DIFFERENT THINGS, AND THEY MUST NOT LOOK ALIKE. Open is the place whose
   contents are in the column to the right - a position, not an answer. Chosen is what the day will be
   filed against. Open is a quiet fill; chosen is the filled pill every other picker on this form uses
   for the same meaning. */
.place-columns__place--open[b-zh3g4v1zlv] {
    background-color: var(--color-state-selected);
    border-color: var(--color-border);
}

.place-columns__place--chosen[b-zh3g4v1zlv] {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-semibold);
}

.place-columns__place-text[b-zh3g4v1zlv] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
    min-width: 0;
}

.place-columns__place-name[b-zh3g4v1zlv] {
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

/* A tag is read character by character rather than as a word, so it takes the mono face. */
.place-columns__code[b-zh3g4v1zlv] {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
}

.place-columns__place--chosen .place-columns__code[b-zh3g4v1zlv] {
    background-color: transparent;
    border: var(--border-width) solid currentColor;
    color: inherit;
}

/* How many places are inside, and the arrow saying the next column will show them. Absent entirely on
   a place with nothing inside, so a column reads as a list of ends and a list of ways on. */
.place-columns__inside[b-zh3g4v1zlv] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
}

.place-columns__place--chosen .place-columns__inside[b-zh3g4v1zlv] { color: inherit; }

.place-columns__inside-count[b-zh3g4v1zlv] {
    font-variant-numeric: tabular-nums;
}

/* A PHONE KEEPS THE SAME COLUMN WIDTH, and the sliver of the next one at the edge is what says the
   strip drags. This briefly set 82vw instead, to make a column nearly fill the screen - which was
   measured against the wrong thing. The strip is inside the panel, inside the page's own side
   padding, so its visible width is some way short of the viewport's: a column of 82vw came out WIDER
   than the box it scrolls in, and the last one could never sit fully in view. Scrolled to the end it
   sat with its left edge cut off, heading and all, reading "EVEL 2".

   15rem is narrower than that box at every width this application supports, so a column is always
   whole. Only the height changes here - a phone has less of it to spare. */
@media (max-width: 30rem) {
    .place-columns__column[b-zh3g4v1zlv] {
        max-height: 17rem;
    }
}
/* /Features/DailyReports/PlacePicker.razor.rz.scp.css */
.place-picker[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);

    /* Measured against the control rather than the window, because the window says nothing useful
       here: the job form goes two-column at 52rem, so this control is WIDER at an 830px window than
       at a 900px one. See the query at the foot of this file for what that arithmetic allows. */
    container-type: inline-size;
}

/* The label when there is nothing to collapse to - no place chosen. Matches the weight base.css gives
   a <label>, because that is what it is. */
.place-picker__asked[b-nr0679ks35] {
    font-weight: var(--font-weight-medium);
}

/* The collapsed row, deliberately the same shape as CompactChoice's: question on the left, answer on
   the right, chevron. Overrides the centred inline-flex base.css gives every button, because a label
   and its value must not both drift to the middle. */
.place-picker__summary[b-nr0679ks35] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, auto) auto;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-input);
    text-align: left;
}

.place-picker__label[b-nr0679ks35] {
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-medium);

    /* The question is what gives way when the row runs out of width; the answer is not. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.place-picker__chevron[b-nr0679ks35] {
    display: flex;
    align-items: center;
    color: var(--color-text-muted);
}

.place-picker__chosen-text[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-1);

    /* Lets the path truncate instead of pushing the chevron off the edge of a narrow phone. */
    min-width: 0;
}

/* The ways of choosing, in the same inset box CompactChoice opens into - so the two controls read as
   the same control asked about different things. */
.place-picker__panel[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

/* The context, above the name and quieter than it. Above rather than below because it reads in the
   order the tree does - zone, then system, then the thing. */
.place-picker__above[b-nr0679ks35] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);

    /* Long paths run to four or five names and must not wrap a form field to three lines. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.place-picker__name[b-nr0679ks35] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    flex-wrap: wrap;
    font-weight: var(--font-weight-semibold);
}

/* A tag comes off a drawing, so it is set in the monospace face - which is what makes a digit
   distinguishable from a letter at a glance, and these differ by one character constantly. */
.place-picker__code[b-nr0679ks35] {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
}

/* The site's own word for this depth - "Sone", "Anlegg", "System". The same quiet pill the site layout
   tree uses, so a level looks the same wherever it is read. */
.place-picker__level[b-nr0679ks35] {
    padding: 0 var(--space-2);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-full);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
    white-space: nowrap;
}

/* -----------------------------------------------------------------------------
   Places already used on this day
   -----------------------------------------------------------------------------
   The shortest path to the commonest answer. After the second job of a day the
   reader is usually moving between places they have already been, and a chip is
   one tap where the tree is three and the search box is a keyboard.
   ----------------------------------------------------------------------------- */

.place-picker__recent[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.place-picker__recent-label[b-nr0679ks35] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.place-picker__recent-list[b-nr0679ks35] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* Full touch height. These were shorter, by analogy with the hours presets - an analogy the same piece
   of work retracted, because a shortcut that is pressed instead of the control below it is not a lesser
   control, it is the one that gets used. The compact padding keeps the row light without shrinking the
   target. */
.place-picker__recent-item[b-nr0679ks35] {
    min-height: var(--layout-touch-target-min);
    max-width: 100%;
    padding: var(--space-1) var(--space-3);

    /* Not a pill any more: a chip now carries the building and the tank as well as the name, because
       three jobs in three different degassers produced three chips reading "Degasser" and a title
       attribute a phone cannot show. That is more than one line's worth, and a two-line pill reads as
       a mistake. */
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
    text-align: left;
}

/* -----------------------------------------------------------------------------
   The two list states
   -----------------------------------------------------------------------------
   Browsing draws one level of the site (PlaceLevel) under the trail that says
   where that level is (PlaceTrail); searching draws a flat ranked list. Both are
   capped and scroll inside their own box, so the form below stays reachable on a
   phone without a long scroll past every place on the site.
   ----------------------------------------------------------------------------- */

/* The trail and the level it describes are one thing, closer to each other than
   either is to the search box above them. */
.place-picker__browse[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

.place-picker__results[b-nr0679ks35],
.place-picker__matches[b-nr0679ks35] {
    max-height: 20rem;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;

    /* A list scrolled to its end must not start scrolling the panel behind it. */
    overscroll-behavior: contain;
    margin: 0;
    padding: var(--space-1);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

/* Edge to edge, unlike the search list. Two reasons, and the second is the one
   that matters: a row is now the whole target rather than a button inset in one,
   so padding around the list would be dead space that looks tappable - and the
   "work was on this place itself" row sticks to the top of this box, which it
   cannot do flush if the box holds it away from its own edge. */
.place-picker__results[b-nr0679ks35] {
    padding: 0;
    overflow-x: hidden;
}

.place-picker__matches[b-nr0679ks35] {
    padding: 0;
    list-style: none;
}

.place-picker__matches li + li[b-nr0679ks35] {
    border-top: var(--border-width) solid var(--color-border-muted);
}

/* =============================================================================
   LED BY WHAT TELLS THE ROW APART
   -----------------------------------------------------------------------------
   A result row used to lead with the place's own name, indent itself by its
   depth, and put the path underneath in the smallest, quietest type on the row.
   On this site that is exactly backwards: search "degasser" and every hit is a
   depth-4 system called Degasser, so the name and the indent were identical down
   all thirty rows - the indent alone spending 60 of a phone's 162 usable pixels
   saying nothing - while the one varying token, the tank, was last and faintest.

   Now the row leads with the shortest part of its path that is unique among the
   rows on screen, at full weight, at a fixed x; what every row shares trails it
   quietly. PlaceLabel decides which is which, and the indent and its guide line
   are gone, along with PlaceOption.Indent that fed them.
   ============================================================================= */

.place-picker__result[b-nr0679ks35] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    width: 100%;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-3);
    border: 0;
    border-radius: var(--radius-none);
    background-color: transparent;
    text-align: left;
}

.place-picker__result-text[b-nr0679ks35] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    min-width: 0;
}

.place-picker__result--selected[b-nr0679ks35] {
    background-color: var(--color-state-selected);
}

/* The lead reads as one line of prose rather than as a row of chips, so it wraps as one - inline,
   not flex. A flex line would break between every segment the moment it ran out of width. */
.place-picker__lead[b-nr0679ks35] {
    min-width: 0;
    overflow-wrap: anywhere;
}

.place-picker__lead-loud[b-nr0679ks35] {
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

/* Said by every row, so it confirms rather than announces: this is the word that was typed. */
.place-picker__lead-quiet[b-nr0679ks35] {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.place-picker__lead-separator[b-nr0679ks35] {
    color: var(--color-text-muted);
}

/* Only drawn where the results span more than one level - see PlacePicker. */
.place-picker__result-meta[b-nr0679ks35] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* =============================================================================
   SAYING HOW MANY THINGS SHARE A NAME
   -----------------------------------------------------------------------------
   Thirty rows that look alike read as a broken list until something says they
   are meant to. The caption says it, and hands over a term that separates them.
   ============================================================================= */

.place-picker__caption[b-nr0679ks35] {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* A term to type, set as one - the same monospace face a tag takes, for the same reason. */
.place-picker__try[b-nr0679ks35] {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-contrast);
    color: var(--color-text);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
}

/* The same "this row is a control and here is what it does" mark the browse list carries, so the two
   states of one picker do not read as two different lists. */
.place-picker__pick[b-nr0679ks35] {
    flex-shrink: 0;
    padding: var(--space-1) var(--space-2);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-full);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

.place-picker__result:hover .place-picker__pick[b-nr0679ks35],
.place-picker__result:focus-visible .place-picker__pick[b-nr0679ks35] {
    border-color: var(--color-border-outline);
    color: var(--color-text);
}

.place-picker__result--selected .place-picker__pick[b-nr0679ks35] {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
}

.place-picker__none[b-nr0679ks35],
.place-picker__more[b-nr0679ks35] {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* =============================================================================
   ONE STEP WIDER THAN A PHONE
   -----------------------------------------------------------------------------
   23rem, and the number is a measurement rather than a taste. The picker's own
   width is not monotonic in the window's: .job-panel goes two-column at a 52rem
   container query, so the control gets about 48rem at an 830px window, 24.5rem
   at 900px, 33rem at 1440px and 36rem at the content cap. Every threshold above
   ~23.4rem therefore switches on at one size and off again at a larger one,
   which is why there is no richer desktop layout here and no second pane: there
   is no desktop width to build one in that does not vanish when the form goes
   two-column.

   What is left is density, and both halves of it are improvements at any width
   rather than a different design that has to hold together on its own.
   ============================================================================= */

@container (min-width: 23rem) {
    /* More of the list at once, but never more than half the screen is tall.
       Inline size is what a container query can ask about and height is what
       this cap is actually about: a phone held sideways is 844px wide and 390
       tall, so it passes 23rem comfortably and would have taken a 384px list
       into a 390px viewport - burying the form this control sits in, which is
       the one thing the base cap exists to prevent. svh rather than vh so the
       browser's own chrome is already subtracted. */
    .place-picker__results[b-nr0679ks35],
    .place-picker__matches[b-nr0679ks35] {
        max-height: min(24rem, 50svh);
    }

    /* The level word joins the lead on one baseline instead of stacking under
       it, which is a line back per row across a list of thirty. */
    .place-picker__result-text[b-nr0679ks35] {
        flex-direction: row;
        align-items: baseline;
        gap: var(--space-3);
    }
}
/* /Features/Manage/ApprovalRow.razor.rz.scp.css */
.approval[b-l0qehvha2j] {
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    overflow: hidden;
}

.approval--open[b-l0qehvha2j] {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

/* The whole summary line is the control. On a phone that is a target the width of the screen rather
   than a chevron the width of a fingernail. */
.approval__summary[b-l0qehvha2j] {
    display: grid;
    gap: var(--space-1) var(--space-4);
    width: 100%;
    padding: var(--space-4);
    border: 0;
    border-radius: 0;
    background-color: transparent;
    text-align: left;

    /* Phone: who, then when, then how much - one under the other, with the chevron alongside. */
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "who chevron"
        "date chevron"
        "hours chevron";
    align-items: center;
}

@media (min-width: 48rem) {
    .approval__summary[b-l0qehvha2j] {
        grid-template-columns: 1fr minmax(7rem, auto) minmax(8rem, auto) auto;
        grid-template-areas: "who date hours chevron";

        /* Top, not centre, once these are four columns side by side rather than three rows stacked. A
           name that wraps to two lines would otherwise push the date and the hours beside it down half a
           line, and a column of rows where the date sits at a slightly different height in each is
           harder to scan than one where every row starts on the same line. Centring is right on a phone,
           where the chevron sits beside a stack of three. */
        align-items: start;
    }

    /* The exception, and deliberately so: the chevron is one glyph that means "open this row", and it
       belongs against the middle of the row it opens rather than pinned to the top corner. */
    .approval__chevron[b-l0qehvha2j] {
        align-self: center;
    }
}

.approval__who[b-l0qehvha2j] {
    grid-area: who;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.approval__author[b-l0qehvha2j] {
    font-weight: var(--font-weight-semibold);
    overflow-wrap: anywhere;
}

.approval__company[b-l0qehvha2j] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.approval__date[b-l0qehvha2j] {
    grid-area: date;
    color: var(--color-text-secondary);
}

.approval__hours[b-l0qehvha2j] {
    grid-area: hours;
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

@media (min-width: 48rem) {
    .approval__hours[b-l0qehvha2j] {
        justify-content: flex-end;
    }
}

/* The number being checked, so it is set larger and in tabular figures - which is what makes a column
   of them scannable down the queue. */
.approval__hours-number[b-l0qehvha2j] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.approval__hours-unit[b-l0qehvha2j] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.approval__chevron[b-l0qehvha2j] {
    grid-area: chevron;
    display: flex;
    align-items: center;
    color: var(--color-text-muted);
}

/* Inset on the recessed surface, so the day's contents read as being inside the row rather than as
   the next row. */
.approval__detail[b-l0qehvha2j] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4);
    border-top: var(--border-width) solid var(--color-border);
    background-color: var(--color-surface-inset);
}

.approval__actions[b-l0qehvha2j] {
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border-muted);
}

.approval__reason[b-l0qehvha2j] {
    width: 100%;
}

.approval__dispute[b-l0qehvha2j] {
    --stack-gap: var(--space-3);
}

.approval__open-day[b-l0qehvha2j] {
    align-self: center;
    margin-left: auto;
    font-size: var(--font-size-sm);
}
/* /Features/Manage/CalendarDayDialog.razor.rz.scp.css */
.day-detail__figures[b-kudi9n4wmy] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(6rem, 45%), 1fr));
    gap: var(--space-4);
    margin: 0;
}

/* The same five colours the grid uses, on the same rule under each number - so a figure means the
   same thing in the dialog as it did in the cell that opened it. */
.figure[b-kudi9n4wmy] {
    border-top: 3px solid var(--color-border);
    padding-top: var(--space-2);
}

.figure dt[b-kudi9n4wmy] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.figure dd[b-kudi9n4wmy] {
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
}

.figure--crew[b-kudi9n4wmy] { border-top-color: var(--color-surface-contrast); }
.figure--arriving[b-kudi9n4wmy] { border-top-color: var(--color-success); }
.figure--leaving[b-kudi9n4wmy] { border-top-color: var(--color-marine-strong); }
.figure--hours[b-kudi9n4wmy] { border-top-color: var(--color-border-strong); }

.day-detail__heading[b-kudi9n4wmy] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-base);
}

/* The sentence that stops this being read as attendance. Kept directly under the heading it qualifies
   rather than in a footnote, because the distinction between "the records say" and "somebody was
   here" is the whole caveat of the feature. */
.day-detail__caveat[b-kudi9n4wmy] {
    margin: 0 0 var(--space-3);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.day-detail__empty[b-kudi9n4wmy] {
    margin: 0;
    color: var(--color-text-muted);
}

.day-detail__list[b-kudi9n4wmy] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.day-report[b-kudi9n4wmy],
.crew-member[b-kudi9n4wmy] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
}

.day-report__who[b-kudi9n4wmy],
.crew-member__who[b-kudi9n4wmy] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.day-report__name[b-kudi9n4wmy],
.crew-member__name[b-kudi9n4wmy] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

.day-report__company[b-kudi9n4wmy],
.crew-member__company[b-kudi9n4wmy] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.day-report__hours[b-kudi9n4wmy] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    margin-left: auto;
}

.day-report__unit[b-kudi9n4wmy] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
}
/* /Features/Manage/ManageTabs.razor.rz.scp.css */
/* A scrolling strip rather than a wrapping one. Three tabs fit at 320px, so it never actually
   scrolls today - but a fourth would push the third onto its own line and make the strip look like
   two rows of navigation, which is worse than a strip that scrolls. */
.manage-tabs[b-e2hp5mhrbc] {
    display: flex;
    gap: var(--space-1);
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-1);
    border-bottom: var(--border-width) solid var(--color-border);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.manage-tabs__tab[b-e2hp5mhrbc] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
    white-space: nowrap;

    /* Sits over the container's bottom rule, so the selected tab joins the page below it rather than
       floating above a line that runs straight through. */
    margin-bottom: calc(var(--space-1) * -1 - var(--border-width));
    border-bottom: 2px solid transparent;
}

.manage-tabs__tab:hover[b-e2hp5mhrbc] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
    color: var(--color-text);
    text-decoration: none;
}

.manage-tabs__tab--on[b-e2hp5mhrbc] {
    border-bottom-color: var(--color-accent);
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
}

.manage-tabs__tab--on:hover[b-e2hp5mhrbc] {
    color: var(--color-text);
}

/* The waiting count. Warning-toned rather than danger: work waiting to be approved is the ordinary
   state of a working site, not a failure - danger is reserved for what did not happen. */
.manage-tabs__count[b-e2hp5mhrbc] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.5rem;
    padding: 0 var(--space-1);
    border-radius: var(--radius-full);
    background-color: var(--color-warning-subtle);
    color: var(--color-warning-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}
/* /Features/Manage/OnSite/DayPicker.razor.rz.scp.css */
/* =============================================================================
   ONE DOM, TWO SHAPES
   -----------------------------------------------------------------------------
   A month is always thirty-seven cells - the six columns of padding a month
   starting on a Sunday needs, plus the thirty-one days of the longest month - so
   every month is one row of the same width and the same weekday sits in the same
   column in every row. A rotation is then a stripe down the strip rather than
   something to be counted, and one weekday header across the top labels every row
   at once.

   Below the phone breakpoint the identical cell sequence wraps at seven instead.
   Nothing is re-rendered and nothing is re-ordered: only the number of columns
   changes, and the per-month header of seven letters takes over from the one of
   thirty-seven. A calendar whose columns move is not a calendar, but neither is
   one that is four screens wide in a glove.
   ============================================================================= */

.day-picker[b-wqjkmc5hks] {
    /* One cell's width, the two gutters between cells, the left column every month
       writes its name in, and the thirty-seven day columns themselves - written
       once so the weekday header and every month's row cannot drift apart, because
       they are literally the same tracks.

       THE TWO GUTTERS ARE DIFFERENT SIZES ON PURPOSE. Across, the gutter is paid for
       thirty-six times in a row that is already the widest thing on the screen, so it
       is the smaller of the two. Down, it is paid once per month and separates rows
       that carry a whole month's meaning, so it is double - which is what stops three
       stacked months reading as one block of squares. */
    --day-picker-cell: 1.6875rem;
    --day-picker-gap-x: var(--space-1);
    --day-picker-gap-y: var(--space-2);
    --day-picker-label: 8rem;
    --day-picker-columns: repeat(37, var(--day-picker-cell));

    display: flex;
    flex-direction: column;
    gap: var(--space-4);

    /* Below the breakpoint base.css turns the detail cell into a grid, and a grid
       item's automatic minimum size is its content - without this the strip would
       push the whole page sideways instead of scrolling inside its own box. */
    min-width: 0;
}

.day-picker__head[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.day-picker__title[b-wqjkmc5hks] {
    margin: 0;
    font-size: var(--font-size-base);
}

.day-picker__loading[b-wqjkmc5hks] {
    margin: 0;
    color: var(--color-text-secondary);
}

/* -----------------------------------------------------------------------------
   The question
   -----------------------------------------------------------------------------
   One element carrying three sentences - the instruction, the half-made run, and
   the answers - because it is a live region and a live region has to exist before
   it has something to announce. The edge on its left is what changes between the
   three: quiet while it is only instructing, amber while it is holding half a
   sentence somebody has to finish, accent once there is something to answer.
   ----------------------------------------------------------------------------- */

.day-picker__bar[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) 0 var(--space-2) var(--space-3);
    border-left: 3px solid var(--color-border);
}

.day-picker__bar--armed[b-wqjkmc5hks] {
    border-left-color: var(--color-warning-text);
    background-color: var(--color-warning-subtle);
    padding-right: var(--space-3);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.day-picker__bar--chosen[b-wqjkmc5hks] {
    border-left-color: var(--color-accent);
    background-color: var(--color-info-subtle);
    padding-right: var(--space-3);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.day-picker__question[b-wqjkmc5hks] {
    margin: 0;
    max-width: 60ch;
    color: var(--color-text-secondary);
}

.day-picker__bar--armed .day-picker__question[b-wqjkmc5hks],
.day-picker__bar--chosen .day-picker__question[b-wqjkmc5hks] {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

.day-picker__answers[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

/* FOUR CONTROLS ANSWERING ONE QUESTION LOOK LIKE ONE KIND OF THING. One class, one
   height, and the swatch each carries is the fill it will paint - so none of them
   is louder than the others and taking a claim back is as ordinary an answer as
   making one. */
.day-picker__answer[b-wqjkmc5hks] {
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    font-size: var(--font-size-sm);
}

/* Travelling is the one of the four that is a toggle, so it alone can be pressed.
   It takes the stone it paints rather than the accent the chosen days wear, because
   what it says is "these days are travelling days" and not "these days are chosen". */
.day-picker__answer[aria-pressed="true"][b-wqjkmc5hks] {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary-text);
    color: var(--color-on-secondary);
    font-weight: var(--font-weight-semibold);
}

/* Travelling applies ON TOP of the answer beside it rather than instead of one, and
   this thin line is what says so. */
.day-picker__separator[b-wqjkmc5hks] {
    align-self: stretch;
    width: var(--border-width);
    min-height: var(--layout-touch-target-min);
    background-color: var(--color-border);
}

.day-picker__swatch[b-wqjkmc5hks] {
    flex: none;
    width: 1rem;
    height: 1rem;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-sm);
}

/* -----------------------------------------------------------------------------
   The strip
   ----------------------------------------------------------------------------- */

/* The wide shape scrolls inside its own box rather than shrinking its cells into
   nothing. The page itself must never scroll sideways. */
.day-picker__scroll[b-wqjkmc5hks] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;

    /* A sideways flick that reaches the end of the strip must not turn into the
       browser's own back gesture, which on a phone loses whatever the reader was in
       the middle of. */
    overscroll-behavior-x: contain;
    padding-bottom: var(--space-2);
}

.day-picker__rows[b-wqjkmc5hks] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--day-picker-gap-y);
    width: max-content;
}

/* One header for the whole strip, pushed clear of the column the months write
   their names in so its letters sit over the cells they name.

   It takes the ACROSS gutter, and it has to be that one: this is a single row of
   letters that have to land over the cells they name, so a gutter of any other size
   walks them off their columns one day at a time. */
.day-picker__columns[b-wqjkmc5hks] {
    display: grid;
    grid-template-columns: var(--day-picker-columns);
    gap: var(--day-picker-gap-x);
}

.day-picker__columns--wide[b-wqjkmc5hks] {
    padding-inline-start: calc(var(--day-picker-label) + var(--space-3));
}

/* The narrow shape's own seven letters. Hidden until the strip wraps, where the one
   header at the top would be scrolled off the moment the reader reached October. */
.day-picker__columns--narrow[b-wqjkmc5hks] {
    display: none;
}

.day-picker__weekday[b-wqjkmc5hks] {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-muted);
}

/* The month's name and its days are one row of one grid, so the name cannot drift
   out of line with the cells beside it. */
.day-picker__month[b-wqjkmc5hks] {
    display: grid;
    grid-template-columns: var(--day-picker-label) 1fr;
    gap: var(--day-picker-gap-y) var(--space-3);
    align-items: center;
}

/* THE MONTH'S NAME IS THE CONTROL THAT FOLDS IT. Quiet enough to read as a label -
   it is one, most of the time - and a real button because it does something. */
.day-picker__month-name[b-wqjkmc5hks] {
    display: flex;
    align-items: baseline;

    /* base.css centres every button's content, which on a fixed-width label column puts each month's
       name in a different place - the longer the name, the further left it starts - and the column
       stops reading as a column. */
    justify-content: flex-start;
    gap: var(--space-2);
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    text-align: left;
    white-space: nowrap;
}

.day-picker__month-name:hover:not(:disabled)[b-wqjkmc5hks] {
    background-image: none;
    color: var(--color-text);
}

.day-picker__month-chevron[b-wqjkmc5hks] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* The summary only earns its space once the month it belongs to is folded away. */
.day-picker__month-summary[b-wqjkmc5hks] {
    display: none;
    font-weight: var(--font-weight-regular);
    color: var(--color-text-muted);
}

.day-picker__month--shut .day-picker__month-summary[b-wqjkmc5hks] {
    display: inline;
}

.day-picker__month--shut .day-picker__cells[b-wqjkmc5hks],
.day-picker__month--shut .day-picker__columns--narrow[b-wqjkmc5hks] {
    display: none;
}

.day-picker__cells[b-wqjkmc5hks] {
    display: grid;
    grid-template-columns: var(--day-picker-columns);
    gap: var(--day-picker-gap-y) var(--day-picker-gap-x);
}

/* -----------------------------------------------------------------------------
   One day
   ----------------------------------------------------------------------------- */

.day[b-wqjkmc5hks] {
    display: flex;
    align-items: center;
    justify-content: center;

    /* Every one of these beats a global button rule that would otherwise make the
       cell 2.75rem tall with 1rem of padding inside it - the shape SiteMapEditor
       documents, where a button was "there, sized, clickable and completely blank". */
    min-height: var(--day-picker-cell);
    padding: 0;
    gap: 0;

    /* The edge is the whole of a day nobody has answered for - there is no fill behind it - so it is
       the strong border rather than the hairline one. These are the days the screen exists to get
       answered; they must not be the hardest cells on the calendar to see. */
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--color-surface-container);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

button.day[b-wqjkmc5hks] {
    cursor: pointer;
}

.day__number[b-wqjkmc5hks] {
    /* Above the diagonal a travelling day paints behind it. */
    position: relative;
    z-index: 1;
}

/* Padding, not a day. It holds its column so the weekdays line up and says nothing. */
.day--blank[b-wqjkmc5hks] {
    border-color: transparent;
    background-color: transparent;
}

/* -----------------------------------------------------------------------------
   THE FILLS, AND WHY A PLANNED DAY IS NOT THE SAME COLOUR AS A RECORDED ONE
   -----------------------------------------------------------------------------
   A day that has happened takes the fill whole. A day still to come takes the same
   colour washed out, behind a dashed edge - recorded, correct, and a plan. Two
   channels for one distinction, because the edge alone is a hairline on a 27px box
   and the wash alone is a hue difference somebody in sunlight will not see.

   Certainty is never the hue itself: on site is green whether it happened or not.
   What changes is weight, which is what tells a register from a rota.
   ----------------------------------------------------------------------------- */

.day--past[b-wqjkmc5hks] {
    border-style: solid;
}

.day--future[b-wqjkmc5hks] {
    border-style: dashed;
}

.day--on-site[b-wqjkmc5hks] {
    border-color: var(--color-success-text);
    background-color: var(--color-success);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-semibold);
}

.day--on-site.day--future[b-wqjkmc5hks] {
    background-color: var(--color-success-subtle);
    color: var(--color-success-text);
}

.day--off-site[b-wqjkmc5hks] {
    border-color: var(--color-info-text);
    background-color: var(--color-info);
    color: var(--color-on-primary);
}

.day--off-site.day--future[b-wqjkmc5hks] {
    background-color: var(--color-info-subtle);
    color: var(--color-info-text);
}

/* TRAVELLING HAS ITS OWN FILL, AND SHARES THE CELL WHEN IT HAS TO. A day spent only
   getting somewhere is off site and travelling - nobody stood on the site - so it
   takes the stone whole. A day spent travelling TO the site is two true things at
   once, they travelled and they arrived, so the cell keeps its on-site fill and
   gives half of itself over to the stone on the diagonal.

   The half is a clipped overlay rather than a background-image, because base.css
   paints hover and press as a background-image layer over whatever fill an element
   has, and that would replace a gradient outright on the first hover. */
.day--travel-off-site[b-wqjkmc5hks] {
    border-color: var(--color-secondary-text);
    background-color: var(--color-secondary);
    color: var(--color-on-secondary);
}

.day--travel-off-site.day--future[b-wqjkmc5hks] {
    background-color: var(--color-secondary-subtle);
    color: var(--color-secondary-text);
}

.day--travel-on-site[b-wqjkmc5hks] {
    position: relative;
    overflow: hidden;
    border-color: var(--color-success-text);
    background-color: var(--color-success);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-semibold);
}

.day--travel-on-site[b-wqjkmc5hks]::before {
    content: "";
    position: absolute;
    inset: 0;
    background-color: var(--color-secondary);
    clip-path: polygon(100% 0, 100% 100%, 0 100%);
}

.day--travel-on-site.day--future[b-wqjkmc5hks] {
    background-color: var(--color-success-subtle);
    color: var(--color-success-text);
}

.day--travel-on-site.day--future[b-wqjkmc5hks]::before {
    background-color: var(--color-secondary-subtle);
}

/* The hover wash would land underneath that overlay and light one half of the cell
   and not the other, which reads as a rendering fault. These cells answer a pointer
   with their border instead, which base.css changes anyway. */
.day--travel-on-site:hover:not(:disabled)[b-wqjkmc5hks],
.day--travel-on-site:active:not(:disabled)[b-wqjkmc5hks] {
    background-image: none;
}

/* NOT RECORDED HAS NO FILL, deliberately. These are the days the screen exists to
   get answered, and an amber wash behind a third of the calendar would read as a
   warning about each day rather than as the gap the summary above already counts. */
.day--unrecorded[b-wqjkmc5hks] {
    background-color: var(--color-surface-container);
    color: var(--color-text-muted);
}

/* Today, ringed from outside the cell so it survives every fill and every edge
   style underneath it. The ring is drawn outward and the chosen outline inward, so
   a day that is both still says both. */
.day--today[b-wqjkmc5hks] {
    box-shadow: 0 0 0 2px var(--color-accent);
    position: relative;
    z-index: 1;
}

.day--today .day__number[b-wqjkmc5hks] {
    font-weight: var(--font-weight-bold);
}

/* Chosen, and not yet answered for. An outline rather than another fill, because the
   fill is what the day already is and the reader needs to see both at once. */
.day--chosen[b-wqjkmc5hks] {
    outline: 1.5px solid var(--color-accent);
    outline-offset: -1.5px;
    position: relative;
    z-index: 2;
}

/* The first tap on its own, while the run is half a sentence. Amber, matching the
   bar that is at that moment asking for the second tap. */
.day--anchor[b-wqjkmc5hks] {
    outline-color: var(--color-warning-text);
    outline-style: dashed;
}

/* -----------------------------------------------------------------------------
   ... and onwards, until this changes
   ----------------------------------------------------------------------------- */

/* Outside the scrolling strip and the full width of the panel, because it is not a
   column of anything - it is the rest of time, and a cell that size would look like
   a thirty-eighth day. Dashed like every other day that has not happened yet. */
.day-picker__onwards[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
    width: 100%;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-4);
    border: var(--border-width) dashed var(--color-border-strong);
    border-radius: var(--radius-md);
    text-align: left;
}

.day-picker__onwards-name[b-wqjkmc5hks] {
    font-weight: var(--font-weight-medium);
}

.day-picker__onwards-state[b-wqjkmc5hks] {
    font-size: var(--font-size-sm);
}

.day-picker__onwards--chosen[b-wqjkmc5hks] {
    outline: 1px solid var(--color-accent);
    outline-offset: -1px;
}

/* -----------------------------------------------------------------------------
   The key
   -----------------------------------------------------------------------------
   A row under the calendar rather than a dialog behind a button. It was a dialog
   while the fills were four; with certainty carried on the edge as well there are
   seven things to tell apart, and a key you have to remember having opened is a key
   nobody opens twice.
   ----------------------------------------------------------------------------- */

.day-picker__legend[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.day-picker__key[b-wqjkmc5hks] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* -----------------------------------------------------------------------------
   Which months are drawn, and the way back out of a mistake
   -----------------------------------------------------------------------------
   A quiet row under the strip rather than a control beside each month: these are
   decisions about the whole calendar, made rarely, and four quiet buttons in a line
   are easier to ignore than four chevrons the eye has to step over on every row.
   ----------------------------------------------------------------------------- */

.day-picker__tools[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.day-picker__tool[b-wqjkmc5hks] {
    min-height: 2rem;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
}

/* -----------------------------------------------------------------------------
   What saving would write
   -----------------------------------------------------------------------------
   The same grouping the request is built from, so the list a reader checks and the
   legs the server receives cannot describe different things.
   ----------------------------------------------------------------------------- */

.day-picker__writes[b-wqjkmc5hks] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.day-picker__writes-title[b-wqjkmc5hks] {
    margin: 0;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.day-picker__writes-line[b-wqjkmc5hks] {
    margin: 0;
    color: var(--color-text-secondary);
}

.day-picker__stints[b-wqjkmc5hks] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One stay per row, with the same edge the calendar paints it in, so a reader
   checking the list against the strip is matching colours and not dates. */
.day-picker__stint[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
    padding-left: var(--space-3);
    border-left: 3px solid var(--color-border);
    font-size: var(--font-size-sm);
}

.day-picker__stint--on-site[b-wqjkmc5hks] {
    border-left-color: var(--color-success-text);
}

.day-picker__stint--off-site[b-wqjkmc5hks] {
    border-left-color: var(--color-info-text);
}

/* The tense, in the same uppercase micro-type the rest of the app labels things
   with. Dashed for a stay that has not begun, which is the edge the calendar uses
   for the same fact about the same days. */
.day-picker__tense[b-wqjkmc5hks] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-1);
}

.day-picker__stint--planned .day-picker__tense[b-wqjkmc5hks] {
    border-style: dashed;
    border-color: var(--color-info-text);
    color: var(--color-info-text);
}

.day-picker__travel-tag[b-wqjkmc5hks] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-secondary-text);
    border: var(--border-width) solid var(--color-secondary-text);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-1);
}

.day-picker__when[b-wqjkmc5hks] {
    font-variant-numeric: tabular-nums;
}

.day-picker__length[b-wqjkmc5hks] {
    margin-left: auto;
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}

/* -----------------------------------------------------------------------------
   Save
   -----------------------------------------------------------------------------
   The only control on this panel that reaches the server, which is why it is the
   only filled one. It is deliberately NOT sticky: the question bar is, and on a
   phone two elements pinned to the bottom of the same screen land on top of one
   another exactly when both matter - while a run is chosen and waiting for an
   answer.
   ----------------------------------------------------------------------------- */

.day-picker__savebar[b-wqjkmc5hks] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding-top: var(--space-3);
    padding-bottom: var(--layout-safe-bottom);
    border-top: var(--border-width) solid var(--color-border);
    background-color: var(--color-surface-inset);
}

.day-picker__changed[b-wqjkmc5hks] {
    margin-left: auto;
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
    color: var(--color-text-secondary);
}

/* =============================================================================
   FINGERS, NOT A POINTER
   -----------------------------------------------------------------------------
   48rem is --bp-md, the width at which the roster table itself becomes cards and
   the app is being used outdoors on a phone. The same cells in the same order wrap
   at seven, the months stack, and every cell grows to the app's own touch minimum.
   It is written as a literal because a custom property in a media query is invalid
   CSS and silently never matches - tokens.css says so explicitly.
   ============================================================================= */

@media (max-width: 48rem) {
    .day-picker[b-wqjkmc5hks] {
        /* Both gutters are named here, because the wide shape's reason for keeping the
           across one small is gone: seven columns pay for six gutters rather than
           thirty-six, and nothing scrolls sideways any more. Down stays the larger of
           the two - here it separates the weeks inside a month as well as the months. */
        --day-picker-gap-x: var(--space-1);
        --day-picker-gap-y: var(--space-2);
        --day-picker-columns: repeat(7, minmax(0, 1fr));
    }

    /* Nothing scrolls sideways any more, so nothing needs a box to scroll inside. */
    .day-picker__scroll[b-wqjkmc5hks] {
        overflow-x: visible;
    }

    .day-picker__rows[b-wqjkmc5hks] {
        width: auto;
        align-items: stretch;
        gap: var(--space-5);
    }

    .day-picker__columns--wide[b-wqjkmc5hks] {
        display: none;
    }

    .day-picker__columns--narrow[b-wqjkmc5hks] {
        display: grid;
        margin-bottom: var(--space-1);
    }

    .day-picker__month[b-wqjkmc5hks] {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-2);
        align-items: start;
    }

    .day-picker__month-name[b-wqjkmc5hks] {
        min-height: var(--layout-touch-target-min);
        align-items: center;
        font-size: var(--font-size-base);
    }

    /* The padding past the end of a month is up to six cells of nothing, which in a
       seven-column grid is an empty row under the month rather than the tail of a
       long row beside it. */
    .day--blank-end[b-wqjkmc5hks] {
        display: none;
    }

    .day[b-wqjkmc5hks] {
        min-height: var(--layout-touch-target-min);
        border-radius: var(--radius-md);
        font-size: var(--font-size-sm);
    }

    .day-picker__onwards[b-wqjkmc5hks] {
        justify-content: center;
    }

    /* The question follows the reader down a calendar taller than the screen, and
       the answers with it - on a phone the days being answered for are usually off
       the top by the time the bar is read. */
    .day-picker__bar--armed[b-wqjkmc5hks],
    .day-picker__bar--chosen[b-wqjkmc5hks] {
        position: sticky;
        bottom: 0;
        z-index: 3;
        box-shadow: var(--shadow-md);
    }

    .day-picker__answers[b-wqjkmc5hks] {
        margin-left: 0;
        width: 100%;
    }

    .day-picker__answer[b-wqjkmc5hks] {
        flex: 1 1 auto;
        justify-content: center;
        min-height: var(--layout-touch-target-min);
    }

    .day-picker__separator[b-wqjkmc5hks] {
        display: none;
    }

    .day-picker__length[b-wqjkmc5hks] {
        margin-left: 0;
    }
}
/* /Features/Manage/OnSite/ParticipationEditor.razor.rz.scp.css */
/* Three questions, asked in order: where, why, for how long. Each grouping is a <fieldset> so it is
   real to a screen reader and not only visual. */

.participation-editor[b-wxo4rhj7ht] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.participation-editor__group[b-wxo4rhj7ht] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    /* A fieldset carries a default min-width that stops its contents shrinking, which makes the panel
       push the page sideways on a phone. */
    min-width: 0;
}

.participation-editor__group > legend[b-wxo4rhj7ht] {
    font-weight: var(--font-weight-semibold);
    padding-inline: var(--space-2);
}

.participation-editor__note[b-wxo4rhj7ht] {
    margin: 0;
    color: var(--color-text-secondary);
}

/* ---------------------------------------------------------------- where */

.participation-editor__kinds[b-wxo4rhj7ht] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The label is the whole card, so the consequence is part of what the reader taps - the choice and
   what it does to the headcount are one thing, and separating them is how somebody picks the wrong
   one. */
.participation-editor__kind[b-wxo4rhj7ht] {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    cursor: pointer;
}

.participation-editor__kind:hover[b-wxo4rhj7ht] {
    background-color: var(--color-state-hover);
}

.participation-editor__kind--chosen[b-wxo4rhj7ht] {
    border-color: var(--color-primary);
    background-color: var(--color-surface-inset);
}

.participation-editor__kind-body[b-wxo4rhj7ht] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.participation-editor__kind-name[b-wxo4rhj7ht] {
    font-weight: var(--font-weight-semibold);
}

.participation-editor__kind-description[b-wxo4rhj7ht] {
    color: var(--color-text-secondary);
}

/* ---------------------------------------------------------------- for how long */

/* Two across where there is room, stacked on a phone. No media query: the min() keeps a single column
   below roughly a 24rem panel, which is where two date inputs stop being usable side by side. */
.participation-editor__dates[b-wxo4rhj7ht] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
    gap: var(--space-3);
}

.participation-editor__actions[b-wxo4rhj7ht] {
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* Set apart from Cancel, and worded rather than iconised, because it is the only control here that
   destroys a row. Not danger-red: it is the correct action for a typo, and a red button teaches
   people to hesitate over the routine case. */
.participation-editor__remove[b-wxo4rhj7ht] {
    margin-inline-start: auto;
    color: var(--color-danger-text);
}
/* /Features/Manage/OnSite/TransitionPanel.razor.rz.scp.css */
.transition[b-gh22f3kibv] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-width: 34rem;
}

.transition__question[b-gh22f3kibv] {
    margin: 0;
}

/* Two choices, side by side, both full-height targets. Not a dropdown: there are two of them and one
   is pressed far more often than the other, so hiding either behind a click would be worse. */
.transition__choices[b-gh22f3kibv] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.transition__choice[b-gh22f3kibv] {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.transition__choice:hover[b-gh22f3kibv] {
    background-color: var(--color-state-hover);
}

.transition__choice--chosen[b-gh22f3kibv] {
    border-color: var(--color-primary);
    background-color: var(--color-surface-inset);
}

.transition__actions[b-gh22f3kibv] {
    flex-wrap: wrap;
    gap: var(--space-2);
}
/* /Features/Manage/Pages/Approvals.razor.rz.scp.css */
.approvals__count[b-q9186madx7] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.approvals__list[b-q9186madx7] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}
/* /Features/Manage/Pages/Dashboard.razor.rz.scp.css */
/* The whole screen is tighter than the rest of the application on purpose. This is the one page
   somebody keeps open all day, and what is below the fold on it is not read. */
.dashboard[b-0tunckhz24] {
    --dashboard-gap: var(--space-4);
}

/* ------------------------------------------------------------------ the bell */

/* The two standing banners, folded into a count. Sized as a real target - it is in the header row
   beside two text buttons and has to be reachable with a thumb. */
.dashboard__bell[b-0tunckhz24] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-md);
    background-color: var(--color-warning-subtle);
    color: var(--color-text);
    cursor: pointer;
}

.dashboard__bell:hover[b-0tunckhz24] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
}

.dashboard__bell--open[b-0tunckhz24] {
    border-color: var(--color-warning-text);
}

.dashboard__bell-count[b-0tunckhz24] {
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.dashboard__notices[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* ---------------------------------------------------------------- who is here */

/* ------------------------------------------------------------------ the two queues */

/* Level on a desktop, stacked below it. Both are lists of a handful of rows, so neither earns the
   full width - and side by side means the two things waiting on a person are one glance apart
   rather than one scroll. The min-width is what makes it collapse on a tablet without a query. */
.dashboard__columns[b-0tunckhz24] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(26rem, 100%), 1fr));
    gap: var(--dashboard-gap);
    align-items: start;
}

.dashboard__block[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.dashboard__block-heading[b-0tunckhz24] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--font-size-base);
}

/* The same count treatment the tab strip uses, down to the token, so "4" looks and means the same
   thing in both places rather than being two badges that happen to be near each other. */
.dashboard__block-count[b-0tunckhz24] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.5rem;
    padding: 0 var(--space-1);
    border-radius: var(--radius-full);
    background-color: var(--color-warning-subtle);
    color: var(--color-warning-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

/* Secondary to the heading and on the same line - a total that qualifies the title rather than a
   figure of its own. */
.dashboard__block-note[b-0tunckhz24] {
    margin-inline-start: auto;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    color: var(--color-text-secondary);
}

.dashboard__rows[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* "The 55 older days are under Approvals" - said, not linked. The tab strip is directly above and
   carries the count, and a second route to it here would be the signpost this screen stopped being
   made of. */
.dashboard__more[b-0tunckhz24],
.dashboard__empty[b-0tunckhz24] {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}


/* ---------------------------------------------------------------- who is here */

/* THREE COLUMNS, NAMES NOT COUNTS. A site manager's next question after "how many" is always "who",
   so the names are the answer and the count is the caption. Level on a desktop, stacked below it,
   by the same minmax the queues use - narrower, because these are short lines. */
.crew[b-0tunckhz24] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
    gap: var(--dashboard-gap);
    align-items: start;
}

.crew__column[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.crew__heading[b-0tunckhz24] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--font-size-base);
}

.crew__count[b-0tunckhz24] {
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-weight-semibold);
}

/* "next 3 days" qualifies the heading rather than being part of it, so the column is still called
   Arriving when the eye skims the row of three. */
.crew__horizon[b-0tunckhz24] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--color-text-muted);
}

/* No cap here - the box owns the height and crew__scroll owns the overflow, so a list and a set of
   dated groups behave the same way inside the same frame.

   No negative inline margin to widen the rows under the buttons: crew__scroll sets overflow-y, which
   makes the other axis scrollable too, so anything wider than the frame buys a horizontal scrollbar
   in a column of names. The buttons take their padding vertically only for the same reason. */
.crew__people[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One person a line: name, then firm beside it in the space left over. Compact on purpose - this is
   a roll call, and a card per person would be four names to a screen.

   A BUTTON RATHER THAN A LINE OF TEXT, because the question these columns raise is always about one
   of the names in them, and the answer now opens in place. Styled as the line it replaced - no
   border, no fill, the parent's own text - so the columns still read as a roll call rather than as
   three stacks of controls. What says it is clickable is the hover and the pointer, which is enough
   for a list where every row behaves the same way. */
.crew__person[b-0tunckhz24] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
    width: 100%;
    min-width: 0;
    margin: 0;

    /* MIN-HEIGHT: 0 IS THE ONE THAT MATTERS. base.css gives every <button> a 2.75rem minimum, which
       is the right default - it is the touch target size, and a control somebody has to hit with a
       thumb should be that big. It is wrong here, and only here, because these are not controls in a
       form: they are a roll call, twenty names to a column, and at 2.75rem apiece a frame that used to
       hold eight held four.

       Zeroing the padding was not enough on its own and looked like it should have been. The row is
       its line box now and nothing more; the hover wash spans the full width of the column, which is
       signal enough on a list where every row behaves identically.

       The size lost is bought back by the whole row being the target rather than the words in it - a
       full-width band at text height is a bigger thing to hit than most buttons on the screen. */
    min-height: 0;
    padding: 0;
    border: 0;

    /* The global rule centres a button's content. Here the firm name takes the slack, so it never
       showed - but a person with no firm would have had their name drift to the middle of the row. */
    justify-content: flex-start;
    border-radius: var(--radius-sm);
    background: none;
    color: inherit;
    font: inherit;
    line-height: var(--line-height-tight);
    text-align: start;
    cursor: pointer;
}

/* The tinted columns already carry a background, so the hover has to be a wash over whatever tone
   is underneath rather than a colour of its own - the same trick the bell uses. */
.crew__person:hover[b-0tunckhz24] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
}

.crew__person:focus-visible[b-0tunckhz24] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 1px;
}

/* THE ONLY THING ON A PHONE THAT SAYS THESE ROWS DO ANYTHING. The hover wash and the pointer cursor
   above are both mouse-only, so the first version of this shipped a list of touch targets that
   looked exactly like the plain text it replaced - on the device where these columns are read most.
   A chevron is the smallest thing that says "this opens something" without a hover, and it earns its
   width on a desktop too.

   ::deep because AppIcon renders the svg, and CSS isolation only stamps this file's own markup - see
   the note at the top of NavMenu.razor.css for the full version of that trap. */
.crew__person[b-0tunckhz24]  .app-icon {
    flex: 0 0 auto;

    /* Centred rather than left to the row's baseline alignment. An svg has no baseline, so browsers
       align its bottom edge to one - which pushes the line box taller and costs the column the height
       this rule was careful not to spend. */
    align-self: center;
    width: 0.875rem;
    height: 0.875rem;
    color: var(--color-text-muted);
}

.crew__name[b-0tunckhz24] {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* Truncated rather than wrapped. Norwegian firm names are long, and a second line per person would
   double the height of a list whose whole job is to be short. The full name is in the tooltip the
   browser gives an overflowing element. */
.crew__firm[b-0tunckhz24] {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* The date a group of people arrive or leave on, written once above them. */
.crew__day[b-0tunckhz24] {
    margin: var(--space-2) 0 0;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.crew__day:first-of-type[b-0tunckhz24] {
    margin-top: 0;
}

.crew__empty[b-0tunckhz24] {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* The count above is only as true as the roster behind it. Warning-coloured because it is the one
   thing in this row that is a defect rather than a reading. */
.crew__gap[b-0tunckhz24] {
    margin: 0;
    padding-top: var(--space-2);
    border-top: var(--border-width) solid var(--color-border);
    font-size: var(--font-size-sm);
}

.crew__gap a[b-0tunckhz24] {
    color: var(--color-warning-text);
}

/* ---------------------------------------------------------------- out of the card */

/* Sits at the end of the heading row, like the mine/all toggle below and for the same reason: the
   section says what it is and offers the one thing to do about it on the same line, rather than
   spending a row on it.

   A real target rather than a word, because the reader most likely to want it is holding a phone and
   has just seen that two of their own days were never sent. The negative inline margin pays the
   padding back to the heading, so the link is bigger to tap without the row growing. */
.dashboard__link[b-0tunckhz24] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-inline-start: auto;
    margin-inline-end: calc(var(--space-2) * -1);

    /* Same trick as the toggle below, and for the same reason: the padding makes it a target, the
       negative block margin keeps the heading row the height of its own words. An <a> escapes the
       global button minimum, so only the padding had to be paid back here. */
    margin-block: calc(var(--space-1) * -1);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    white-space: nowrap;
}

.dashboard__link:hover[b-0tunckhz24] {
    background-color: var(--color-state-hover);
    text-decoration: none;
}

/* ::deep because AppIcon renders the svg - see the note at the top of NavMenu.razor.css. */
.dashboard__link[b-0tunckhz24]  .app-icon {
    width: 0.875rem;
    height: 0.875rem;
}

/* ---------------------------------------------------------------- mine or all */

/* Sits at the end of the heading row, so the section says what it is showing and offers the other
   view in one line rather than spending a row on a filter strip. */
/* A BIG TARGET THAT TAKES UP NO ROOM. The heading row is baseline-aligned, so anything taller than
   the words in it makes the whole row taller - and base.css gives every button a 2.75rem minimum,
   which was silently setting the height of this heading and leaving it taller than the Approvals one
   beside it.

   Padding plus an equal negative block margin is the way to have both: the border box stays a
   comfortable thing to hit with a thumb, and the margin box - which is what the flex line measures -
   is only as tall as the text. The crew rows solve the same problem the other way, by being
   full-width bands; there is no width to spare here. */
.dashboard__toggle[b-0tunckhz24] {
    margin-inline-start: auto;
    margin-block: calc(var(--space-2) * -1);
    min-height: 0;
    padding: var(--space-2) 0;
    border: 0;
    background: none;
    color: var(--color-accent);
    font-size: var(--font-size-sm);
    cursor: pointer;
    text-decoration: underline;
}

.dashboard__toggle:hover[b-0tunckhz24] {
    color: var(--color-accent-hover);
}

/* ---------------------------------------------------------------- fixed frames */

/* EVERY BOX IS THE SAME HEIGHT AS ITS NEIGHBOUR AND SCROLLS INSIDE. Before this the three crew
   columns and the two queues were each as tall as their contents, so the row was ragged, the page
   grew with whatever happened to be busiest, and Approvals alone could be a screen and a half.

   A fixed frame trades some empty space in a quiet column for a layout that does not move: the same
   things are in the same places whether four people are on site or forty, which is what makes a
   screen readable at a glance rather than one that has to be re-parsed on every visit. */
.crew__column[b-0tunckhz24] {
    height: 15rem;
}

.dashboard__block[b-0tunckhz24] {
    height: 26rem;
}

/* The block below the two queues is a chart and sizes itself, so it is exempt: a heatmap with a
   scrollbar would be a chart nobody can read whole. */
.dashboard__block--auto[b-0tunckhz24] {
    height: auto;
}

/* The moving middle of a fixed frame. Headings above it and footnotes below it stay put, so the
   count of what is off screen is never itself off screen. */
.crew__scroll[b-0tunckhz24],
.dashboard__scroll[b-0tunckhz24] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.crew__scroll[b-0tunckhz24] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* ---------------------------------------------------------------- the three tones */

/* Green for who is here, blue for who is coming, amber for who is going - the application's own
   success, info and warning, in their subtle variants so the colour is a wash rather than a state.
   Every one of the three is defined in both themes, so this reads the same in dark. */
.crew__column--here[b-0tunckhz24] {
    border-color: var(--color-success);
    background-color: var(--color-success-subtle);
}

.crew__column--in[b-0tunckhz24] {
    border-color: var(--color-info);
    background-color: var(--color-info-subtle);
}

.crew__column--out[b-0tunckhz24] {
    border-color: var(--color-warning);
    background-color: var(--color-warning-subtle);
}

/* The gap line sits on a tinted ground now, so its rule has to be the tone's own border rather than
   the neutral one, which disappears against it. */
.crew__column .crew__gap[b-0tunckhz24] {
    border-top-color: currentColor;
    opacity: 0.9;
}
/* /Features/Manage/Pages/OnSite.razor.rz.scp.css */
/* The summary, and it gets the weight. This is the only block on the screen allowed to be loud,
   because it is the only one that says whether there is anything left to do. The same shape the site
   overview's attention block uses, for the same reason: a reader should not have to compare three
   equal tiles to work out which of them is asking for something. */
.participation-summary[b-lei78or9ya] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-lg);
    background-color: var(--color-warning-subtle);
}

/* Nothing left unanswered. Not success-coloured: a complete roster is the ordinary state of a site
   somebody is keeping up with, so it reads as calm rather than as congratulation. */
.participation-summary:has(.participation-summary__lead--clear)[b-lei78or9ya] {
    border-color: var(--color-border);
    background-color: var(--color-surface-container);
}

.participation-summary__lead[b-lei78or9ya] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
}

.participation-summary__headline[b-lei78or9ya] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.participation-summary__text[b-lei78or9ya] {
    margin: 0;
    max-width: 60ch;
    color: var(--color-text-secondary);
}

/* Styled as the primary button base.css defines rather than as a link: it is the action the block
   exists to offer, and an underlined phrase is not a target for a gloved thumb. */
.participation-summary__action[b-lei78or9ya] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-5);
    border: var(--border-width) solid var(--color-primary);
    border-radius: var(--radius-md);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-medium);
}

.participation-summary__action:hover[b-lei78or9ya],
.participation-summary__action:focus-visible[b-lei78or9ya] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
}

/* auto-fit rather than a fixed count: three across on a laptop, one on a phone, no media query. */
.participation-summary__figures[b-lei78or9ya] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(8rem, 100%), 1fr));
    gap: var(--space-4);
    margin: 0;
}

/* A rule under each number in the colour its badge carries in the table, so a figure here means the
   same thing as the row it is a count of. */
.figure[b-lei78or9ya] {
    border-top: 3px solid var(--color-border);
    padding-top: var(--space-2);
}

.figure dt[b-lei78or9ya] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.figure dd[b-lei78or9ya] {
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
}

.figure--on-site[b-lei78or9ya] { border-top-color: var(--color-success); }
.figure--elsewhere[b-lei78or9ya] { border-top-color: var(--color-info); }
.figure--unrecorded[b-lei78or9ya] { border-top-color: var(--color-warning); }

/* FOUR CONTROLS OF THREE DIFFERENT HEIGHTS. Bottom-aligned they read as an accident: the Show group
   wraps to two rows of options on a narrow content column, so aligning their feet puts each label at
   a different height and the strip looks like it fell over. Aligned at the top, every label starts on
   the same line and the groups underneath are free to be as tall as they need. */
.participation__filters[b-lei78or9ya] {
    align-items: flex-start;
}

/* -----------------------------------------------------------------------------
   The rows
   -----------------------------------------------------------------------------
   ::deep throughout, descending from .participation - the one element on this
   screen written as plain markup in this file, so it is what the scope attribute
   certainly lands on. Everything below it is at one remove: each cell is rendered
   by <RecordCell>, the badge by <StatusBadge>, and the Days button and the picker
   panel by RenderFragments in the @code block. CSS isolation does not stamp this
   file's scope onto another component's markup, and reasoning about which of those
   halves carries it is how a rule ends up silently doing nothing - see the note at
   the top of PeopleTable.razor.css.
   ----------------------------------------------------------------------------- */

.participation[b-lei78or9ya]  .participation__name {
    font-weight: var(--font-weight-medium);
}

.participation[b-lei78or9ya]  .participation__company {
    display: block;
    color: var(--color-text-secondary);
}

/* Connected by a role grant rather than by employment - a real state, and one the headcount could not
   represent at all before participation was recorded. Muted rather than warning-coloured: it is
   unusual, not wrong. */
.participation[b-lei78or9ya]  .participation__company--none {
    font-style: italic;
    color: var(--color-text-muted);
}

/* The badge carries the whole of the state now that the record buttons have gone, so it gets a line
   of its own rather than sharing one with the dates under it. */
.participation[b-lei78or9ya]  .participation__state {
    display: block;
    margin-bottom: var(--space-1);
}

/* DUE LATER IS OFF SITE'S COLOUR, AND THIS IS WHAT TELLS THEM APART. Both are Info, because neither
   of them is somebody standing on the site today, and minting a fifth hue for "not yet" would claim a
   difference bigger than the one there is. So certainty is carried by the edge instead - dashed for a
   state that is still a plan, solid for one in force - which is the same rule the day picker draws its
   future days with, and the word on the badge says it as well for anybody who cannot see either.

   The dash is drawn in --color-info-text rather than in the badge's own --color-info, which is a pale
   fill: a dashed border nobody can make out is not a second channel. info-text on info-subtle is
   5.18:1, comfortably past the 3:1 WCAG 1.4.11 asks of a graphical object. */
.participation[b-lei78or9ya]  .participation__state--due .status-badge {
    border-style: dashed;
    border-color: var(--color-info-text);
}

/* The glyph on the badge, which is the third channel after the word and the colour. Sized down from
   the icon set's own 1.25rem: at full size it is taller than the word beside it and the pill grows a
   line to hold it. It inherits the badge's colour, so the tone that pairs with each fill carries it. */
.participation[b-lei78or9ya]  .participation__badge-icon {
    width: 0.875rem;
    height: 0.875rem;
}

/* Travel, which is an adjective on the stint rather than a state of its own - so it sits under the
   badge and never in it. Secondary text, because the word "travelling" already says what this is, and
   the line is detail beneath the badge rather than a status of its own competing with it. */
.participation[b-lei78or9ya]  .participation__travel {
    display: block;
    color: var(--color-text-secondary);
}

.participation[b-lei78or9ya]  .participation__window {
    display: block;
    font-variant-numeric: tabular-nums;
}

/* Days are recorded for this person, just not today's. Muted, because it is context rather than the
   answer - and worded "on other days" rather than "earlier", since a run answered in the picker can
   sit ahead of today just as easily as behind it. */
.participation[b-lei78or9ya]  .participation__window--other {
    color: var(--color-text-muted);
}

.participation[b-lei78or9ya]  .participation__note {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* When the current state started, and what is already planned to happen next. Both sit under the
   badge as quieter lines: the badge is the answer, these are its detail. */
.participation[b-lei78or9ya]  .participation__since {
    display: block;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-secondary);
}

/* A departure or return already booked in. Accent-coloured rather than muted, because it is the one
   thing on the row that has not happened yet and is the likeliest thing a reader is looking for. */
.participation[b-lei78or9ya]  .participation__planned {
    display: block;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

/* A mark pointing forward, so the line reads as something ahead rather than as a second date the row
   is stating. It is drawn in CSS because it is punctuation on the sentence rather than content in it -
   and given empty alternative text, so a screen reader announces the sentence and not the arrowhead.
   The plain declaration first, for engines that do not take the alt-text form and would otherwise drop
   the whole rule. */
.participation[b-lei78or9ya]  .participation__planned::before {
    content: "\203A\00A0";
    content: "\203A\00A0" / "";
}

/* THE ONE CONTROL ON THE ROW. Sized as a real target rather than as a link - this is the control the
   screen exists for, used repeatedly, on a phone, outdoors, in gloves. */
.participation[b-lei78or9ya]  .participation__days {
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-sm);
    background: none;
    color: inherit;
    cursor: pointer;
}

.participation[b-lei78or9ya]  .participation__days:hover {
    background-color: var(--color-state-hover);
}

/* Keyed off the ARIA state rather than off a modifier class of its own, so what the button looks like
   and what it announces cannot drift apart: there is one fact, and both readings take it from the same
   attribute. */
.participation[b-lei78or9ya]  .participation__days[aria-expanded="true"] {
    border-color: var(--color-primary);
    background-color: var(--color-surface-inset);
}

/* The panel the button expands. It exists so aria-controls has an element to name - the picker itself
   is a component - and it needs the zero minimum for the same reason the picker's own root does:
   below 48rem base.css makes the detail cell a grid, and a grid item's automatic minimum size is its
   content, so without this the calendar strip would push the whole page sideways instead of scrolling
   inside its own box. */
.participation[b-lei78or9ya]  .participation__picker {
    min-width: 0;

    /* AN EDGE DOWN THE WHOLE PANEL, so an opened row reads as one object with the row that opened it.
       The table gives the detail cell its own inset background already; what it cannot say is which row
       this belongs to, and on a roster of forty people the panel is tall enough that its own heading
       has scrolled off by the time somebody is looking at November. */
    border-left: 4px solid var(--color-accent);
    padding-left: var(--space-4);
}
/* /Features/Manage/Pages/SiteCalendar.razor.rz.scp.css */
/* =============================================================================
   THE FIVE COLOURS
   -----------------------------------------------------------------------------
   Every figure on this screen has one, and it is the same one everywhere it
   appears - cell, summary row, legend and dialog. They are drawn from the
   existing token palette rather than invented, so the calendar stays inside the
   design system and inherits both themes.

     crew      neutral contrast   how many are here - context, not a state
     arriving  success            somebody starting is good news
     leaving   marine             neither good nor bad; a fact to plan around
     waiting   warning            the only one that asks the reader to act
     approved  success text       settled

   Colour is never the only channel. Every mark carries its meaning in title and
   in visually-hidden text, and the legend spells all five out - a phone in
   direct sunlight on a site loses colour long before it loses text.
   ============================================================================= */

.calendar__controls[b-nnke2bve62] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}

.calendar__title[b-nnke2bve62] {
    margin: 0;
    font-size: var(--font-size-lg);

    /* Fixed, so a changing title does not shuffle the arrows either side of it under the reader's
       thumb as they page through. */
    min-width: 11rem;
    text-align: center;
}

.calendar__totals[b-nnke2bve62] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(7rem, 45%), 1fr));
    gap: var(--space-4);
    margin: 0;
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.figure dt[b-nnke2bve62] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.figure dd[b-nnke2bve62] {
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: var(--line-height-tight);
}

/* A coloured rule under each total, tying the number to the colour it wears in the grid. */
.figure[b-nnke2bve62] {
    border-top: 3px solid var(--color-border);
    padding-top: var(--space-2);
}

.figure--crew[b-nnke2bve62] { border-top-color: var(--color-surface-contrast); }
.figure--arriving[b-nnke2bve62] { border-top-color: var(--color-success); }
.figure--leaving[b-nnke2bve62] { border-top-color: var(--color-marine-strong); }
.figure--waiting[b-nnke2bve62] { border-top-color: var(--color-warning); }
.figure--approved[b-nnke2bve62] { border-top-color: var(--color-green-dark); }
.figure--hours[b-nnke2bve62] { border-top-color: var(--color-border-strong); }

/* Dimmed rather than blanked while a span loads, so paging does not flash the grid away and back. */
.calendar--loading[b-nnke2bve62] {
    opacity: 0.55;
    transition: opacity var(--motion-duration-fast) var(--motion-easing-standard);
}

/* -----------------------------------------------------------------------------
   The day grid
   ----------------------------------------------------------------------------- */

/* Seven equal columns at every width. A calendar that reflows is not a calendar - the whole value is
   that the same weekday sits in the same column every row - so cells get smaller on a phone rather
   than fewer. minmax(0, 1fr) rather than 1fr: without the zero minimum a long number inside a cell
   would widen its column and break the alignment. */
.calendar__grid[b-nnke2bve62] {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-1);
}

.calendar__heading[b-nnke2bve62] {
    padding: var(--space-1) 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    text-align: center;
}

.cell[b-nnke2bve62] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);

    /* Tall enough for a date and all five marks stacked, because .cell is overflow:
       hidden and a cell that cannot fit them drops the last ones silently - no
       scrollbar, no ellipsis, nothing to notice. Five labelled marks at 1.5 line-height
       plus the date and the padding is a shade over eight rems. */
    min-height: 8.5rem;
    padding: var(--space-2);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
    text-align: left;
    overflow: hidden;
}

/* Days from the months either side. Quieter, and still drawn - work registered on the 31st of last
   month is still work, and hiding it would make the corner of the grid read as an empty day. */
.cell--outside[b-nnke2bve62] {
    background-color: var(--color-surface-inset);
    opacity: 0.6;
}

.cell--today[b-nnke2bve62] {
    border-color: var(--color-accent);
    border-width: 2px;
}

/* A day with something waiting. The left edge rather than the whole cell, so it reads at a glance
   down a column without swamping the figures - and the warning-coloured mark inside carries the same
   meaning for anybody who cannot see the edge. */
.cell--attention[b-nnke2bve62] {
    border-left: 3px solid var(--color-warning);
}

.cell__label[b-nnke2bve62] {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
}

/* Stacked, one mark to a line, now that each carries a word as well as a figure. Wrapped
   in a row they broke mid-phrase - "9 on" on one line and "site" on the next - which is
   worse than the bare number this replaced. The phone breakpoint drops back to a wrapping
   row, where the labels are hidden and the figures are narrow again. */
.cell__marks[b-nnke2bve62] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

/* -----------------------------------------------------------------------------
   The marks - one per figure, coloured by kind
   ----------------------------------------------------------------------------- */

.mark[b-nnke2bve62] {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-1);
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
}

.mark__name[b-nnke2bve62] {
    font-weight: var(--font-weight-regular);
    opacity: 0.8;
}

/* Every pairing here is a token background with its matching AA-safe text token - the same pairs the
   status badges use, so the contrast floor the design tokens guarantee applies unchanged. */
.mark--crew[b-nnke2bve62] {
    background-color: var(--color-surface-contrast);
    color: var(--color-text);
}

.mark--arriving[b-nnke2bve62] {
    background-color: var(--color-success-subtle);
    color: var(--color-success-text);
}

.mark--leaving[b-nnke2bve62] {
    background-color: var(--color-info-subtle);
    color: var(--color-info-text);
}

.mark--waiting[b-nnke2bve62] {
    background-color: var(--color-warning-subtle);
    color: var(--color-warning-text);
}

.mark--approved[b-nnke2bve62] {
    background-color: var(--color-success-subtle);
    color: var(--color-success-text);
    /* Distinguished from "arriving" by a ring rather than by a different green: the two share a
       meaning - both are good news - and inventing a sixth hue for that would be noise. */
    box-shadow: inset 0 0 0 1px var(--color-success);
}

/* -----------------------------------------------------------------------------
   The summary rows, for a quarter and a year
   ----------------------------------------------------------------------------- */

.calendar__rows[b-nnke2bve62] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The whole row is the control, and it opens the span below it - a month from a year, a week from a
   quarter. A row that only sat there would make the long spans read-only. */
.period[b-nnke2bve62] {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "label hours"
        "marks marks";
    gap: var(--space-2) var(--space-4);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    text-align: left;
}

@media (min-width: 48rem) {
    .period[b-nnke2bve62] {
        grid-template-columns: minmax(9rem, auto) 1fr minmax(5rem, auto);
        grid-template-areas: "label marks hours";
        align-items: center;
    }
}

.period--current[b-nnke2bve62] {
    border-color: var(--color-accent);
}

.period__label[b-nnke2bve62] {
    grid-area: label;
    font-weight: var(--font-weight-semibold);
}

.period__marks[b-nnke2bve62] {
    grid-area: marks;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.period__hours[b-nnke2bve62] {
    grid-area: hours;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.period__unit[b-nnke2bve62] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
}

/* -----------------------------------------------------------------------------
   The legend and the note
   ----------------------------------------------------------------------------- */

.legend[b-nnke2bve62] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.legend__item[b-nnke2bve62] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.legend__swatch[b-nnke2bve62] {
    width: 1rem;
    height: 1rem;
    border-radius: var(--radius-sm);
    padding: 0;
}

.calendar__note[b-nnke2bve62] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* Below the tablet breakpoint the cells lose the mark labels and keep the figures. Seven columns at
   320px leaves roughly 40px a cell, which fits a date and two small numbers and nothing else - and a
   cell crammed with five lines of 10px text is a cell nobody reads. The dialog is where the detail
   lives at that width, which is what makes tapping a day the primary interaction on a phone. */
@media (max-width: 48rem) {
    .cell[b-nnke2bve62] {
        min-height: 4.5rem;
        padding: var(--space-1);
        gap: 2px;
    }

    /* Back to a wrapping row here. With .mark__name hidden below this breakpoint each mark
       is a figure two or three characters wide, and stacking five of them would need a cell
       taller than the seven-column grid has width to justify. */
    .cell__marks[b-nnke2bve62] {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 2px;
    }

    .mark[b-nnke2bve62] {
        padding: 0 2px;
    }

    .mark__name[b-nnke2bve62] {
        display: none;
    }
}
/* /Features/Manage/Pages/WorkLog.razor.rz.scp.css */
/* The screen is a vertical stack of blocks - notice, answer, composer, outstanding, filters, log - so
   spacing comes from the .stack primitive in base.css. */

.work-log[b-0g3gg7vu2x] {
    --stack-gap: var(--space-5);
}

/* THE ANSWER, BEFORE ANY NUMBER. A heading rather than a tile, because it is a sentence somebody reads
   rather than a figure they have to interpret - the rule the site overview already follows. */
.work-log__answer[b-0g3gg7vu2x] {
    margin: 0;
    font-size: var(--font-size-xl);
    text-wrap: balance;
}

.work-log__log[b-0g3gg7vu2x] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
/* /Features/Manage/WorkLog/OutstandingList.razor.rz.scp.css */
/* Set apart from the log below it. Warning-bordered rather than warning-filled: this section is on the
   screen at every visit, and a block of colour that is always there stops being read within a week. */
.outstanding[b-skj7fpuxcd] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.outstanding__heading[b-skj7fpuxcd] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.outstanding__none[b-skj7fpuxcd] {
    margin: 0;
    color: var(--color-text-secondary);
}

.outstanding__list[b-skj7fpuxcd] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.outstanding__item[b-skj7fpuxcd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.outstanding__text[b-skj7fpuxcd] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;

    /* Takes the room the buttons do not, and wraps them under it when there is not enough. */
    flex: 1 1 18rem;
}

.outstanding__title[b-skj7fpuxcd] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin: 0;
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

/* The kind as a word in a quiet chip, like the card's - tone is reserved for status everywhere. */
.outstanding__kind[b-skj7fpuxcd] {
    padding: 0 var(--space-2);
    border: var(--border-width) solid var(--color-border-subtle);
    border-radius: var(--radius-full);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    white-space: nowrap;
}

.outstanding__meta[b-skj7fpuxcd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.outstanding__age[b-skj7fpuxcd] {
    font-weight: var(--font-weight-medium);
}

.outstanding__age--calm[b-skj7fpuxcd] {
    color: var(--color-text-muted);
}

.outstanding__age--warn[b-skj7fpuxcd] {
    color: var(--color-warning-text);
}

.outstanding__age--urgent[b-skj7fpuxcd] {
    color: var(--color-danger-text);
}

/* Said in words, never by colour alone - and this is the state the whole section is about. */
.outstanding__unclaimed[b-skj7fpuxcd] {
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
}

.outstanding__place[b-skj7fpuxcd] {
    overflow-wrap: anywhere;
}

.outstanding__actions[b-skj7fpuxcd] {
    --cluster-gap: var(--space-2);
    flex-shrink: 0;
}

@media (max-width: 48rem) {
    .outstanding[b-skj7fpuxcd] {
        padding: var(--space-4);
    }

    /* Full width on a phone. This is the section somebody acts on at the start of a shift, in gloves, so
       the targets take the whole line rather than sharing it. */
    .outstanding__actions[b-skj7fpuxcd] {
        width: 100%;
    }

    .outstanding__actions button[b-skj7fpuxcd] {
        flex: 1 1 8rem;
    }
}
/* /Features/Manage/WorkLog/WorkLogActPanel.razor.rz.scp.css */
/* Full width, and taller than one line without pretending to be an essay: the sentence this collects is
   one sentence, and a box the size of a paragraph asks for a paragraph. */
.work-log-act__note[b-y2cg7n2o34] {
    width: 100%;
    min-height: 5rem;
}

.work-log-act__actions[b-y2cg7n2o34] {
    margin-top: var(--space-4);
}
/* /Features/Manage/WorkLog/WorkLogComposer.razor.rz.scp.css */
/* The box that has to be in front of somebody every time they open this screen. Bordered and on the
   container surface so it reads as the thing to do rather than as a caption above the log. */
.work-log-composer[b-d7jot2x48f] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
    box-shadow: var(--shadow-sm);

    /* The two panes below are measured against this box rather than the window, because the box is the
       window minus a sidebar that is there on a laptop and gone on a tablet. */
    container-type: inline-size;
}

.work-log-composer__heading[b-d7jot2x48f] {
    margin: 0;
    font-size: var(--font-size-lg);
}

/* The heading the log lists and searches by. Set at the base size and no smaller: this is the field the
   whole feature depends on being used. */
.work-log-composer__title[b-d7jot2x48f] {
    width: 100%;
    font-size: var(--font-size-base);
}

.work-log-composer__more[b-d7jot2x48f] {
    align-self: flex-start;
    color: var(--color-link);
}

/* The classification: what kind, where, and which day. One column on a phone, two on a wide box - these
   are short controls, and a single column of them would be a tall panel of half-empty rows. The writing
   box is NOT in here: it sits above, always open, because where the text box lives is the clearest thing
   a form says about how much it expects. */
.work-log-composer__detail[b-d7jot2x48f] {
    display: grid;

    /* The same guard the two-column rule below sets, and for the same reason: an implicit track is
       auto-sized, and auto's floor is the min-content width of its contents - so one field holding
       something that will not wrap widens the panel past the screen. See JobPanel, which carries the
       long version of this. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

/* One control, and the button that belongs to it. A grid cell rather than a column of its own, so that
   the three of them line up at the top of the panel instead of stacking under one another. */
.work-log-composer__fact[b-d7jot2x48f] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Full width, and given room to be tall. The editor reads --rich-text-min-height from here. */
.work-log-composer__write[b-d7jot2x48f] {
    display: flex;
    flex-direction: column;
    --rich-text-min-height: 10rem;
}

.work-log-composer__add-place[b-d7jot2x48f],
.work-log-composer__drop-place[b-d7jot2x48f] {
    align-self: flex-start;
    color: var(--color-link);
}

@container (min-width: 52rem) {
    /* Aligned at the top, so the two columns of controls start on the same line rather than one being
       centred against the other - the rule the rest of the application follows. */
    .work-log-composer__detail[b-d7jot2x48f] {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: var(--space-6);
        align-items: start;
    }

    /* Taller where there is room for it. Set here rather than in the editor, because what decides
       whether there is room is the width of this box. */
    .work-log-composer__write[b-d7jot2x48f] {
        --rich-text-min-height: 14rem;
    }
}

.work-log-composer__actions[b-d7jot2x48f] {
    --cluster-gap: var(--space-3);
    margin-top: var(--space-2);
}

@media (max-width: 48rem) {
    .work-log-composer[b-d7jot2x48f] {
        padding: var(--space-4);
    }

    /* Stacked and full width on a phone, not side by side. These two buttons say different things and a
       thumb at the end of a shift should not have to aim between them. No ::deep: they are this
       component's own markup. */
    .work-log-composer__actions button[b-d7jot2x48f] {
        flex: 1 1 100%;
    }
}
/* /Features/Manage/WorkLog/WorkLogDayGroup.razor.rz.scp.css */
.work-log-group[b-rkpwmocjiq] {
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

/* The whole header is the tap target, at the application's minimum height, because on a phone this is
   what somebody presses to read a shift. The browser's own marker is kept - it is the affordance every
   reader already knows, and drawing our own would mean keeping it in step with the open state by hand. */
.work-log-group__summary[b-rkpwmocjiq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-4);
    min-height: var(--layout-touch-target-min);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
}

.work-log-group__summary:hover[b-rkpwmocjiq] {
    background-color: var(--color-state-hover);
    border-radius: var(--radius-lg);
}

.work-log-group__heading[b-rkpwmocjiq] {
    font-weight: var(--font-weight-semibold);
}

.work-log-group__counts[b-rkpwmocjiq] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* How many inside are still waiting. A word rather than only a colour, and only present when the number
   is not zero - "0 waiting" on every closed group is noise that teaches people to skip the line. */
.work-log-group__outstanding[b-rkpwmocjiq] {
    padding: 0 var(--space-2);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-full);
    color: var(--color-warning-text);
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

.work-log-group__entries[b-rkpwmocjiq] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: 0 var(--space-4) var(--space-4);
}

@media (max-width: 48rem) {
    .work-log-group__summary[b-rkpwmocjiq] {
        padding: var(--space-3);
    }

    .work-log-group__entries[b-rkpwmocjiq] {
        padding: 0 var(--space-3) var(--space-3);
    }
}
/* /Features/Manage/WorkLog/WorkLogEntryCard.razor.rz.scp.css */
.work-log-card[b-m5wzoqymm9] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

/* Something still waiting on somebody, wherever it is drawn. A left edge rather than a fill, so a run of
   outstanding items reads as a column of marks down the page rather than as a block of colour - and so
   the badge saying so in words is still the loudest thing on the card. */
.work-log-card--outstanding[b-m5wzoqymm9] {
    border-inline-start: var(--space-1) solid var(--color-warning);
}

.work-log-card__head[b-m5wzoqymm9] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.work-log-card__marks[b-m5wzoqymm9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* THE KIND IS ALWAYS NEUTRAL, for all seven of them. Seven categories cannot be mapped onto four tones
   without one of the colours lying, so tone is reserved for status and the kind is a word in a quiet
   chip - which is also why this needed no new token. */
.work-log-card__kind[b-m5wzoqymm9] {
    padding: 0 var(--space-2);
    border: var(--border-width) solid var(--color-border-subtle);
    border-radius: var(--radius-full);
    background-color: var(--color-surface-inset);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    white-space: nowrap;
}

/* How long it has been waiting, escalating with the wait. The word is always there - the colour only
   makes an old item findable in a scan, and never carries the meaning on its own. */
.work-log-card__age[b-m5wzoqymm9] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
}

.work-log-card__age--calm[b-m5wzoqymm9] {
    color: var(--color-text-muted);
}

.work-log-card__age--warn[b-m5wzoqymm9] {
    color: var(--color-warning-text);
}

.work-log-card__age--urgent[b-m5wzoqymm9] {
    color: var(--color-danger-text);
}

.work-log-card__title[b-m5wzoqymm9] {
    margin: 0;
    font-size: var(--font-size-lg);

    /* A title is one line of somebody's own words and can be anything. It wraps rather than truncating,
       because the title is the only thing a collapsed group shows. */
    overflow-wrap: anywhere;
}

.work-log-card__by[b-m5wzoqymm9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.work-log-card__edited[b-m5wzoqymm9] {
    font-style: italic;
}

/* Wraps rather than truncating: a path cut short is a place nobody can identify, which is the one thing
   this line exists to prevent. */
.work-log-card__place[b-m5wzoqymm9] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.work-log-card__body[b-m5wzoqymm9] {
    margin: 0;
}

.work-log-card__holder[b-m5wzoqymm9] {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* What was done, or why it was dropped. Set apart from the body, because it was written later and by
   somebody who may not be the author. */
.work-log-card__closed[b-m5wzoqymm9] {
    margin: 0;
    padding: var(--space-3);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
    font-size: var(--font-size-sm);
}

.work-log-card__closed-label[b-m5wzoqymm9] {
    margin-inline-end: var(--space-2);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
}

/* A native <details>. The browser supplies the disclosure semantics, the keyboard behaviour and the
   expanded state - see adr/0004 - so there is no aria-expanded here to keep in step by hand. */
.work-log-card__trail-summary[b-m5wzoqymm9] {
    display: flex;
    align-items: center;
    min-height: var(--layout-touch-target-min);
    color: var(--color-link);
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.work-log-card__trail-list[b-m5wzoqymm9] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding-inline-start: var(--space-5);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.work-log-card__trail-act[b-m5wzoqymm9] {
    display: block;
}

.work-log-card__trail-note[b-m5wzoqymm9] {
    display: block;
    color: var(--color-text-muted);
}

.work-log-card__actions[b-m5wzoqymm9] {
    --cluster-gap: var(--space-2);
    padding-top: var(--space-2);
    border-top: var(--border-width) solid var(--color-border-muted);
}

@media (max-width: 48rem) {
    .work-log-card[b-m5wzoqymm9] {
        padding: var(--space-4);
    }

    /* Full-width buttons on a phone, where this is the end of a shift and a thumb is nowhere near a
       precise target. .cluster already wraps; this makes each one take the whole line rather than
       leaving three half-width targets in a ragged row.

       No ::deep: these buttons are this component's own markup, so they carry its scope attribute. */
    .work-log-card__actions button[b-m5wzoqymm9] {
        flex: 1 1 100%;
    }
}
/* /Features/Manage/WorkLog/WorkLogFilters.razor.rz.scp.css */
.work-log-filters[b-xupbfg36pm] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.work-log-filters__row[b-xupbfg36pm] {
    align-items: flex-end;
    --cluster-gap: var(--space-4);
}

/* Grows into whatever the segments leave, and drops to its own line on a phone rather than squeezing to
   a box too narrow to read a sentence in. */
.work-log-filters__search[b-xupbfg36pm] {
    flex: 1 1 14rem;
    min-width: 0;
}

.work-log-filters__more[b-xupbfg36pm] {
    align-self: center;
    color: var(--color-link);
    white-space: nowrap;
}

/* Says that something beyond the default is set, so the reader is never looking at a narrowed list with
   no sign of why. A dot alone would be colour carrying meaning, so a visually-hidden sentence goes with
   it. */
.work-log-filters__mark[b-xupbfg36pm] {
    color: var(--color-accent);
    font-size: var(--font-size-lg);
    line-height: 1;
}

.work-log-filters__panel[b-xupbfg36pm] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    gap: var(--space-4);
    padding: var(--space-4);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
    align-items: end;
}

.work-log-filters__clear[b-xupbfg36pm] {
    justify-self: start;
    color: var(--color-link);
}
/* /Features/Reports/Map/SiteMapView.razor.rz.scp.css */
/* The site drawn to scale.

   NOTHING HERE HAS A SIZE OF ITS OWN except the frame's aspect ratio, and that comes from the
   drawing rather than from this file. Everything else is a token or a percentage, which is what lets
   the same markup be a wide desktop panel and a 320px phone with no media query deciding anything.

   THE SVG IS STRETCHED TO ITS BOX, ALWAYS, AND THE BOX IS THE DRAWING'S OWN SHAPE. The element
   carries preserveAspectRatio="none", so nothing here letterboxes and there is never space above or
   below the drawing: the SVG fills the frame in both directions. What keeps the proportions is that
   the component sets the site's aspect ratio inline on the frame - see FrameShape - and this file
   gives that box nothing that would make it a different shape. It is also what lets the names be
   positioned in percentages, since a percentage of the frame is then a percentage of the viewBox.
   So a padding, a border or a cap that leaves the box a shape the drawing is not does not letterbox
   it, it stretches it - and a stretched scale drawing is not a scale drawing. */

.sitemap[b-mw0009z2yr] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.sitemap__bar[b-mw0009z2yr] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
}

.sitemap__crumbs[b-mw0009z2yr] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1);
    min-width: 0;
}

/* THE WAY OUT OF A ZOOM HAS TO LOOK LIKE ONE. Measured on the running page, these were 14px, weight
   400, rgb(83,84,84), with no padding, no border and no underline: the same size and weight as the
   explanatory sentence above the panel and a shade darker than it, and much quieter than the 16px
   semibold "1 Sep" sharing their row. Three pieces of flat grey text, one of which happened to be the
   only way out of a zoom. Half of "there is no way to get back to the whole site" was the reset not
   working; the other half is that the control which performs it did not read as a control, in either
   theme. Link colour, a little padding and a corner give it the weight of something to press without
   turning a trail into a row of boxed buttons. The 44px hit area was always here - it comes from the
   button rule in base.css - so nothing about the size of the target changes, only whether anybody can
   see where it is.

   THE HOVER IS OVERRIDDEN, WHICH IS NOT USUALLY ALLOWED IN THIS APPLICATION. base.css argues that its
   single hover model is the only one that cannot drift between variants, and that argument holds for
   the translucent layer, which is left exactly as it is. What cannot stand is the COLOUR half:
   button.quiet:hover paints --color-text, so a crumb went from link blue to near-black the moment a
   pointer touched it - a control getting quieter as you reach for it, which is the precise reading
   this rule exists to remove. --color-link-hover is the same move every other link on the screen
   makes. Scoped to button. deliberately: the current step is a span, and giving a hover state to
   something that cannot be pressed is the same lie told the other way round.

   BUTTONS RATHER THAN LINKS, STILL, BUT NOT FOR THE REASON THAT USED TO BE WRITTEN HERE. That comment
   said these do not navigate and do not change the address. They do change it now: a crumb sets the
   page's place filter, exactly as the filter bar's own chip does, and that filter is in the address.
   They stay buttons because they act on this screen rather than going to another one, which is the
   distinction that decides the element. */
.sitemap__crumb[b-mw0009z2yr] {
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--color-link);
    font-size: var(--font-size-sm);
}

button.sitemap__crumb:hover:not(:disabled)[b-mw0009z2yr] {
    color: var(--color-link-hover);
}

/* WHERE THE DRAWING IS, WHICH IS NOT SOMEWHERE TO GO. The last step of the trail - and "Whole site"
   itself when nothing is narrowed - is drawn as text, because pressing it would do nothing. A control
   that does nothing is worse on this bar than no control at all: it is the one thing here that looks
   pressable, and a reader who tries it and sees the picture stay put has been taught that the trail is
   decoration, at exactly the moment they are hunting for the way out.

   IT KEEPS THE BUTTON'S HEIGHT ALTHOUGH IT IS NOT ONE. A span is a line tall where a button is 44px,
   so without this the bar shrank whenever nothing was narrowed and the whole drawing jumped up the
   page each time somebody came back out of a building - which on a panel that reframes at the same
   instant reads as the drawing having done something else as well. Measured at 44px in both states and
   both themes, so nothing on the panel moves. */
.sitemap__crumb--here[b-mw0009z2yr] {
    display: inline-flex;
    align-items: center;
    min-height: var(--layout-touch-target-min);
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
    cursor: default;
}

.sitemap__crumb-sep[b-mw0009z2yr] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* The bucket being shown, and the loudest text on the control bar - during playback it is the only
   thing on screen that says which day the picture is of. */
.sitemap__when[b-mw0009z2yr] {
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

/* The drawing sits on its own ground, with the site aspect ratio set inline so nothing letterboxes.
   Capped in height so a tall plant cannot push the rest of the screen away, and centred when the cap
   bites. */
.sitemap__frame[b-mw0009z2yr] {
    position: relative;
    width: 100%;

    /* THE CAP IS A CUSTOM PROPERTY SO A NARROW SCREEN CAN MOVE IT WITHOUT CHANGING THIS BOX'S SHAPE.
       The component reads it back in the inline max-width - see FrameShape - so whichever cap is in
       force, the width allowed is recomputed from the drawing's own ratio and the box stays the shape
       of the viewBox. Capping the HEIGHT alone would leave the width where it was, and a frame that is
       not the viewBox's shape is a frame preserveAspectRatio="none" stretches the drawing into.
       Both halves are needed: the height alone crops a tall site, the width alone lets it grow
       forever. Matches FrameCapRem in the component, which is the fallback if this never arrives. */
    --sitemap-cap: 44rem;
    max-height: var(--sitemap-cap, 44rem);
    margin-inline: auto;

    /* NO PADDING, AND THE REASON IS THAT THIS BOX CARRIES THE DRAWING'S ASPECT RATIO. The ratio is set
       inline on the border box, while the SVG fills the CONTENT box - so a padding of 1rem made the
       content box sixteen pixels narrower AND sixteen shorter, which is a different shape, and with
       preserveAspectRatio="none" the drawing was quietly stretched into it: about one and a half
       percent on a desktop panel and five on a phone. That is a metre square drawn out of square on a
       grid this screen invites the reader to count, and a circle drawn as an ellipse. What is left of
       that error is the 1 px border, which is a tenth of a percent.

       It cost more than a stretch, because a percentage on an absolutely positioned child resolves
       against the PADDING box: the names were measured over a box thirty-two pixels wider than the
       drawing they label, correct at the middle and out by up to sixteen pixels at either edge. With
       no padding the padding box and the content box are the same box, so that error is not reduced
       but gone.

       The drawing needs no padding anyway - ExtentOf already leaves a margin of four percent around
       every shape, in metres, which is the same inset expressed in the only units this file trusts.
       The editor's canvas has carried the ratio with no padding all along. */
    box-sizing: border-box;
    overflow: hidden;
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

/* THE GRID IS RULED IN METRES, IN THE SVG, not painted behind it in CSS.
   It was two CSS gradients on a 2.5rem pitch, which is a fixed number of PIXELS - so the squares
   meant nothing, changed size with the panel, and disagreed with the scale bar sitting next to them.
   A plan whose grid is decorative is a plan that invites somebody to count squares and get a wrong
   answer. Ruled at the same round step the editor uses, it is a measurement instead. */
.sitemap__grid[b-mw0009z2yr] {
    stroke: var(--color-border-muted);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    opacity: 0.6;
    pointer-events: none;
}

.sitemap__svg[b-mw0009z2yr] {
    display: block;
    width: 100%;
    height: 100%;
}

/* THE LAYER THE NAMES LIVE ON, WHICH IS THE DRAWING AND NOT THE PANEL AROUND IT. A percentage on an
   absolutely positioned element is a percentage of its ancestor's PADDING box, so while the frame
   carried a pad the labels were measured against a box a pad wider and a pad taller than the SVG they
   name. The error was zero in the middle and a whole pad at the edges - every place in the bottom
   half of the plan had its name drawn low, by more than a line of text on a phone - and it was
   invisible in review because the centre of the drawing always looked right. The frame's padding is
   gone for the aspect-ratio reason given up there, so its padding box and its content box are one
   box, this layer is exactly the box the SVG fills, and a percentage here is a percentage of the
   viewBox. */
.sitemap__names[b-mw0009z2yr] {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* NAMES OVER THE DRAWING, as HTML rather than SVG text so they are never scaled by the viewBox.

   CENTRED ON A POINT THE COMPONENT PUTS ON AN EDGE OF THE SHAPE, which is the whole of the placement
   rule: a leaf's name straddles its bottom edge, a container's straddles its top edge, and scenery
   keeps the middle it has always had because nothing is ever drawn inside a quay. Half a line inside
   the shape and half a line outside it. Wholly inside is where the dots are - at the smallest size
   this stylesheet is ever asked to letter, one mark is more than four fifths of the shape's height,
   so a name inside a small tank is a name printed through a person. Wholly outside is worse still:
   the name then reads as belonging to whatever it lands on, and on a hall of tanks in rows that is
   the next tank down.

   Allowed to overhang its shape sideways, still: a name clipped to fit inside a small tank is a name
   nobody can read, and this way the shape stays honest about its size while the label stays legible.

   The gap either side of an edge is half this box, so it is measured in the type size and not in
   metres. That is deliberate and it is the thing the fraction of the frame height it replaces could
   not do: a clearance written as a share of the drawing is a constant number of lines at exactly one
   panel width, two thirds of a line on a phone and two and a half on a wide desktop. */
.sitemap__label[b-mw0009z2yr] {
    position: absolute;
    transform: translate(-50%, -50%);
    padding: 0 0.15rem;
    color: var(--color-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    line-height: 1;
    white-space: nowrap;
    pointer-events: none;

    /* The drawing shows through behind the words rather than a box being punched in it. It is also
       what makes straddling an edge survivable: the shape's own outline runs under the text, and
       without the halo the two would read as one smudged line. */
    text-shadow:
        0 0 3px var(--color-surface-container),
        0 0 3px var(--color-surface-container),
        0 0 6px var(--color-surface-container);
}

/* A LEAF THAT CARRIES ITS TAG HANGS ITS LAST LINE ON THE EDGE, NOT THE MIDDLE OF THE PAIR. A container
   puts its first line on its top edge and the tag falls inside underneath it, which the rule below
   does for free. A leaf is named on its BOTTOM edge, so the line that has to straddle is the last one
   - and centring the two-line box there instead left the name wholly inside and the tag wholly below,
   in the gap under the tank, which on a hall of tanks in rows is the next tank down. That is precisely
   the misattribution the placement rule refuses to accept. -100% puts the box's foot on the edge and
   0.3rem - half the tag's own 0.6rem line - lifts it back to straddling. Which labels this applies to
   is decided in the component, in LabelClass, for the reason the stacked case is: a child selector
   cannot be asked about here without out-specifying the area rule. It sits before that rule so source
   order settles the tie the way this stylesheet settles the others. */
.sitemap__label--tagged[b-mw0009z2yr] {
    transform: translate(-50%, calc(-100% + 0.3rem));
}

/* Scenery. Quieter than the quietest place name and italic, so it reads as annotation on the ground
   rather than as somewhere work could be booked. */
.sitemap__label--ground[b-mw0009z2yr] {
    color: var(--color-text-muted);
    font-size: 0.68rem;
    font-weight: var(--font-weight-regular);
    font-style: italic;
    letter-spacing: 0.02em;
}

/* A PLACE WITH THINGS INSIDE IT CARRIES ITS NAME ON ITS OWN TOP EDGE, the way a title block letters a
   space on a real plan - half a line above the edge and half below it, so the whole interior belongs
   to the places drawn in it and the people standing in them. It used to be anchored a share of the
   shape's height BELOW the top edge and then hang the text downwards from there, so the two
   displacements compounded and a deep container's name started a quarter of the way into its own
   middle, straight across the tank labels and the dot clusters it contains.

   LEFT-ALIGNED ON THE SHAPE'S LEFT EDGE rather than centred on its middle. It begins at the corner of
   the shape it names, which is the one thing a centred name cannot promise: centred and wider than
   its shape, a name starts to the LEFT of it, over the neighbour. The component holds an area to a
   wider per-character allowance than a leaf before drawing its name at all - this rule is 0.68 rem
   uppercase semibold with 0.04 em of tracking, which costs about a fifth more per character than the
   12 px mixed case the leaf's figure was calibrated on - so what is left over spills right, off the
   end, rather than off both ends. See Shape.Labelled. A building and the hall drawn inside it stack
   into one column the way a plan letters them. The hairline inset is the label's own padding - a type
   measurement rather than a length in metres, which would drift with the frame - and it is now all in
   front of the first letter rather than symmetric, which is why Labelled budgets for it. */
.sitemap__label--area[b-mw0009z2yr] {
    /* HALF A LINE, NOT HALF THE BOX. A percentage here is a share of the element, and a name with its
       reference designation under it is two line boxes - so -50% centred the PAIR on the edge and put
       the name a whole line clear of the shape, with only the tag straddling. Half of the first line
       is 0.5em of this rule's own font size, because line-height is 1: identical to -50% when there is
       no tag, and the stated rule rather than an accident when there is. */
    transform: translate(0, -0.5em);
    color: var(--color-text-secondary);
    font-size: 0.68rem;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* THE ONE CASE WHERE A CONTAINER'S NAME LEAVES ITS OWN TOP EDGE: when the thing it is drawn inside
   has its name at the same height already. That happens whenever somebody traces a building a couple
   of metres outside the hall it holds, and two metres on a 175 m site is two pixels - the pair
   rendered as one word made of both names. Dropping this one by a line puts them in the order a plan
   reads, the outer name on the shared edge and the inner one under it, and it costs only the top line
   of a shape whose own children start further down. One line and not two, and that is now a smaller
   claim than it was: it clears the outer NAME and not the reference designation under it, so a pair
   that is both near-coincident and tagged still prints the inner name through the outer tag. That case
   used to be argued away on the grounds that a container was only lettered once it was about an eighth
   of the frame tall, which Shape.Labelled no longer requires - so the argument is gone and only the
   rarity is left. Fixing it needs a second step that clears two lines and knows whether the PARENT is
   tagged, which is a decision to take deliberately rather than a constant to nudge. Which names this
   applies to is decided in the component; see
   SiteMapGeometry.NameStacksInside. This must stay after the rule above, which it overrides by source
   order rather than by weight. */
.sitemap__label--stacked[b-mw0009z2yr] {
    /* The same half-line correction as the rule above, folded in: -0.5em + 1.25em. */
    transform: translate(0, 0.75em);
}

/* THE GROUND THE PLANT STANDS ON: quays, roads, the sea. Fainter than the faintest place and never
   clickable, because it is not somewhere work happens - it is what makes the places findable. A
   dashed edge so it cannot be mistaken for one of them even at a glance. */
.sitemap__ground[b-mw0009z2yr] {
    fill: var(--color-text-secondary);
    fill-opacity: 0.05;
    stroke: var(--color-border-strong);
    stroke-opacity: 0.3;
    stroke-width: 1;
    stroke-dasharray: 6 5;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

/* EVERY LEVEL IS A LINE. All of the structure is drawn on one plan at once - an area, its systems,
   their equipment - and filled blocks at three depths is a stack of slabs where the inner ones are
   simply lost. An outline inside an outline reads as inside it, which is the whole point.

   A place with no hours is the faintest line on the drawing rather than a hole in it: it is still
   somewhere on the site, and at this weight it recedes without disappearing. */
.sitemap__place[b-mw0009z2yr] {
    fill: var(--color-accent);
    fill-opacity: 0;
    stroke: var(--color-border-strong);

    /* 0.6, RAISED FROM 0.45 WHEN THE LIGHT STOPPED FOLLOWING THE PERIOD. While every place anybody
       had ever worked in was lit on every frame, the unlit ones were the exception and could afford
       to recede. Now they are most of the plan on most days - a fish farm has sixty tanks and six
       people - so this is the weight the drawing itself is read at, and on the dark ground, where
       border-strong is gray-600 rather than gray-300, 0.45 of it was very nearly nothing: the tanks
       nobody had worked in disappeared and the plan stopped being a plan between the lit ones. */
    stroke-opacity: 0.6;
    stroke-width: 1.25;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
    cursor: pointer;
    /* The line only. A place's inside is never tinted now - the hours light its wall instead - so a
       transition on fill-opacity animates a value that no longer moves. */
    transition: stroke-opacity 120ms ease-out;
}

/* Somewhere work was done. The accent takes over from the neutral border, and the inline style sets
   how strongly - a continuous value, because an outline carries one better than five steps do. */
.sitemap__place--busy[b-mw0009z2yr] {
    stroke: var(--color-accent);
    stroke-width: 1.75;
}

.sitemap__place:hover[b-mw0009z2yr] {
    stroke: var(--color-primary);
    stroke-opacity: 1;
}

/* THE LIGHT INSIDE A SHAPE, FROM ITS OWN LINE INWARD. Two bands per place: a deep faint one for the
   hours worked there over the period, and a shallow bright one carrying those hours again plus how far
   the place moved since the frame before - so during playback the eye is pulled to what is happening
   rather than to wherever the most hours have ever been. Both are the shape drawn again and inset by
   half their own stroke width, which is what keeps the paint strictly inside the outline; the markup
   explains why that beats a clip path, a mask and a blur.

   SILENT UNTIL THE INLINE STYLE SAYS OTHERWISE, and both of the properties it sets are quantities, so
   neither can live here: the width is a fraction of the frame in metres and the opacity is the data. A
   band with nothing to report is left with no style at all rather than removed from the drawing, which
   is what keeps the node set fixed while somebody scrubs.

   NO VECTOR-EFFECT HERE, DELIBERATELY, where the outlines and the marks all carry one. Those are lines
   that must stay the same weight at every zoom; this is a distance into a room, and a room drilled into
   is a bigger room on screen. Adding non-scaling-stroke would pin the band to a pixel width and break
   the one thing that makes it contained - the inset is in metres, and the stroke must be too.

   THE ROUND JOIN IS LOAD-BEARING. Where a shape's corner is tighter than the inset, the band's corner
   radius floors at zero and the join is the only thing keeping its outer edge inside the outline's own
   arc; a mitre there would put a spike of light outside the shape, which is the whole fault being
   fixed. */
.sitemap__glow[b-mw0009z2yr] {
    fill: none;
    stroke: var(--color-accent);
    stroke-opacity: 0;
    stroke-width: 0;
    stroke-linejoin: round;
    pointer-events: none;
}

/* One person. Ringed in the panel surface so a cluster reads as countable dots rather than as a
   blob, which is the whole reason marks are drawn instead of a number being printed.

   THE RING CAME DOWN WITH THE DOT, from 1.75, and it had to. A non-scaling stroke is a fixed number
   of pixels while the dot is a fraction of the panel, so the same ring is a hairline on a wide screen
   and a border on a phone - and a stroke is centred on the path, so it eats the fill from the inside
   as well as adding to the outside. Held at 1.75 against a mark of 0.014 its two bands would have
   taken 3.5 px out of an 8 px phone dot, nearly half, leaving the firm colour as a pinhole inside a
   grey circle and undoing the only job the colour has. Cut by the same fifth the mark was, the bands
   take a third of the small dot and a twelfth of the large one, which is where they already sat.

   It stops at 1.25 rather than going on to 1 because that is the width the place outlines already use
   and the thinnest line this stylesheet trusts to stay a line: below it a non-scaling stroke on an
   ordinary desktop display anti-aliases into a grey haze, and a ring nobody can see is a ring that is
   separating nothing. */
/* IT TAKES THE POINTER NOW, WHERE IT USED TO REFUSE IT, and that one removed line is the whole of
   this feature on the drawing's side. A mark was pointer-events: none so the place underneath kept
   every pixel of its own click target, which was right for exactly as long as a dot meant nothing
   anybody could ask about. It means something now: on a site run through a single contractor every
   dot on the plan wears one firm colour and the legend suppresses itself, so "which of these six is
   Ola" had no answer anywhere on the screen - and a dot that refuses the pointer cannot carry the
   <title> that answers it either, which is why one property blocked both halves of the question.

   WHAT IT COSTS THE PLACE UNDERNEATH, MEASURED AND WRITTEN DOWN HERE RATHER THAN DISCOVERED LATER.
   Pack will not put a mark in a shape narrower than 2.8 radii; the smallest place on this farm's plan
   that clears that is 26 px across on a desktop panel while the dot is 17, so a third of that shape's
   area stops being the place's target and becomes the person's. The corners and the rim stay the
   place's, a tank on the same plan gives up a fifteenth of itself, and everywhere the dot is not, the
   shape's own tooltip, hover and click are exactly as they were. That is the exchange: the smallest
   places give up a third of their middle so that every person on the drawing becomes somebody you can
   ask about. */
.sitemap__mark[b-mw0009z2yr] {
    fill: var(--chart-colour, var(--color-accent));
    stroke: var(--color-surface-container);
    stroke-width: 1.25;
    vector-effect: non-scaling-stroke;
    cursor: pointer;
}

/* WHICH DOT WILL TAKE THE CLICK, SAID BEFORE IT IS MADE. In a cluster the dots stand 2.8 radii apart
   and the pointer alone does not say which of them it is on; nor does the tooltip, which takes half a
   second to appear and is drawn beside the pointer rather than on the dot. The ring says it at once.
   It is also the drawing's answer to something it would otherwise get wrong: a place brightens its
   own outline on hover and now cannot, because the pointer is on the dot rather than on it - which is
   exactly correct, since the click will not go there either - so without this the drawing would look
   inert at the one moment it is being aimed at.

   THE RING AND NOT THE FILL, because the fill is the firm's colour, and the single thing a hover here
   must never do is make a dot look as though it belongs to another firm.

   --color-text AND NOT --color-primary, WHICH IS WHAT THE PLACE OUTLINES USE. This palette's primary
   is the brand ice blue, #cee7f7; on the white panel of the light theme it is very nearly the panel,
   and painted onto a ring that is ALREADY the panel colour it changes nothing a reader can see. A
   place survives that because it thickens its outline as well. A mark does not, because the ring is
   the entire highlight. --color-text is the theme's ink - near black on white, near white on the dark
   ground - so it reads against all eleven firm colours in both themes, which is the only property
   this ring actually needs to have.

   HOVER AND NOT FOCUS, because there is no focus to style. A mark is clickable and deliberately not
   focusable: it lives inside an aria-hidden SVG, where a focusable element is forbidden outright
   rather than merely unhelpful. The keyboard reaches the same state through the Person filter above
   the map, and the table at the foot of the component says so. */
.sitemap__mark:hover[b-mw0009z2yr] {
    stroke: var(--color-text);
    stroke-width: 2.5;
}

/* UNDIRECTED, AND THE QUIETEST HUE ON THE DRAWING. A link is context for the marks rather than a
   series of its own, so it is drawn in a neutral. The accent already means hours worked here - it is
   the lit rim on a busy place - and the firm colours already mean who a dot belongs to, so a link in
   either would be a third meaning in a hue that already carries two. Grey says the only thing a link
   has to say: these two dots are the same person.

   ONE WIDTH, BECAUSE A LINE IS ONE PERSON. It used to thicken with how many people made the pair,
   which meant a reader had to decode a stroke width against the other strokes on the plan to recover
   a number. Two people crossing the same two places are now two lines lying beside each other, which
   is the same fact drawn as what it is. Nothing about a link arrives inline any more.

   fill: none is not optional on a path. Without it the curve is filled between its two ends and
   becomes a solid wedge across the site.

   A PIXEL WIDTH, WHICH IS ONLY LEGITIMATE BECAUSE OF non-scaling-stroke. Every length in this
   drawing is a fraction of the frame, because user units here are metres - but a stroke that opts
   out of the user space is not a length in metres at all, which is exactly why the outlines, the
   grid, the scenery and the marks are written the same way. Remove the vector-effect and this
   becomes a line a metre and a bit wide: a band across a pump room.

   NO FADED ENDS ANY MORE, AND THE ANCHORING IS WHY. A gradient along each link existed to stop its
   ends competing with the marks, back when a line ran to the middle of a place and under whatever
   crowd was standing there. A line now stops at the edge of the one dot it belongs to, so its end is
   the thing that makes it readable - faded, it would read as not quite reaching the person it is
   about. That also takes two linearGradients, four stops each and a per-link class off the drawing. */
.sitemap__link[b-mw0009z2yr] {
    fill: none;
    stroke: var(--color-text-secondary);
    stroke-width: 1.25;
    stroke-opacity: 0.42;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

.sitemap__scale line[b-mw0009z2yr] {
    stroke: var(--color-text-muted);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
}

/* THE WORDS THAT SAY WHAT THE BAR IS, ANCHORED TO THE SAME SHARE OF THE DRAWING THE BAR IS. The bar
   is drawn in metre space at four percent of the drawing's height, with ticks a further one and two
   tenths of a percent either side, so the top of its left tick is at 5.2 percent - a distance that
   shrinks with the panel. Pinned instead to a constant eight pixels from the bottom, which worked
   only while the frame's padding held a sixteen pixel gutter under the drawing, the words landed in
   the bar's own band on every frame between about three hundred and five hundred and fifty pixels
   tall: the tick was drawn down through the letters and, on a site wider than it is tall, the bar's
   line ran through them as well. Clearing it downwards would need 0.028 of the drawing's height to
   exceed the top of the text - 821 pixels, which the cap makes unreachable - and there is no room
   below the tick for an eighteen pixel line box either, so the words go ABOVE the bar, which is the
   only side with room at every size. Left-aligned on four percent for the same reason: that is where
   the bar starts, whatever the panel is doing. */
.sitemap__scale-label[b-mw0009z2yr] {
    position: absolute;
    bottom: calc(5.2% + var(--space-1));
    left: 4%;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-variant-numeric: tabular-nums;

    /* The words sit over the drawing now rather than in a gutter below it, and ExtentOf's four
       percent margin is exactly the strip the bar occupies - so a shape at the foot of the plan can
       reach them. The same halo the place names wear, for the same reason. */
    text-shadow:
        0 0 3px var(--color-surface-container),
        0 0 3px var(--color-surface-container),
        0 0 6px var(--color-surface-container);
}

/* WHAT THE FRAME SAYS, IN FIGURES, directly under the drawing - because during playback this is the
   part that moves, and a reader watching the shapes needs the numbers in the same glance. Tabular
   figures so a count changing from 9 to 10 does not shift everything beside it. */
.sitemap__readout[b-mw0009z2yr] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-5);
    padding: var(--space-3) var(--space-4);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.sitemap__figure[b-mw0009z2yr] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

.sitemap__figure-value[b-mw0009z2yr] {
    color: var(--color-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.sitemap__figure-label[b-mw0009z2yr] {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* WHICH WAY IT WENT SINCE THE FRAME BEFORE. Two neutral directions rather than green and red: fewer
   people on a site is a finish, an evacuation or a Sunday, and this screen cannot tell which. */
.sitemap__delta[b-mw0009z2yr] {
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    font-variant-numeric: tabular-nums;
}

.sitemap__delta--up[b-mw0009z2yr] {
    background-color: var(--color-primary-subtle);
    color: var(--color-primary-active);
}

.sitemap__delta--down[b-mw0009z2yr] {
    background-color: var(--color-surface-contrast);
    color: var(--color-text-secondary);
}

/* THE WHOLE PERIOD AS A ROW OF BARS, above the track that scrubs it. A scrub bar says how far
   through you are and nothing about what is on either side, so playback is a surprise every time.
   It also gives empty days a shape: a weekend is visibly a gap in a row rather than a map that
   looks like it failed to load. */
.sitemap__strip[b-mw0009z2yr] {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 1.75rem;
    padding: var(--space-2);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

.sitemap__tick[b-mw0009z2yr] {
    position: relative;
    flex: 1 1 0;
    min-width: 2px;
    height: 100%;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
}

/* The bar itself is the pseudo-element, so the button stays full height and therefore a full-height
   click target. A one-pixel-tall day would otherwise be a one-pixel-tall thing to hit. */
.sitemap__tick[b-mw0009z2yr]::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: var(--fill);
    border-radius: 1px;
    background-color: var(--color-primary);
    opacity: 0.45;
    transition: opacity var(--motion-duration-base) var(--motion-easing-standard);
}

.sitemap__tick:hover[b-mw0009z2yr]::after {
    opacity: 0.6;
}

/* A day with nothing recorded keeps a stub, so the row stays a row and the gap is visibly a gap
   rather than a hole where a control should be. */
.sitemap__tick--empty[b-mw0009z2yr]::after {
    background-color: var(--color-border-strong);
    opacity: 0.3;
}

.sitemap__tick--on[b-mw0009z2yr]::after {
    opacity: 1;
}

/* The frame being shown, marked the full height of the strip AND underlined, rather than only by the
   height its own bar happens to reach. On a quiet day - and quiet days are exactly when somebody is
   hunting for the marker - the bar is a stub, so brightening it marks nothing. */
.sitemap__tick--on[b-mw0009z2yr] {
    box-shadow: inset 0 -2px 0 var(--color-primary);
}

/* The frame being shown, marked the full height of the strip rather than only as far as its bar
   reaches - otherwise the current day is unfindable on a quiet one, which is exactly when somebody
   is looking for it. */
.sitemap__tick--on[b-mw0009z2yr]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 0;
    border-radius: 2px;
    background-color: var(--color-primary);
    opacity: 0.18;
}

.sitemap__tick:focus-visible[b-mw0009z2yr] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 1px;
}

/* Only ever shown when there is more than one firm to tell apart, so this is a legend rather than a
   label. It reorders itself as the animation runs, which on a site run through subcontractors is
   itself worth watching. */
.sitemap__firms[b-mw0009z2yr] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-inline-start: auto;
}

.sitemap__firm[b-mw0009z2yr] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--font-size-sm);
}

/* THE SAME DOT THE MAP DRAWS, at the size a line of text can carry. It cannot literally match a mark
   and should not try: a mark is a fraction of the panel, so it is about 6 px in a hand and 28 px on a
   wide screen, whereas this sits in a row of small text and has to hold still at one size. So it came
   down when the mark did, from 0.7rem, but it lands on the size the heatmap legend already uses for
   exactly this - a round dot beside a name at --font-size-sm - rather than on a fifth off the old
   number, which would have made the one legend on this screen smaller than every other legend in the
   application while claiming to track something that has no fixed size. A swatch too small to read a
   hue off is a legend that has stopped explaining anything.

   NO RING ON THIS ONE, deliberately. A mark is ringed because it sits ON a place's fill, whose
   colour it cannot know, and a step of 2.8 radii from the next mark in a cluster; the ring in the
   panel surface is what holds those apart. A swatch has neither neighbour: it sits alone in a row
   of text, on --color-surface-inset, the readout strip's own flat ground. A ring there would be
   separating the colour from nothing, and its only effect would be to make the swatch bigger. */
.sitemap__swatch[b-mw0009z2yr] {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: var(--radius-full);
    background-color: var(--chart-colour, var(--color-accent));
}

.sitemap__firm-name[b-mw0009z2yr] {
    color: var(--color-text-secondary);
}

.sitemap__firm-count[b-mw0009z2yr] {
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.sitemap__play[b-mw0009z2yr] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

.sitemap__play-button[b-mw0009z2yr] {
    min-width: calc(var(--space-8) + var(--space-4));
}

/* Takes the slack, because scrubbing is the control people reach for most and a short track is a
   fiddly one. */
.sitemap__scrub[b-mw0009z2yr] {
    flex: 1 1 12rem;
    min-width: 0;
}

.sitemap__speeds[b-mw0009z2yr] {
    display: flex;
    gap: var(--space-1);
}

.sitemap__speed[b-mw0009z2yr] {
    padding: var(--space-1) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background-color: var(--color-surface);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.sitemap__speed--on[b-mw0009z2yr] {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-medium);
}

.sitemap__speed:focus-visible[b-mw0009z2yr],
.sitemap__crumb:focus-visible[b-mw0009z2yr] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* What a dot means, in words. Ordinary text rather than a title attribute: the reader it is written
   for is the one about to quote the dot count as a head count, and they are not going to hover over
   anything to find out they should not. */
.sitemap__note[b-mw0009z2yr] {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
}

.sitemap__note--warn[b-mw0009z2yr] {
    color: var(--color-warning-text);
}

/* A phone gives the panel a third of the width, and the full desktop cap would put a 44rem box on a
   screen that is barely taller than one.

   THE CAP MOVES, THE SHAPE DOES NOT. This lowers the frame's own cap rather than clipping the SVG and
   the names inside it, and the difference is the whole of this rule. The frame's height comes from the
   inline aspect-ratio on a full-width border box, so it does not shrink when its contents do: clipping
   the children left the frame at the ratio height with the drawing in the top of it - on a 40 x 200 m
   site at 320px, a 704px box holding a 256px drawing, 445px of empty ground, the "Nothing recorded"
   pill floating 95px below the last row of the plan and the scale words 450px from the bar they label.
   Worse, an SVG viewport that is no longer the viewBox's shape is one preserveAspectRatio="none"
   stretches into: the same site was drawn 2.7 times wider than tall, a metre square as a lying
   rectangle on a grid this screen invites the reader to count, and every metre-space judgement the
   geometry makes - NameClearFraction, IsLegible, the mark radius - was out by that factor in one axis.
   A stretched scale drawing is not a scale drawing.

   Lowering the cap instead costs the width the ratio says it costs and nothing else. The component
   turns this number into the matching max-width, so the frame keeps the viewBox's shape, the SVG's
   height: 100% and the names layer's inset: 0 follow it exactly, and the pill and the scale words stay
   on the drawing because the drawing is still the whole box. */
@media (max-width: 30rem) {
    .sitemap__frame[b-mw0009z2yr] {
        --sitemap-cap: calc(var(--space-8) * 4);
    }

    /* =========================================================================
       NO NAMES ON A PHONE, AND THIS IS THE GATE'S OWN ARGUMENT TAKEN TO ITS END
       -------------------------------------------------------------------------
       The gate that decides whether a shape is wide enough for its name is
       measured in metres, from a frame assumed to be about seven hundred pixels
       wide - the component says so in as many words, and says that nothing can
       measure the real panel. A phone gives this panel about 294. The metres do
       not change, so the same shapes still qualify; but each is drawn at about
       two fifths of the pixels while every label stays at its fixed size. The
       gate therefore passes names roughly two and a half times wider than the
       shapes they sit on, which is not a caption - it is a drawing with words
       spilled across it.

       The component already knows what to do about that, for the case it could
       foresee: "a name spilling across three neighbours is what makes a drawing
       look amateur", and a place's name "is still in the table below, in the
       tooltip on its shape and one click away". At this width every name spills,
       so every name goes, and what is left is the thing a phone can actually
       read: shapes to scale, shaded by hours, with people on them.

       CSS AND NOT THE GATE, deliberately. Changing Labelled or Tagged would put
       a width-dependent branch in metre arithmetic that the site-map editor
       shares and that nothing tests, in a file of 2,688 lines. This decides one
       thing - whether the names layer is painted - at the only place that knows
       the answer, and it cannot reach a desktop.

       THE COST, AND IT IS REAL: scenery loses its captions too, and scenery is
       the one kind of label with no other route - it has no table row, no
       tooltip and no click. See SiteMapGeometry.Captions, which argues exactly
       that. A road on a phone is now an unnamed grey band. That is the trade,
       and it is the right way round: an unnamed band reads as ground, where a
       caption three times its width reads as a fault.
       ========================================================================= */
    .sitemap__label[b-mw0009z2yr] {
        display: none;
    }
}

/* Playback is motion nobody asked for. The scrubber still works, so the picture stays reachable. */
@media (prefers-reduced-motion: reduce) {
    .sitemap__play-button[b-mw0009z2yr] {
        display: none;
    }
}

/* Said on the drawing rather than only in the figures below it: during playback an empty frame is on
   screen for a second, and a blank plan with a "0" somewhere underneath reads as a map that broke. */
.sitemap__nothing[b-mw0009z2yr] {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-full);
    background-color: color-mix(in srgb, var(--color-surface-container) 88%, transparent);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    pointer-events: none;
}

/* THE REFERENCE DESIGNATION, UNDER THE NAME. A real plan prints both against every space - the
   description says what it is, the tag says which one - and the tag is what somebody holding the CAD
   sheet or a work order is reading. Quieter and smaller than the name, because it is the second
   question, not the first. */
.sitemap__tag[b-mw0009z2yr] {
    display: block;
    color: var(--color-text-muted);
    font-size: 0.6rem;
    font-weight: var(--font-weight-regular);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.03em;
}
/* /Features/Reports/Pages/Reports.razor.rz.scp.css */
/* A vertical stack of blocks - filters, figures, the board of charts, the table - so
   spacing comes from the .stack primitive in base.css rather than from margins on
   each block. Only what that primitive cannot say lives here. */
.reports[b-6sojhoq4kd] {
    --stack-gap: var(--space-6);
}

/* The charts. Two columns where there is room, one on a phone, and a panel may claim
   the full width when its shape needs it - the bar list, the heatmap and the table are
   all wider than they are tall.

   auto-fit with a floor rather than a fixed two columns: on a wide monitor the third
   column arrives on its own, and there is no breakpoint to keep in step. */
.reports__board[b-6sojhoq4kd] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    gap: var(--space-5);
    /* Tops aligned. Panels are different heights and a centred row would leave their
       headings on different lines - the rule the rest of the application follows. */
    align-items: start;
}

.reports__panel--wide[b-6sojhoq4kd] {
    grid-column: 1 / -1;
}

.reports__panel[b-6sojhoq4kd] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);
}

.reports__panel-title[b-6sojhoq4kd] {
    margin: 0;
    font-size: var(--font-size-lg);
}

.reports__panel-hint[b-6sojhoq4kd] {
    margin: 0;
    max-width: 40rem;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

@media (max-width: 48rem) {
    .reports__panel[b-6sojhoq4kd] {
        padding: var(--space-4);
    }
}

/* THE CHARTS GO STALE WITH THE FIGURES ABOVE THEM. A failed request leaves the previous answer on
   every panel, and until now it sat at full strength beneath a red notice - which is how a number
   from last month's filter gets read out as this month's. The same 0.55 the totals row has always
   dimmed to while loading, so "old" looks the same everywhere on the page. */
.reports__board--stale[b-6sojhoq4kd] {
    opacity: 0.55;
}
/* /Features/Reports/ReportFilters.razor.rz.scp.css */
/* The whole control surface of the screen, so it reads as one thing rather than as
   a row of loose controls above some charts. On the container surface with a border,
   the same treatment the work log composer gets for the same reason. */
.report-filters[b-7623u16kyu] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-container);

    /* The three primary controls are measured against this box rather than the
       window - the box is the window minus a sidebar that is there on a laptop and
       gone on a tablet. */
    container-type: inline-size;
}

/* One column on a phone, three across when there is room. Tops aligned, because
   the three controls are different heights and a centred row would leave their
   labels on three different lines. */
.report-filters__primary[b-7623u16kyu] {
    display: grid;
    gap: var(--space-4);
    align-items: start;
}

@container (min-width: 44rem) {
    .report-filters__primary[b-7623u16kyu] {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--space-5);
    }
}

/* THE THIRD BOX HAD ITS LABEL IN THE WRONG PLACE, AND THAT IS WHY IT SAT LOW.
   -----------------------------------------------------------------------------
   Period and What counts are SegmentedChoice, which prints its label ABOVE the
   control. Group by is CompactChoice, which prints its label INSIDE the collapsed
   row, on the left, with the value on the right. So the third box had nothing on
   the line the other two put their labels on, and its one row started where their
   options started - reading as a box dropped half a step down the row.

   CompactChoice already carries both shapes in its markup for exactly this reason
   ("BOTH SHAPES ARE ALWAYS IN THE MARKUP, and which one shows is a layout question")
   and JobPanel.razor.css uses the same three ::deep switches to take the other
   branch. The difference is that JobPanel hides the row and shows every option;
   here the row is kept - there is no space on a filter strip for seven group-by
   options - and only the label moves out of it.

   ::deep because every one of these belongs to CompactChoice's own markup and so
   never carries this file's scope attribute. */
.report-filters__primary[b-7623u16kyu]  .compact-choice__asked {
    display: block;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* The label is above now, so the copy inside the row would be a second one - but it is
   CLIPPED RATHER THAN REMOVED, and the difference is the whole accessible name of the
   control. CompactChoice's summary button carries no aria-label and no aria-labelledby:
   its name is computed from its contents, and this span is the only part of them that
   says what the button is about. display:none takes it out of the accessibility tree
   too, and the button then announces itself as "Kind of work, collapsed, button" - the
   name of its current VALUE, which on this screen is also the legend of a filter
   fieldset and the text of a chip. Three different controls, one announced name.

   Clipped, the text stays in the tree and the button still announces "Group by
   (required) Kind of work". The visible label above is .compact-choice__asked, which is
   a plain span with no id, so it cannot be pointed at instead.

   position:absolute also takes it out of the grid flow, which is what the two-column
   rule below is written against. */
.report-filters__primary[b-7623u16kyu]  .compact-choice__label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* With the question clipped out of the row's flow, the answer takes the space it was
   using. Left, because the row now reads as a field's value under its label rather than
   as a question and its answer facing each other across a form. Two columns rather than
   three: the clipped label is absolutely positioned and so places no grid item. */
.report-filters__primary[b-7623u16kyu]  .compact-choice__summary {
    grid-template-columns: minmax(0, 1fr) auto;
}

.report-filters__primary[b-7623u16kyu]  .compact-choice__value {
    justify-self: start;
}

.report-filters__dates[b-7623u16kyu] {
    display: grid;
    gap: var(--space-4);
    align-items: start;
}

@container (min-width: 30rem) {
    .report-filters__dates[b-7623u16kyu] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* A CONTROL, NOT A FOOTNOTE. This was a bare blue link reading "Narrow these numbers",
   which drew the screen's second most useful control at the weight of small print -
   and people did not find it. It is now a bordered, button-shaped target on the input
   surface: the same treatment CompactChoice gives its own summary row, so the two
   disclosures on this screen read as the same kind of thing.

   Still a <summary> rather than a <button>, because <details> keeps the open state
   without any of this file's making, and a real button would need it back in C#. */
.report-filters__more > summary[b-7623u16kyu] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    padding: var(--space-2) var(--space-4);

    /* It is a primary control on a screen people use on a tablet, so it takes the same
       floor every other tapped target does. Without it the padding alone gives about
       42px, which is under it. */
    min-height: var(--layout-touch-target-min);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-input);
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);

    /* The default marker would sit beside the chevron this file draws, and two
       triangles pointing different ways is worse than either alone. */
    list-style: none;
}

.report-filters__more > summary[b-7623u16kyu]::-webkit-details-marker {
    display: none;
}

.report-filters__more > summary:hover[b-7623u16kyu] {
    border-color: var(--color-primary);
}

.report-filters__more > summary:focus-visible[b-7623u16kyu] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* Turns with the disclosure, so the row says whether pressing it opens or closes
   before anybody presses it. */
.report-filters__more-icon[b-7623u16kyu] {
    display: flex;
    align-items: center;
    color: var(--color-text-muted);
}

/* Open, it stays lit so the panel below has something it visibly belongs to. Its corners
   are deliberately NOT flattened into the panel: the summary is inline-flex and sized to
   its own words, so joining a short tab to a full-width panel would draw an edge that
   lines up with nothing on the right. */
.report-filters__more[open] > summary[b-7623u16kyu] {
    border-color: var(--color-primary);
}

/* How many filters are hidden behind the disclosure. Carries a number rather than
   a dot, because "3" tells the reader how much of what they are looking at is not
   the whole picture and a dot only says "some". */
.report-filters__count[b-7623u16kyu] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    padding: 0 var(--space-1);
    border-radius: var(--radius-pill);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.report-filters__panel[b-7623u16kyu] {
    display: grid;
    gap: var(--space-5);
    align-items: start;
    padding: var(--space-4);
    margin-top: var(--space-2);
    border: var(--border-width) solid var(--color-border-muted);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-inset);
}

@container (min-width: 44rem) {
    .report-filters__panel[b-7623u16kyu] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: var(--space-6);
    }
}

.report-filters__group[b-7623u16kyu] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.report-filters__group > legend[b-7623u16kyu] {
    padding: 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.report-filters__chips[b-7623u16kyu] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* A chip is on or off, and says so with a border and a fill rather than with colour
   alone - the same value has to be readable to somebody who cannot tell the two
   greens apart. aria-pressed carries it to a screen reader. */
.report-filters__chip[b-7623u16kyu] {
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background-color: var(--color-surface);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.report-filters__chip:hover[b-7623u16kyu] {
    border-color: var(--color-primary);
    color: var(--color-text);
}

.report-filters__chip--on[b-7623u16kyu] {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--font-weight-medium);
}

.report-filters__chip:focus-visible[b-7623u16kyu] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* Always visible when anything is narrowing the numbers, whether or not the panel
   above is open. This is the line that stops somebody reading a filtered figure as
   the whole site's. */
.report-filters__active[b-7623u16kyu] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border-muted);
}

.report-filters__active-label[b-7623u16kyu] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.report-filters__remove[b-7623u16kyu] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background-color: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.report-filters__remove:hover[b-7623u16kyu] {
    border-color: var(--color-danger);
    color: var(--color-danger-text);
}

.report-filters__remove:focus-visible[b-7623u16kyu] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

.report-filters__clear[b-7623u16kyu] {
    margin-inline-start: auto;
}

@media (max-width: 48rem) {
    .report-filters[b-7623u16kyu] {
        padding: var(--space-4);
    }
}
/* /Features/Reports/ReportJobsTable.razor.rz.scp.css */
/* The wrapper is load-bearing, not decoration: CSS isolation stamps this file's scope
   attribute onto elements written HERE, and <RecordTable> is a component tag. Without
   a real element to hang it on, every ::deep rule below would have nothing to descend
   from. */
.report-jobs[b-8u0s8hpf88] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.report-jobs__day[b-8u0s8hpf88] {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.report-jobs__who[b-8u0s8hpf88],
.report-jobs__work[b-8u0s8hpf88] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.report-jobs__company[b-8u0s8hpf88],
.report-jobs__cost[b-8u0s8hpf88] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* The third line of the Work cell, and quieter still than the second - it is the
   one that is often absent, so it must not leave a hole in the rows that have it
   when read down the column. Italic rather than another size, because a third size
   in one cell is a cell nobody can scan. */
.report-jobs__phase[b-8u0s8hpf88] {
    font-size: var(--font-size-xs);
    font-style: italic;
    color: var(--color-text-muted);
}

.report-jobs__place[b-8u0s8hpf88] {
    color: var(--color-text-secondary);
}

.report-jobs__hours[b-8u0s8hpf88] {
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

/* The evidence column, and the only one allowed to be long. Clamped to three lines so
   one verbose entry cannot make a row taller than the screen; the whole sentence is on
   the day it links to. */
.report-jobs__description[b-8u0s8hpf88] {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* Below the breakpoint RecordTable turns every row into a card, and a clamped cell in
   a card reads as truncation for no reason - there is width to spare there. */
@media (max-width: 48rem) {
    .report-jobs__description[b-8u0s8hpf88] {
        -webkit-line-clamp: none;
        line-clamp: none;
        overflow: visible;
    }
}
/* /Features/Reports/ReportTotals.razor.rz.scp.css */
.report-totals[b-2dj9zhj5tq] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Dimmed rather than blanked while a newer filter is in flight. Blanking makes the
   whole screen flash on every click; dimming says "about to change" and keeps the
   reader's place. */
.report-totals--busy[b-2dj9zhj5tq] {
    opacity: 0.55;
}

.report-totals__sentence[b-2dj9zhj5tq] {
    margin: 0;
    font-size: var(--font-size-lg);
    line-height: var(--line-height-snug);
    color: var(--color-text);
    max-width: 46rem;
}

/* Auto-fit rather than a fixed count: five figures on a laptop, two on a phone, and
   no breakpoint to keep in step with the number of them. */
.report-totals__figures[b-2dj9zhj5tq] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(8rem, 45%), 1fr));
    gap: var(--space-4);
    margin: 0;
}

/* Each figure carries a coloured top rule tying it to the thing it counts - the same
   device the calendar and the site overview already use, so it arrives pre-learned. */
.report-totals__figure[b-2dj9zhj5tq] {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-top: var(--space-3);
    border-top: 3px solid var(--color-border-strong);
}

.report-totals__figure > dt[b-2dj9zhj5tq] {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.report-totals__figure > dd[b-2dj9zhj5tq] {
    margin: 0;
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-tight);
    /* Digits in a row of figures have to line up, and these are read as a set. */
    font-variant-numeric: tabular-nums;
}

.report-totals__figure--hours[b-2dj9zhj5tq] { border-top-color: var(--color-primary); }
.report-totals__figure--jobs[b-2dj9zhj5tq] { border-top-color: var(--color-category-5); }
.report-totals__figure--days[b-2dj9zhj5tq] { border-top-color: var(--color-category-7); }
.report-totals__figure--outside[b-2dj9zhj5tq] { border-top-color: var(--color-warning); }
.report-totals__figure--waiting[b-2dj9zhj5tq] { border-top-color: var(--color-danger); }

.report-totals__note[b-2dj9zhj5tq] {
    margin: 0;
    max-width: 46rem;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}
/* /Layout/AccountMenu.razor.rz.scp.css */
/* The wrapper does nothing but anchor the panel. The top bar lays out the button,
   which is why this has no size, no padding and no colour of its own. */
.account-menu[b-qhfxvmhjsz] {
    position: relative;
    display: inline-flex;
}

/* Square and round, in the same terms as the theme toggle that used to stand here,
   so the trailing edge of the bar keeps the shape and the touch target it had.
   Positioned because the marker below is placed against it. */
.account-menu__button[b-qhfxvmhjsz] {
    position: relative;
    width: var(--layout-touch-target-min);
    min-width: var(--layout-touch-target-min);
    padding: 0;
    border-radius: var(--radius-full);
}

/* The dot that says there is something about this identity worth opening the menu
   for. Ringed in the bar's own colour so it stays legible where it overlaps the
   icon, in either theme. */
.account-menu__marker[b-qhfxvmhjsz] {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    width: var(--space-2);
    height: var(--space-2);
    border-radius: var(--radius-full);
    box-shadow: 0 0 0 var(--border-width) var(--color-topbar-background);
}

/* The two tones of the badges they stand for: a caution, and a statement. */
.account-menu__marker--warning[b-qhfxvmhjsz] {
    background-color: var(--color-warning);
}

.account-menu__marker--danger[b-qhfxvmhjsz] {
    background-color: var(--color-danger);
}

/* Fixed and transparent: it exists to catch the click that dismisses, not to dim
   the page. A menu does not block the application, and a scrim would say it does. */
.account-menu__backdrop[b-qhfxvmhjsz] {
    position: fixed;
    inset: 0;
    z-index: var(--z-dropdown);
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-none);
    background-color: transparent;
    cursor: default;
}

/* Base.css lays a translucent state layer over every button on hover and press.
   Over a full-screen element that would tint the entire application grey the moment
   the pointer moved, so this one opts out of both. */
.account-menu__backdrop:hover:not(:disabled)[b-qhfxvmhjsz],
.account-menu__backdrop:active:not(:disabled)[b-qhfxvmhjsz] {
    background-image: none;
    border-color: transparent;
}

.account-menu__panel[b-qhfxvmhjsz] {
    position: absolute;
    top: calc(100% + var(--space-2));
    right: 0;
    /* One above the backdrop, which is already above the page. */
    z-index: calc(var(--z-dropdown) + 1);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 14rem;
    /* Never wider than the screen it drops onto. At 320px a fixed width would push
       the panel off the leading edge and take the name with it. */
    max-width: min(18rem, calc(100vw - var(--space-6)));
    padding: var(--space-3);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    background-color: var(--color-surface-overlay);
    box-shadow: var(--shadow-lg);
    /* Short enough to read as "it came from the button" rather than as a delay.
       base.css already reduces every animation to nothing for a reader who asked
       for less motion, so there is no guard to repeat here. */
    animation: account-menu-open-b-qhfxvmhjsz var(--motion-duration-fast) var(--motion-easing-standard);
}

@keyframes account-menu-open-b-qhfxvmhjsz {
    from {
        opacity: 0;
        transform: translateY(calc(var(--space-1) * -1));
    }
}

/* The panel takes focus when it opens; that is orientation rather than an error, so
   it should not also draw a keyboard focus ring around the whole box. */
.account-menu__panel:focus[b-qhfxvmhjsz] {
    outline: none;
}

.account-menu__identity[b-qhfxvmhjsz] {
    display: flex;
    flex-direction: column;
    /* Start rather than stretch, so a badge is the width of its word instead of the
       width of the panel. */
    align-items: flex-start;
    gap: var(--space-2);
}

.account-menu__user[b-qhfxvmhjsz] {
    margin: 0;
    font-weight: var(--font-weight-medium);
    /* A long name wraps instead of widening the panel past the edge of the screen. */
    overflow-wrap: anywhere;
}

/* The same two badges the top bar used to carry, unchanged in tone: they are the
   only things in this panel that are about a problem rather than a choice. */
.account-menu__badge[b-qhfxvmhjsz] {
    margin: 0;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-full);
    background-color: var(--color-warning-subtle);
    color: var(--color-warning-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
}

/* Louder than the warning above it: a fake identity is not a caution, it is a
   statement. */
.account-menu__badge--development[b-qhfxvmhjsz] {
    background-color: var(--color-danger-subtle);
    color: var(--color-danger-text);
}

/* The rule is on the TOP of the row rather than the bottom of the block above it,
   so nothing is left dangling under the last item when there is no action below -
   which is exactly the development sign-in's case. */
.account-menu__row[b-qhfxvmhjsz] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-width) solid var(--color-border-muted);
}

.account-menu__row-label[b-qhfxvmhjsz] {
    color: var(--color-text-secondary);
}

/* Sign out and Sign in are the same row in two states, so they are one class across
   a button and an anchor. Full width because this is the bottom of a narrow panel
   on a phone, where a control that stops halfway across reads as unfinished.
   Transparent rather than filled: the panel already sits on the overlay surface, and
   a container-coloured fill inside it reads as a hole in the dark theme. */
.account-menu__action[b-qhfxvmhjsz] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-4);
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background-color: transparent;
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
}

/* base.css gives buttons the state layer for free but not anchors, and Sign in is an
   anchor because it is a real navigation to the sign-in endpoint. Stated here so the
   two states of this row cannot look different from one another. */
.account-menu__action:hover[b-qhfxvmhjsz],
.account-menu__action:focus-visible[b-qhfxvmhjsz] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
    border-color: var(--color-border-outline);
    color: var(--color-text);
}

.account-menu__action:active[b-qhfxvmhjsz] {
    background-image: linear-gradient(var(--color-state-pressed), var(--color-state-pressed));
}
/* /Layout/AppUpdateBanner.razor.rz.scp.css */
/* =============================================================================
   The new-version bar

   Sits between the top bar and the content, full width, and pushes rather than
   covers. A floating snackbar would sit over whatever is at the bottom of the
   screen - on a phone that is usually the primary action of the page - and this
   is not urgent enough to be in the way of work.
   ============================================================================= */

.app-update[b-e6ga8wb4jz] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-2) var(--space-4);
    border-bottom: var(--border-width) solid var(--color-info);
    background-color: var(--color-info-subtle);
    color: var(--color-text);
}

.app-update__text[b-e6ga8wb4jz] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
    /* Takes the row and lets the button sit at its end; on a narrow screen the
       button wraps beneath rather than squeezing the sentence to two words. */
    flex: 1 1 12rem;
    margin: 0;
    min-width: 0;
    font-size: var(--font-size-sm);
}

.app-update__title[b-e6ga8wb4jz] {
    font-weight: var(--font-weight-semibold);
}

/* The second half of the sentence, and the first thing to go when the bar is
   narrow: "A new version is ready" beside a button saying "Update now" is
   already the whole message. */
.app-update__detail[b-e6ga8wb4jz] {
    color: var(--color-text-secondary);
}

@media (max-width: 30rem) {
    .app-update__detail[b-e6ga8wb4jz] {
        display: none;
    }
}

/* A real button rather than a link. This is the one thing on the bar to do, it
   is being offered to somebody holding a phone in one hand, and it has to be a
   target rather than a word. */
.app-update__action[b-e6ga8wb4jz] {
    flex: 0 0 auto;
    min-height: var(--layout-touch-target-min);
    padding: var(--space-1) var(--space-4);
    border: var(--border-width) solid var(--color-info);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-container);
    color: var(--color-text);
    font: inherit;
    font-weight: var(--font-weight-medium);
    cursor: pointer;
}

.app-update__action:hover:not(:disabled)[b-e6ga8wb4jz] {
    background-image: linear-gradient(var(--color-state-hover), var(--color-state-hover));
}

.app-update__action:focus-visible[b-e6ga8wb4jz] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

.app-update__action:disabled[b-e6ga8wb4jz] {
    cursor: default;
    opacity: 0.7;
}
/* /Layout/NavMenu.razor.rz.scp.css */
/* =============================================================================
   Sidebar navigation

   WHY ::deep IS EVERYWHERE BELOW
   NavLink is a *component*, and Blazor's CSS isolation only stamps this component's
   scope attribute onto elements written in this file's own markup - never onto
   markup another component renders. So `.nav-menu__link { ... }` compiles to
   `.nav-menu__link[b-xxxxx]`, which the <a> that NavLink renders never carries, and
   the rule silently does nothing. Every nav link in this application was therefore
   unstyled - falling through to the global `a` rule and rendering as plain blue
   text - until these selectors were rewritten with ::deep.

   ::deep drops the attribute from the *last* compound selector and keeps it on the
   ancestor, giving `.nav-menu__nav[b-xxxxx] .nav-menu__link`. That matches, because
   .nav-menu__nav IS in this file's markup.
   ============================================================================= */

.nav-menu[b-eo4yn9h18n] {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.nav-menu__brand[b-eo4yn9h18n] {
    display: flex;
    align-items: center;
    min-height: var(--layout-topbar-height);
    padding: 0 var(--space-4);
    /* Lines up with the top bar's own bottom border across the shell. */
    border-bottom: var(--border-width) solid var(--color-sidebar-border);
}

/* A plain <a> in this file's markup, so no ::deep needed here. */
.nav-menu__brand a[b-eo4yn9h18n] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--color-sidebar-text-active);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-tight);
    text-decoration: none;
}

/* THE SAME FILE THE BROWSER TAB AND THE INSTALLED APP USE, at a size the sidebar can spare. One
   asset for all three places means the mark cannot drift between them - the tab, the home screen and
   the sidebar are the three places somebody recognises this product, and three files would be three
   chances for one of them to be a version behind.

   The radius matches the artwork's own corners so the square does not read as a screenshot of an
   icon; flex-shrink is off because a mark that squashes is worse than a name that truncates. */
.nav-menu__logo[b-eo4yn9h18n] {
    flex: 0 0 auto;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--radius-sm);
}

.nav-menu__nav[b-eo4yn9h18n] {
    /* Horizontal padding on the container, not the items: it is what insets the
       rounded highlight from the sidebar edge so it reads as a pill rather than a
       full-width band. */
    padding: var(--space-3) var(--space-2);
    overflow-y: auto;
}

.nav-menu__section[b-eo4yn9h18n] {
    margin: var(--space-5) var(--space-3) var(--space-2);
    color: var(--color-sidebar-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
}

.nav-menu__list[b-eo4yn9h18n] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.nav-menu__nav[b-eo4yn9h18n]  .nav-menu__link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: var(--layout-touch-target-min);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    color: var(--color-sidebar-text);
    text-decoration: none;
    transition:
        background-color var(--motion-duration-fast) var(--motion-easing-standard),
        color var(--motion-duration-fast) var(--motion-easing-standard);
}

/* Overrides the global `a:hover` underline: in a nav list an underline on hover
   reads as a text link in prose rather than as a row in a menu. */
.nav-menu__nav[b-eo4yn9h18n]  .nav-menu__link:hover {
    background-color: var(--color-state-hover);
    color: var(--color-sidebar-text-active);
    text-decoration: none;
}

/* NavLink adds this class for the currently routed entry. */
.nav-menu__nav[b-eo4yn9h18n]  .nav-menu__link.active {
    background-color: var(--color-state-selected);
    color: var(--color-sidebar-text-active);
    font-weight: var(--font-weight-medium);
}

/* The accent is spent on one thing - which entry you are on. Everything else in
   the sidebar stays monochrome so this reads at a glance. */
.nav-menu__nav[b-eo4yn9h18n]  .nav-menu__link.active .app-icon {
    color: var(--color-accent);
}

/* Slightly smaller than the default icon size: at the nav's text size a 20px icon
   out-weighs its label. */
.nav-menu__nav[b-eo4yn9h18n]  .app-icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* The links are the drawer's whole content below 64rem, so they get the roomier
   touch target there rather than the compact desktop one. */
@media (max-width: 64rem) {
    .nav-menu__nav[b-eo4yn9h18n]  .nav-menu__link {
        min-height: calc(var(--layout-touch-target-min) + var(--space-1));
    }
}
/* /Layout/SiteSwitcher.razor.rz.scp.css */
/* Sits in the top bar between the drawer toggle and the theme control. Set in the
   same terms as its neighbours: the icon at text size, the name at the base size,
   and nothing that makes the bar taller than the toggle already does. */
.site-switcher[b-cgwpd5vsih] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--color-text-secondary);
}

/* The name is what gives way when the bar runs out of room - on a phone the
   hamburger, the theme toggle and the account control all have to survive, and a
   truncated site name still says which site you are on. */
.site-switcher__name[b-cgwpd5vsih],
.site-switcher__select[b-cgwpd5vsih] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-switcher__name[b-cgwpd5vsih] {
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

/* Styled as text rather than as a form control. It is a statement of where you are
   that happens to be changeable, and a bordered input in a top bar reads as
   something waiting to be filled in. The chevron is the only affordance it needs,
   and the browser supplies that. */
.site-switcher__select[b-cgwpd5vsih] {
    max-width: 14rem;
    padding: var(--space-1) var(--space-2);
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-md);
    background-color: transparent;
    color: var(--color-text);
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
}

.site-switcher__select:hover[b-cgwpd5vsih] {
    border-color: var(--color-border);
    background-color: var(--color-surface-hover);
}

/* Focus is the one state that must not be quiet. */
.site-switcher__select:focus-visible[b-cgwpd5vsih] {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* The list itself is drawn by the operating system, which does not inherit the
   transparent background above - so the options need a real surface or they are
   white-on-white in dark mode on some platforms. */
.site-switcher__select option[b-cgwpd5vsih] {
    background-color: var(--color-surface);
    color: var(--color-text);
}

/* Decorative, and the first thing to go when the bar is narrow. The control beside it already says
   what it is - a site's name in the top bar is not mistakable for anything else - so on a phone the
   icon is spending the width that the name itself needs. Hidden rather than removed from the markup,
   because on a wide bar it is the thing that makes the name read as a place rather than as a page
   title. */
.site-switcher__icon[b-cgwpd5vsih] {
    display: inline-flex;
}

/* THE NAME GETS THE ROOM ON A PHONE. It was capped at 8rem, which truncated almost every real site
   name to two words and an ellipsis - and the space it was giving up went to a spacer. The cap is now
   past what a phone can offer, so the control takes whatever the bar has left after the two buttons
   and shrinks below that only when it must. The spacer is left alone deliberately: it is what keeps
   the account button hard right when there is no site to name at all. */
@media (max-width: 30rem) {
    .site-switcher__icon[b-cgwpd5vsih] {
        display: none;
    }

    .site-switcher__select[b-cgwpd5vsih],
    .site-switcher__name[b-cgwpd5vsih] {
        max-width: 16rem;
    }

    /* The horizontal padding was buying separation from an icon that is no longer there. */
    .site-switcher__select[b-cgwpd5vsih] {
        padding-inline: var(--space-1);
    }
}
/* /Shared/AccessDeniedNotice.razor.rz.scp.css */
.access-denied[b-b4pqj4lk2m] {
    padding: var(--space-5);
    background-color: var(--color-warning-subtle);
    border: var(--border-width) solid var(--color-warning);
    border-radius: var(--radius-lg);
}

.access-denied__title[b-b4pqj4lk2m] {
    margin-bottom: var(--space-2);
    font-size: var(--font-size-lg);
}

.access-denied__body[b-b4pqj4lk2m] {
    margin: 0;
    max-width: 46rem;
}
/* /Shared/EmptyState.razor.rz.scp.css */
.empty-state[b-5ze273wnjz] {
    padding: var(--space-7) var(--space-5);
    text-align: center;
    background-color: var(--color-surface-container);
    border: var(--border-width) dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
    color: var(--color-text-muted);
}

.empty-state__title[b-5ze273wnjz] {
    margin-bottom: var(--space-2);
    color: var(--color-text);
    font-size: var(--font-size-lg);
}

.empty-state__body[b-5ze273wnjz] {
    max-width: 40rem;
    margin: 0 auto;
}
/* /Shared/SiteChooser.razor.rz.scp.css */
.site-chooser__title[b-5emge21452] {
    font-size: var(--font-size-lg);
}

.site-chooser__description[b-5emge21452] {
    max-width: 46rem;
    color: var(--color-text-secondary);
}

/* Layout from the .grid-auto primitive in base.css; only the tuning knobs here. */
.site-chooser__list[b-5emge21452] {
    list-style: none;
    margin: 0;
    padding: 0;
    --grid-min: 16rem;
    --grid-gap: var(--space-3);
}

/* A whole card is the target, not a link inside one: it is the biggest hit area the
   layout can offer, which is what a gloved thumb needs. */
.site-chooser__site[b-5emge21452] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    width: 100%;
    height: 100%;
    padding: var(--space-4);
    border-radius: var(--radius-lg);
    text-align: left;
}

.site-chooser__name[b-5emge21452] {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
}

.site-chooser__roles[b-5emge21452] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}
