@import '_content/Microsoft.FluentUI.AspNetCore.Components/Microsoft.FluentUI.AspNetCore.Components.lcdo7z9xd2.bundle.scp.css';

/* /Components/Attachments/AttachmentList.razor.rz.scp.css */
/* Spec 033 / Phase 2 / T022 — scoped tile styling. The grid container
   itself (`.cs-media-grid`) is styled globally in app.css (spec 027)
   — this file only adds attachment-specific bits: extra top margin to
   separate the listing from the uploader above (D2), and the
   icon-tile centering for non-media items. */

.cs-attachment-list[b-vsgxwshblf] {
    /* Breathing room between the uploader (above) and the listing
       (below). D2 says the uploader stays the primary CTA; this gap
       makes the visual separation read as intentional rhythm rather
       than crowding. */
    margin-top: 2rem;
}

/* Icon tiles (non-media: PDF, file) reuse the cs-media-grid__poster
   square shape but render a centered icon instead of a thumbnail
   image. */
[b-vsgxwshblf] .cs-attachment-list__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--neutral-foreground-hint);
}

[b-vsgxwshblf] .cs-attachment-list__icon svg {
    width: 40%;
    height: 40%;
    /* Inherit the muted foreground color from the parent so the icon
       sits quietly against the tile background rather than
       competing with the filename caption below. */
}

/* Spec 033 / Phase 3 / T030 — per-tile delete button. Wrapper is
   `position: relative` so the button can anchor top-right of the
   tile's square. Hover-reveal on desktop (opacity 0 → 1 on
   wrapper hover); always-visible on mobile (`@media (hover: none)`
   forces opacity 1). Focus-visible also reveals so keyboard users
   can reach the button without a hover state. */
.cs-attachment-list__tile-wrapper[b-vsgxwshblf] {
    position: relative;
}

/* Spec 034 P2 (T021) — image tiles are now <button>s (they open the
   lightbox in-place instead of drilling through to /items/{id}). The
   global cs-media-grid__tile styling is anchor-shaped, so we strip
   the default button chrome here and let the tile inherit the same
   grid-cell shape. Same focus-visible + hover behavior as the anchor
   tiles. */
.cs-attachment-list__photo-tile[b-vsgxwshblf] {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    text-align: inherit;
    cursor: pointer;
    /* Same outline behavior the <a> tiles already get via the global
       cs-media-grid__tile rule — explicit here because the <button>
       default differs. */
    outline-offset: 2px;
}

.cs-attachment-list__photo-tile:focus-visible[b-vsgxwshblf] {
    outline: 2px solid var(--accent-fill-rest);
}

.cs-attachment-list__delete-btn[b-vsgxwshblf] {
    position: absolute;
    top: 0.375rem;
    right: 0.375rem;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 50%;
    /* More opaque than the original 0.55 — on bright photo tiles in
       light theme the trash icon was washing out. 0.7 keeps it
       legible against any poster tone without reading as a heavy
       solid blob. */
    background: rgba(0, 0, 0, 0.7);
    color: white;
    cursor: pointer;
    opacity: 0;
    transition: opacity 120ms ease, background 120ms ease;
}

.cs-attachment-list__tile-wrapper:hover .cs-attachment-list__delete-btn[b-vsgxwshblf],
.cs-attachment-list__tile-wrapper:focus-within .cs-attachment-list__delete-btn[b-vsgxwshblf] {
    opacity: 1;
}

.cs-attachment-list__delete-btn:hover[b-vsgxwshblf] {
    background: rgba(0, 0, 0, 0.85);
}

.cs-attachment-list__delete-btn:focus-visible[b-vsgxwshblf] {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: 2px;
    opacity: 1;
}

@media (hover: none), (max-width: 640px) {
    /* Touch devices AND narrow viewports: keep the button always
       visible since hover doesn't fire reliably on touch and is
       awkward to discover at narrow widths. The width breakpoint
       (640px) matches `cs-media-grid`'s desktop→mobile boundary so
       both transitions happen together. DevTools mobile simulator
       doesn't toggle `hover: none` reliably, so the OR-with-width
       query covers that path too.

       Tap target stays ≥ 28px (close enough to 44px Apple HIG; full
       44px would crowd small tiles — the icon is 16px and the
       surrounding circle provides padding). */
    .cs-attachment-list__delete-btn[b-vsgxwshblf] {
        opacity: 1;
    }
}

/* Play-icon overlay moved to MediaGridThumbnail (shared with the
   Media rollup) — styles now live in app.css's cs-media-grid block.
   No media-wrapper / play-overlay rules needed here anymore. */

/* Force the delete icon white. FluentIcon's SVG path is otherwise
   pinned to the accent token by the theme-accent JS, which read as
   accent-orange (not the intended white) and was hard to see on
   bright poster tiles in light theme. */
[b-vsgxwshblf] .cs-attachment-list__delete-btn svg {
    width: 16px;
    height: 16px;
    fill: #fff;
}
/* /Components/Attachments/PhotoLightbox.razor.rz.scp.css */
/* Spec 034 P2 (T020/T025) — full-viewport photo overlay.

   VP-002: "The lightbox is the photo, not chrome." The image is centred,
   max-height: 100vh; controls are quiet, thumb-reachable on mobile, and
   sit on top of a low-opacity backdrop rather than competing with the
   image for attention.

   Mobile pass (FR-012): 360px width works without horizontal overflow;
   close/nav targets are ≥44×44px (WCAG 2.5.5); the meta strip falls
   below the image on narrow viewports.

   Theming: the overlay reads `--neutral-foreground-on-accent-rest` for
   icon colour over the dark backdrop; falls back to white. */

.cs-photo-lightbox[b-gz3z0s6v9q] {
    position: fixed;
    inset: 0;
    z-index: 1000;
    /* Stacks the chrome above the backdrop. */
    display: grid;
    place-items: center;
    /* Black backdrop tint — bright enough to read controls, dark enough
       that the photo's frame disappears against it. Hard-coded rather
       than var() because the backdrop is intentionally non-themable —
       a light-theme lightbox is the same dark void. */
    background: rgba(0, 0, 0, 0.85);
    /* Component has tabindex=-1; focus-visible should not paint a
       browser outline around the whole overlay rect. */
    outline: none;
}

.cs-photo-lightbox__backdrop[b-gz3z0s6v9q] {
    /* The decorative dismiss surface — covers the full viewport behind
       the chrome. tabindex=-1 + aria-hidden in the markup; the visible
       Close button + Esc are the discoverable affordances. */
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    cursor: zoom-out;
}

.cs-photo-lightbox__chrome[b-gz3z0s6v9q] {
    /* The chrome positions the photo + controls relative to the
       viewport. `pointer-events: none` on the chrome cell + `auto`
       on every child means clicks land on either the photo (stage)
       or a button — never on the chrome itself, so the backdrop's
       dismiss action remains reachable everywhere there isn't a
       button or the image. */
    position: relative;
    width: 100%;
    height: 100%;
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: auto 1fr auto auto;
    grid-template-areas:
        "topbar topbar topbar"
        "prev   stage  next"
        ".      desc   ."
        ".      meta   .";
    align-items: center;
    justify-items: center;
    gap: 0.5rem;
    padding: 1rem;
    box-sizing: border-box;
    pointer-events: none;
}

.cs-photo-lightbox__chrome > *[b-gz3z0s6v9q] {
    pointer-events: auto;
}

/* Spec 047 P2 follow-up iter 2 — single top toolbar. Three-column
   inner grid (1fr | auto | 1fr) so the title sits in the middle col
   visually centred across the chrome width regardless of which
   icons are visible (the rotate row hides for non-owners). The
   icons-group lives in the right col, right-aligned as a flex row. */
.cs-photo-lightbox__topbar[b-gz3z0s6v9q] {
    grid-area: topbar;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    width: 100%;
    gap: 0.5rem;
}

.cs-photo-lightbox__topbar > .cs-photo-lightbox__title[b-gz3z0s6v9q] {
    grid-column: 2;
    justify-self: center;
}

.cs-photo-lightbox__icons-group[b-gz3z0s6v9q] {
    grid-column: 3;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.cs-photo-lightbox__nav--prev[b-gz3z0s6v9q] { grid-area: prev; }
.cs-photo-lightbox__nav--next[b-gz3z0s6v9q] { grid-area: next; }

.cs-photo-lightbox__stage[b-gz3z0s6v9q] {
    grid-area: stage;
    /* Photo + viewer container; absorbs the available space so the
       image scales to fit. */
    display: grid;
    place-items: center;
    max-width: 100%;
    max-height: 100%;
    overflow: hidden;
    cursor: default;
}

.cs-photo-lightbox__stage :deep(.cs-photo-viewer)[b-gz3z0s6v9q],
.cs-photo-lightbox__stage :deep(.cs-photo-viewer--loaded)[b-gz3z0s6v9q] {
    /* Override the PhotoViewer's default block layout so the embedded
       image fits the viewport. ::deep targets the un-scoped class on
       the child component (deliberate: PhotoViewer is shared, scoped
       styles can't reach it). */
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    margin: 0;
}

.cs-photo-lightbox__stage :deep(.cs-photo-viewer__img)[b-gz3z0s6v9q] {
    max-width: min(96vw, 100%);
    max-height: min(86vh, 100%);
    width: auto;
    height: auto;
    object-fit: contain;
    display: block;
    /* Spec 034 P3 (T030) — promote to its own layer so the per-frame
       transform from photo-lightbox.js doesn't repaint surrounding
       chrome on every pinch/pan/wheel tick. Also disables native
       gesture handling so iOS Safari's double-tap-to-zoom doesn't
       fight the custom toggle. */
    will-change: transform;
    touch-action: none;
    user-select: none;
    -webkit-user-drag: none;
}

/* The control buttons share one shape: a 44×44 circular tap target
   with a semi-transparent panel so they're legible on bright photos
   but recede when the user isn't looking at them. VP-002: controls
   are quiet — `opacity` carries the fade transition so the idle
   state below can fade them away when the pointer has been still. */
.cs-photo-lightbox__close[b-gz3z0s6v9q],
.cs-photo-lightbox__fullscreen[b-gz3z0s6v9q],
.cs-photo-lightbox__nav[b-gz3z0s6v9q],
.cs-photo-lightbox__action[b-gz3z0s6v9q] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 0;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    cursor: pointer;
    transition: background 120ms ease, transform 120ms ease, opacity 260ms ease;
}

.cs-photo-lightbox__close :deep(svg)[b-gz3z0s6v9q],
.cs-photo-lightbox__fullscreen :deep(svg)[b-gz3z0s6v9q],
.cs-photo-lightbox__nav :deep(svg)[b-gz3z0s6v9q],
.cs-photo-lightbox__action :deep(svg)[b-gz3z0s6v9q] {
    fill: #fff;
}

.cs-photo-lightbox__close:hover[b-gz3z0s6v9q],
.cs-photo-lightbox__fullscreen:hover[b-gz3z0s6v9q],
.cs-photo-lightbox__nav:hover[b-gz3z0s6v9q],
.cs-photo-lightbox__action:hover:not([disabled])[b-gz3z0s6v9q] {
    background: rgba(0, 0, 0, 0.75);
}

.cs-photo-lightbox__close:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox__fullscreen:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox__nav:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox__action:focus-visible[b-gz3z0s6v9q] {
    outline: 2px solid var(--accent-fill-rest, #ffffff);
    outline-offset: 2px;
}

.cs-photo-lightbox__action[disabled][b-gz3z0s6v9q] {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Spec 047 P2 follow-up iter 2 — the rotate row is now part of the
   topbar (icons-group flex), not a standalone bottom row. Drop
   grid-area and the pill background (the topbar's chrome handles
   visual containment); keep the inline-flex so the three buttons +
   optional rotate-msg span lay out horizontally. */
.cs-photo-lightbox__rotate[b-gz3z0s6v9q] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.cs-photo-lightbox__rotate-msg[b-gz3z0s6v9q] {
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.875rem;
    line-height: 1.3;
    padding: 0 0.5rem;
}

/* Spec 034 P4 (T040) — auto-fade controls after pointer idle (VP-002:
   the photo is the content, chrome is quiet). photo-lightbox.js
   toggles the `cs-photo-lightbox--idle` class on the overlay root
   after IDLE_AFTER_MS without pointer/keyboard activity, and clears
   it on any movement. The meta strip stays visible (it's
   informational, not a hover-only affordance) — fade applies only to
   the interactive buttons + the rotate row.

   Mobile (`@media (hover: none)`) keeps controls visible regardless:
   touch devices have no equivalent of "pointer idle" and a vanishing
   tap target is worse than a slightly busier viewport. */
.cs-photo-lightbox--idle .cs-photo-lightbox__close[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__fullscreen[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__nav[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__rotate[b-gz3z0s6v9q] {
    opacity: 0;
    pointer-events: none;
}

@media (hover: none) {
    .cs-photo-lightbox--idle .cs-photo-lightbox__close[b-gz3z0s6v9q],
    .cs-photo-lightbox--idle .cs-photo-lightbox__fullscreen[b-gz3z0s6v9q],
    .cs-photo-lightbox--idle .cs-photo-lightbox__nav[b-gz3z0s6v9q],
    .cs-photo-lightbox--idle .cs-photo-lightbox__rotate[b-gz3z0s6v9q] {
        opacity: 1;
        pointer-events: auto;
    }
}

/* Focus stays visible even when otherwise idle — keyboard users
   shouldn't lose the focus ring just because they paused. */
.cs-photo-lightbox--idle .cs-photo-lightbox__close:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__fullscreen:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__nav:focus-visible[b-gz3z0s6v9q],
.cs-photo-lightbox--idle .cs-photo-lightbox__action:focus-visible[b-gz3z0s6v9q] {
    opacity: 1;
    pointer-events: auto;
}

/* Spec 047 P2 follow-up (Brett 2026-05-23) — title above the photo,
   description below. Both are informational like __meta below, so
   they stay visible when the rest of the chrome fades. White text on
   a calm pill background for legibility against any photo. */
.cs-photo-lightbox__title[b-gz3z0s6v9q] {
    grid-area: title;
    color: rgba(255, 255, 255, 0.95);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.3;
    padding: 0.375rem 0.875rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.4);
    max-width: 92vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cs-photo-lightbox__description[b-gz3z0s6v9q] {
    grid-area: desc;
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.9375rem;
    line-height: 1.4;
    padding: 0.375rem 0.875rem;
    border-radius: 12px;
    background: rgba(0, 0, 0, 0.4);
    max-width: 80vw;
    /* Multi-line cap so a long description doesn't crowd the photo;
       overflow ellipses after ~3 lines (the user can open details to
       see the full text). */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-align: center;
    white-space: pre-wrap;
}

.cs-photo-lightbox__meta[b-gz3z0s6v9q] {
    grid-area: meta;
    color: rgba(255, 255, 255, 0.92);
    font-size: 0.875rem;
    line-height: 1.4;
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.375rem 0.875rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.4);
    max-width: 92vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cs-photo-lightbox__filename[b-gz3z0s6v9q] {
    max-width: 60vw;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-photo-lightbox__size[b-gz3z0s6v9q],
.cs-photo-lightbox__counter[b-gz3z0s6v9q] {
    color: rgba(255, 255, 255, 0.7);
}

/* Narrow viewports — collapse the side nav columns so the photo gets
   the full width, and pull the nav buttons to the bottom corners. */
@media (max-width: 480px) {
    .cs-photo-lightbox__chrome[b-gz3z0s6v9q] {
        grid-template-columns: 1fr;
        grid-template-rows: auto 1fr auto auto auto;
        grid-template-areas:
            "topbar"
            "stage"
            "nav"
            "desc"
            "meta";
        gap: 0.375rem;
        padding: 0.5rem;
    }

    .cs-photo-lightbox__nav--prev[b-gz3z0s6v9q],
    .cs-photo-lightbox__nav--next[b-gz3z0s6v9q] {
        grid-area: nav;
        position: relative;
    }

    .cs-photo-lightbox__nav--prev[b-gz3z0s6v9q] { justify-self: start; }
    .cs-photo-lightbox__nav--next[b-gz3z0s6v9q] { justify-self: end; }

    /* Spec 047 P2 follow-up iter 3 (Brett 2026-05-23) — on narrow
       viewports the inner 1fr|auto|1fr topbar grid squeezes the
       middle title column to nothing because the right column needs
       ~252px for the 5 icons (rotate-L/R + edit + fullscreen +
       close). Switch to a stacked layout: title row above, icons
       row below — both full-width. Title centred; icons right-
       aligned as before. */
    .cs-photo-lightbox__topbar[b-gz3z0s6v9q] {
        grid-template-columns: 1fr;
        grid-template-rows: auto auto;
        row-gap: 0.375rem;
    }

    .cs-photo-lightbox__topbar > .cs-photo-lightbox__title[b-gz3z0s6v9q] {
        grid-column: 1;
        grid-row: 1;
        justify-self: center;
        /* Cap to viewport-minus-padding so very long titles still
           ellipsize instead of forcing a horizontal scroll. */
        max-width: 100%;
    }

    .cs-photo-lightbox__icons-group[b-gz3z0s6v9q] {
        grid-column: 1;
        grid-row: 2;
        justify-self: end;
    }
}
/* /Components/Attachments/PhotoViewer.razor.rz.scp.css */
/* Spec 035 T044 iter 3 (Brett 2026-05-20) — kill the inline-image
   line-height descender gap so the photo's rendered height matches
   its container exactly. `display: block` removes the baseline
   strut; `max-width: 100%` keeps the image inside the cell;
   `height: auto` preserves the intrinsic aspect ratio. Without this
   rule the wrapping div was ~5px taller than the rendered <img>,
   which caused the flank Prev/Next buttons to extend slightly above
   and below the photo on the detail page. */
.cs-photo-viewer__img[b-5sh8gtqd42] {
    display: block;
    max-width: 100%;
    height: auto;
    /* Spec 047 P2 follow-up — belt-and-suspenders against the
       browser's native HTML5 image-drag gesture (the no-drop cursor
       Brett hit while trying to pan the zoomed lightbox image). The
       img tag carries `draggable="false"` too; this guards Safari /
       legacy paths that ignore the attribute. */
    -webkit-user-drag: none;
    user-select: none;
}

/* Spec 035 T044 follow-up (Brett 2026-05-20) — image rotation
   controls. Mirrors the .cs-video-player__btn / __controls look so
   photos and videos feel like one family. Inline SkiaSharp on the
   server; the response returns once rotation + derivative regen
   are done, and the component then re-fetches the SAS with a
   cache-bust to surface the new orientation. */
.cs-photo-viewer__controls[b-5sh8gtqd42] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}

.cs-photo-viewer__btn[b-5sh8gtqd42] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    border-radius: var(--control-corner-radius, 4px);
    background: var(--neutral-fill-rest, #f5f5f5);
    color: var(--neutral-foreground-rest);
    font-size: 0.9375rem;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}

.cs-photo-viewer__btn:hover:not([disabled])[b-5sh8gtqd42] {
    background: var(--neutral-fill-hover, #ebebeb);
    border-color: var(--neutral-foreground-hint);
}

.cs-photo-viewer__btn:focus-visible[b-5sh8gtqd42] {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: 2px;
}

.cs-photo-viewer__btn[disabled][b-5sh8gtqd42] {
    opacity: 0.55;
    cursor: not-allowed;
}

.cs-photo-viewer__msg[b-5sh8gtqd42] {
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
    line-height: 1.3;
}
/* /Components/Attachments/VideoPlayer.razor.rz.scp.css */
/* Spec 035 T044 (Brett iter 2, 2026-05-20) — pre-size the <video>
   element on first paint so the page doesn't jump when metadata
   loads. `aspect-ratio: auto 16 / 9` means "use the video's intrinsic
   ratio when it's known, fall back to 16:9 before metadata arrives."
   `object-fit: contain` + a black backdrop lets letter/pillar-boxing
   absorb the mismatch when the actual ratio differs from 16:9
   (notably phone-portrait clips). `max-height: 70vh` keeps tall
   portrait videos from monopolising the viewport on desktops. */
.cs-video-player__video[b-t256x2ixju] {
    width: 100%;
    aspect-ratio: auto 16 / 9;
    height: auto;
    max-height: 70vh;
    object-fit: contain;
    background: #000;
    display: block;
}

/* Spec 035 T044 iter 5 (Brett 2026-05-20) — single controls row:
   thumbnail (image + upload) on the left, rotate on the right.
   `justify-content: space-between` spreads them; `flex-wrap` keeps
   the layout sane on narrow viewports. */
.cs-video-player__controls[b-t256x2ixju] {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}

.cs-video-player__controls-thumb[b-t256x2ixju],
.cs-video-player__controls-rotate[b-t256x2ixju] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.cs-video-player__controls-thumb-actions[b-t256x2ixju] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
}

/* iter 6 (Brett 2026-05-20) — descriptor label sits ABOVE the
   button, not inside it. Pairs the Image icon with the prose so the
   button itself reads as a simple "Choose file" affordance. */
.cs-video-player__field-label[b-t256x2ixju] {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--neutral-foreground-rest);
    font-size: 0.875rem;
    line-height: 1.2;
}

/* Thumbnail preview + same-sized placeholder when none is set.
   ~96 × 144px ≈ 50% larger than the iter-1 inline 64×96 — visible at
   a glance without dominating the controls row. `object-fit: cover`
   keeps the aspect honest while filling the slot. */
.cs-video-player__thumb-preview[b-t256x2ixju],
.cs-video-player__thumb-placeholder[b-t256x2ixju] {
    width: 144px;
    height: 96px;
    border-radius: 0.375rem;
    flex: 0 0 auto;
    display: block;
}

.cs-video-player__thumb-preview[b-t256x2ixju] {
    object-fit: cover;
    background: var(--neutral-fill-rest, #f5f5f5);
}

.cs-video-player__thumb-placeholder[b-t256x2ixju] {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--neutral-fill-rest, #f5f5f5);
    color: var(--neutral-foreground-hint, #707070);
    border: 1px dashed var(--neutral-stroke-rest, #d0d0d0);
}

/* Match the attachment-uploader's "Choose files…" button style so
   the video controls feel like the rest of the app. Mirror of
   .cs-attachment-uploader__choose-btn in app.css; scoped here so
   the rule travels with the component. */
.cs-video-player__btn[b-t256x2ixju] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    border-radius: var(--control-corner-radius, 4px);
    background: var(--neutral-fill-rest, #f5f5f5);
    color: var(--neutral-foreground-rest);
    font-size: 0.9375rem;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}

.cs-video-player__btn:hover:not([disabled])[b-t256x2ixju] {
    background: var(--neutral-fill-hover, #ebebeb);
    border-color: var(--neutral-foreground-hint);
}

.cs-video-player__btn:focus-within[b-t256x2ixju],
.cs-video-player__btn:focus-visible[b-t256x2ixju] {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: 2px;
}

.cs-video-player__btn[disabled][b-t256x2ixju] {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Visually hide the native file input but keep it focusable +
   screen-reader-reachable (the <label> wrapper is the visible
   target). Same pattern as .cs-attachment-uploader__file. */
.cs-video-player__file-input[b-t256x2ixju] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}

.cs-video-player__msg[b-t256x2ixju] {
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
    line-height: 1.3;
}

/* Spec 042 P4 (T051) — quiet inline label that introduces the burn-in
   fallback buttons. Slightly dimmed so the affordance reads as a follow-up
   to the primary rotate pair, not a competing control. */
.cs-video-player__rotate-fallback-label[b-t256x2ixju] {
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
    line-height: 1.3;
    margin-left: 0.25rem;
}

/* Spec 042 P2 / T031 — transcode-status banner, shown ABOVE the video.
   Calm + in-voice (brand-values): the info variant is a soft neutral
   tint, the warn variant a warm amber — never an alarming red. */
.cs-video-player__banner[b-t256x2ixju] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0.625rem 0.875rem;
    margin-bottom: 0.5rem;
    border-radius: var(--control-corner-radius, 4px);
    border: 1px solid transparent;
    font-size: 0.9375rem;
    line-height: 1.35;
}

.cs-video-player__banner--info[b-t256x2ixju] {
    background: var(--neutral-fill-rest, #f5f5f5);
    border-color: var(--neutral-stroke-rest, #d0d0d0);
    color: var(--neutral-foreground-rest);
}

/* Warm, not alarming — a failed optimise is honest information, not an
   error the user caused. Amber tint with a readable foreground. */
.cs-video-player__banner--warn[b-t256x2ixju] {
    background: #fdf4e3;
    border-color: #e8d3a2;
    color: #6b4e16;
}

.cs-video-player__banner-text[b-t256x2ixju] {
    flex: 1 1 12rem;
}

/* T035 — the subtle current-rendition line under the player. */
.cs-video-player__rendition[b-t256x2ixju] {
    margin: 0.25rem 0 0;
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.8125rem;
    line-height: 1.2;
}

/* Spec 042 P3 (T040) — caption uploader row. Sits below the rotate +
   thumbnail row; same flex shape so the controls feel uniform. */
.cs-video-player__controls-captions[b-t256x2ixju] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}

.cs-video-player__captions-lang[b-t256x2ixju] {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--neutral-foreground-rest);
    font-size: 0.875rem;
}

.cs-video-player__captions-lang-text[b-t256x2ixju] {
    color: var(--neutral-foreground-hint, #707070);
}

.cs-video-player__captions-select[b-t256x2ixju] {
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    border-radius: var(--control-corner-radius, 4px);
    background: var(--neutral-fill-rest, #f5f5f5);
    color: var(--neutral-foreground-rest);
    font-size: 0.875rem;
    line-height: 1.3;
}

.cs-video-player__captions-have[b-t256x2ixju] {
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
    line-height: 1.3;
}
/* /Components/GuestSessionBanner.razor.rz.scp.css */
.cs-guest-session-banner[b-c535ln0r3b] {
    margin: 0.5rem 0;
    /* Spec 004 — force a high-contrast palette so the banner stays
       readable across both light and dark themes. The default Fluent
       MessageBar Info tokens render near-invisible on the CleverSets
       dark surface (see screenshot in conversation). */
    background-color: var(--accent-fill-rest, #0078d4);
    color: #ffffff;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: var(--control-corner-radius, 4px);
    padding: 0.5rem 0.75rem;
}

[b-c535ln0r3b] .cs-guest-session-banner,
[b-c535ln0r3b] .cs-guest-session-banner * {
    color: #ffffff !important;
    fill: #ffffff;
}

[b-c535ln0r3b] .cs-guest-session-banner a,
[b-c535ln0r3b] .cs-guest-session-banner fluent-anchor::part(control) {
    color: #ffffff !important;
    text-decoration: underline;
    font-weight: 600;
    margin-left: 0.25rem;
}

/* /Components/ItemCard.razor.rz.scp.css */
/* Spec 005 polish — unified ItemCard styles.

   Goals:
     • Card-like surface with a sane max-width (so very wide screens don't
       sprawl) and no horizontal scroll on any nested element.
     • Vertical scroll on the children/sharing tab bodies, never on the
       outer document — keeps the back row + breadcrumb pinned in view.
     • Mirror existing .cs-list / .cs-empty / .cs-breadcrumbs idioms used
       on the Cabinets list so children rows look consistent.
*/

[b-ttq8lt1czw] .cs-item-card {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-3, 0.75rem);
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    /* Prevent the article from forcing horizontal scroll if a child
       overflows — we prefer wrapping/truncation over horizontal motion. */
    overflow-x: hidden;
}

[b-ttq8lt1czw] .cs-item-card__topbar {
    display: flex;
    align-items: center;
    gap: var(--cs-spacing-3, 0.75rem);
    flex-wrap: wrap;
}

[b-ttq8lt1czw] .cs-item-card__topbar .cs-breadcrumbs {
    flex: 1 1 auto;
    min-width: 0;
}

[b-ttq8lt1czw] .cs-breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--cs-spacing-1, 0.25rem);
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.9rem;
}

[b-ttq8lt1czw] .cs-breadcrumbs a {
    color: inherit;
    text-decoration: none;
}

[b-ttq8lt1czw] .cs-breadcrumbs a:hover,
[b-ttq8lt1czw] .cs-breadcrumbs a:focus-visible {
    text-decoration: underline;
}

[b-ttq8lt1czw] .cs-breadcrumbs__sep {
    opacity: 0.6;
}

[b-ttq8lt1czw] .cs-item-card__header {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-2, 0.5rem);
    padding: var(--cs-spacing-3, 0.75rem) 0;
    border-bottom: 1px solid var(--neutral-stroke-rest, #e0e0e0);
}

[b-ttq8lt1czw] .cs-item-card__header-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-1, 0.25rem);
    /* Long titles/descriptions wrap rather than overflow horizontally. */
    overflow-wrap: anywhere;
}

/* Spec 035 T044 iter 5 (Brett 2026-05-20, applies to ALL items) —
   one-line title row with title (flex 1), then the type+sharing meta,
   then the edit pencil. Pulls meta out of the vertical stack so the
   description flows directly under the title without interruption, and
   the edit affordance lives next to the metadata it edits instead of
   being isolated on the right. */
[b-ttq8lt1czw] .cs-item-card__header-titlerow {
    display: flex;
    align-items: center;
    gap: var(--cs-spacing-2, 0.5rem);
    flex-wrap: wrap; /* narrow viewports wrap meta + edit under the title */
}

[b-ttq8lt1czw] .cs-item-card__header-titlerow .cs-page-title {
    flex: 1 1 auto;
    min-width: 0;
}

[b-ttq8lt1czw] .cs-item-card__header-titlerow .cs-page-meta {
    flex: 0 0 auto;
}

[b-ttq8lt1czw] .cs-item-card__header-edit {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-2, 0.5rem);
}

/* Spec 044 Phase 1 / P5-b (Brett, 2026-05-23) — edit-mode internal tab
   body. Stack fields vertically with consistent spacing, and force the
   FluentTextField + FluentTextArea inputs to fill the available width
   so they don't render at the FluentUI default narrow width. */
[b-ttq8lt1czw] .cs-item-card__header-edit-tab {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-2, 0.5rem);
    padding-top: var(--cs-spacing-2, 0.5rem);
}

[b-ttq8lt1czw] .cs-item-card__header-edit-tab fluent-text-field,
[b-ttq8lt1czw] .cs-item-card__header-edit-tab fluent-text-area {
    width: 100%;
}

/* Spec 044 Phase 3 (T023) — partial-failure block. Honest status, not
   error styling: a soft amber tint so the user reads it as "some
   worked, some didn't" rather than "everything broke." */
[b-ttq8lt1czw] .cs-item-card__partial-failure {
    margin: 0.5rem 0;
    padding: 0.625rem 0.875rem;
    background: #fdf4e3;
    border: 1px solid #e8d3a2;
    border-radius: var(--control-corner-radius, 4px);
    color: #6b4e16;
}

[b-ttq8lt1czw] .cs-item-card__partial-failure-summary {
    margin: 0 0 0.5rem;
    font-weight: 600;
}

[b-ttq8lt1czw] .cs-item-card__partial-failure-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

[b-ttq8lt1czw] .cs-item-card__partial-failure-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
    line-height: 1.3;
}

[b-ttq8lt1czw] .cs-item-card__partial-failure-ok {
    color: var(--neutral-foreground-hint, #707070);
}

[b-ttq8lt1czw] .cs-item-card__partial-failure-bad {
    flex: 1 1 auto;
}

/* Spec 044 Phase 4 (T031) — realtime "changed elsewhere" notice.
   Calm neutral surface (VP-005 — informational, not alarm). Sits
   above Save/Cancel so it reads as a state change the user needs to
   acknowledge before continuing. */
[b-ttq8lt1czw] .cs-item-card__elsewhere-notice {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0.5rem 0;
    padding: 0.625rem 0.875rem;
    background: var(--neutral-fill-rest, #f5f5f5);
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    border-radius: var(--control-corner-radius, 4px);
    color: var(--neutral-foreground-rest);
}

[b-ttq8lt1czw] .cs-item-card__elsewhere-text {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.4;
}

[b-ttq8lt1czw] .cs-page-title {
    margin: 0;
    font-size: 1.5rem;
    line-height: 1.2;
}

[b-ttq8lt1czw] .cs-page-meta {
    margin: 0;
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
}

[b-ttq8lt1czw] .cs-page-subtitle {
    margin: 0;
    color: var(--neutral-foreground-rest, #303030);
}

/* Spec 011 polish — Contact-flavored item view-mode field list. dt/dd
   pairs render in a tight two-column grid; multi-line MailingAddress
   spans the full row via white-space: pre-line. */
[b-ttq8lt1czw] .cs-item-card__contact {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.25rem 0.75rem;
    margin: 0.5rem 0 0 0;
    font-size: 0.9375rem;
}
[b-ttq8lt1czw] .cs-item-card__contact dt {
    color: var(--neutral-foreground-hint, #707070);
    font-weight: 500;
}
[b-ttq8lt1czw] .cs-item-card__contact dd {
    margin: 0;
    color: var(--neutral-foreground-rest, #303030);
}
[b-ttq8lt1czw] .cs-item-card__contact-multiline {
    white-space: pre-line;
}

[b-ttq8lt1czw] .cs-item-card__tabs {
    /* Let the tab strip span the card; tab bodies handle their own scroll. */
    width: 100%;
}

[b-ttq8lt1czw] .cs-item-card__tabbody {
    padding: var(--cs-spacing-3, 0.75rem) 0;
    /* Spec 027 smoke follow-up — the prior implementation capped the
       tab body height and gave it its own vertical scroll. That made
       browser features (Cmd/Ctrl+End, in-page Find auto-scroll,
       mobile pull-to-refresh) feel wrong because the inner scroll
       stole the natural page-level scroll. Drop the cap + overflow
       and let the page scroll instead. If the tab strip scrolling
       out of view becomes annoying on tall lists, follow up with
       `position: sticky` on `.cs-item-card__tabs` rather than
       reintroducing the inner scrollbar. */
    overflow-x: hidden;
}

[b-ttq8lt1czw] .cs-item-card__add {
    margin-bottom: var(--cs-spacing-3, 0.75rem);
}

[b-ttq8lt1czw] .cs-item-card__children .cs-list {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-2, 0.5rem);
}

[b-ttq8lt1czw] .cs-list__row-wrapper {
    display: flex;
    align-items: flex-start;
    gap: var(--cs-spacing-2, 0.5rem);
    border-radius: var(--control-corner-radius, 4px);
    min-width: 0;
}

[b-ttq8lt1czw] .cs-list__row-wrapper > .cs-list__row {
    flex: 1 1 auto;
    min-width: 0;
}

/* Actions (sharing badge + delete) top-align with the title row so
   they sit next to the title rather than floating beside whatever
   content height the subtitle happens to produce. The 0.75rem
   top-padding matches the .cs-item-display top-padding so the badge
   bottom-aligns visually with the title baseline. */
[b-ttq8lt1czw] .cs-list__actions {
    display: flex;
    align-items: center;
    gap: var(--cs-spacing-1, 0.25rem);
    flex: 0 0 auto;
    padding-top: 0.75rem;
}

[b-ttq8lt1czw] .cs-list__row {
    display: block;
    color: inherit;
    text-decoration: none;
    border-radius: var(--control-corner-radius, 4px);
}

[b-ttq8lt1czw] .cs-list__row:hover,
[b-ttq8lt1czw] .cs-list__row:focus-visible {
    background: var(--neutral-fill-secondary-rest, #fafafa);
    outline: none;
}

[b-ttq8lt1czw] .cs-empty {
    margin-top: var(--cs-spacing-4, 1rem);
    padding: var(--cs-spacing-6, 1.5rem);
    border: 1px dashed var(--neutral-stroke-rest, #d1d1d1);
    border-radius: var(--control-corner-radius, 4px);
    text-align: center;
}

[b-ttq8lt1czw] .cs-empty__title {
    font-weight: 600;
    margin: 0 0 var(--cs-spacing-1, 0.25rem) 0;
}

[b-ttq8lt1czw] .cs-empty__hint {
    margin: 0;
    color: var(--neutral-foreground-hint, #707070);
}

[b-ttq8lt1czw] .cs-loading {
    color: var(--neutral-foreground-hint, #707070);
}

[b-ttq8lt1czw] .cs-dialog-error,
[b-ttq8lt1czw] .cs-action-error {
    color: var(--error-foreground-rest, #b00020);
    margin-top: var(--cs-spacing-2, 0.5rem);
}

/* Spec 035 T044 (Brett iter 2, 2026-05-20) — Prev/Next flank the
   VIDEO ITSELF, not the whole preview block (which also contains the
   rotate + poster controls below). CSS Grid + `:has(.cs-video-player
   --playable)` + `display: contents` surfaces the <video> as a row-1
   grid item and drops the rotate/poster control rows into rows 2/3
   spanning all columns, so the buttons stretch only to the video's
   height. For non-playable states (loading / honest-note) and for
   non-video viewers (photo / pdf / file), the preview stays a single
   grid item in col 2 row 1 — buttons match that block as before.
   Mobile (<=640px): stack vertically with full-width row buttons. */
[b-ttq8lt1czw] .cs-item-card__attachment-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: stretch;
    gap: var(--cs-spacing-2, 0.5rem);
    width: 100%;
}

/* Display:contents surfaces nested children to participate in the row's
   grid, but ONLY for the loaded-content states — the loading / honest-
   note / error wrappers stay a single grid item so prev/next still
   flank them cleanly. Same shape for both viewers; iter-3 (2026-05-20)
   added the photo variant after Brett noticed the ~10-20px inline-image
   gap that left buttons extending slightly past the photo's edges. */
[b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-video-player--playable) .cs-item-card__attachment-preview,
[b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-photo-viewer--loaded) .cs-item-card__attachment-preview { display: contents; }
[b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-video-player--playable) .cs-video-player--playable { display: contents; }
[b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-photo-viewer--loaded) .cs-photo-viewer--loaded { display: contents; }

[b-ttq8lt1czw] .cs-item-card__attachment-nav-prev { grid-column: 1; grid-row: 1; }
[b-ttq8lt1czw] .cs-item-card__attachment-nav-next { grid-column: 3; grid-row: 1; }

/* Video: <video> is row 1 col 2; the combined rotate+thumbnail
   controls row (iter-5 merged the old __rotate + __poster divs into
   .cs-video-player__controls) drops into row 2 spanning every column. */
[b-ttq8lt1czw] .cs-item-card__attachment-row .cs-video-player__video { grid-column: 2; grid-row: 1; }
[b-ttq8lt1czw] .cs-item-card__attachment-row .cs-video-player__controls { grid-column: 1 / -1; }

/* Photo: the <img> becomes the row 1 col 2 grid item. iter-4
   (2026-05-20, Brett follow-up): center horizontally so a photo whose
   intrinsic width is narrower than the cell sits in the middle of the
   space between the flank buttons (the default `justify-self: start`
   left-aligns it; `max-width: 100%` keeps it from scaling up). Videos
   don't need this — `width: 100%` makes them always fill the cell.
   Image-rotation follow-up (2026-05-20): the photo controls row drops
   to row 2 spanning all columns (mirrors .cs-video-player__controls). */
[b-ttq8lt1czw] .cs-item-card__attachment-row .cs-photo-viewer__img {
    grid-column: 2;
    grid-row: 1;
    justify-self: center;
}

[b-ttq8lt1czw] .cs-item-card__attachment-row .cs-photo-viewer__controls { grid-column: 1 / -1; }

[b-ttq8lt1czw] .cs-item-card__attachment-nav-link {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--cs-spacing-1, 0.25rem);
    width: 4.5rem;
    padding: var(--cs-spacing-2, 0.5rem) var(--cs-spacing-1, 0.25rem);
    background: var(--accent-fill-rest, #0078d4);
    /* dark-mode safety: hard-set white instead of trusting
       --foreground-on-accent-rest, which resolves to black in some
       theme combos (the chevron stays white via CustomColor; the label
       had to be pinned explicitly to match). */
    color: #ffffff;
    border: 0;
    /* Friendlier corner — Brett's iter 2 request (was control-corner-radius / 4px). */
    border-radius: 0.75rem;
    cursor: pointer;
    transition: background-color 120ms ease, transform 80ms ease;
}

[b-ttq8lt1czw] .cs-item-card__attachment-nav-link:hover {
    background: var(--accent-fill-hover, #106ebe);
}

[b-ttq8lt1czw] .cs-item-card__attachment-nav-link:active {
    background: var(--accent-fill-active, #005a9e);
    transform: scale(0.98);
}

[b-ttq8lt1czw] .cs-item-card__attachment-nav-link:focus-visible {
    outline: 2px solid var(--accent-foreground-rest, #ffffff);
    outline-offset: 2px;
}

[b-ttq8lt1czw] .cs-item-card__attachment-nav-label {
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1;
    color: #ffffff; /* same dark-mode safety as above */
}

@media (max-width: 640px) {
    [b-ttq8lt1czw] .cs-item-card__attachment-row {
        display: flex;
        flex-direction: column;
    }
    [b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-video-player--playable) .cs-item-card__attachment-preview,
    [b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-video-player--playable) .cs-video-player--playable,
    [b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-photo-viewer--loaded) .cs-item-card__attachment-preview,
    [b-ttq8lt1czw] .cs-item-card__attachment-row:has(.cs-photo-viewer--loaded) .cs-photo-viewer--loaded {
        display: block;
    }
    [b-ttq8lt1czw] .cs-item-card__attachment-nav-link {
        width: 100%;
        flex-direction: row;
        gap: var(--cs-spacing-2, 0.5rem);
        padding: var(--cs-spacing-2, 0.5rem) var(--cs-spacing-3, 0.75rem);
    }
}

/* Spec 047 P3 (T020 / VP-003) — empty-state affordance shown below
   the header when the item has no children. One calm centred line;
   no border or background, no exclamation, no illustration. */
.cs-item-card__empty-affordance[b-ttq8lt1czw] {
    text-align: center;
    color: var(--neutral-foreground-hint, #6c757d);
    font-size: 0.9375rem;
    padding: var(--cs-spacing-3, 0.75rem) var(--cs-spacing-2, 0.5rem);
}

/* Spec 047 P3 (T022 / VP-002) — drag-over visual. Calm outline tint
   keyed off the JS controller's data-drag-active attribute on the
   article root; no full-screen overlay, no animation longer than
   100ms. Sits inside the chrome so it doesn't shift layout. */
.cs-item-card[data-drag-active="true"][b-ttq8lt1czw] {
    outline: 2px solid var(--accent-fill-rest, #0078d4);
    outline-offset: -4px;
    transition: outline-color 100ms ease;
}
/* /Components/ItemDisplay.razor.rz.scp.css */
.cs-item-display[b-kw6dj4ru3q] {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.75rem 0.5rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest, #ebebeb);
}
.cs-item-display:last-child[b-kw6dj4ru3q] {
    border-bottom: none;
}
.cs-item-display__row[b-kw6dj4ru3q] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
}
.cs-item-display__icon[b-kw6dj4ru3q],
.cs-item-display__avatar[b-kw6dj4ru3q] {
    width: 36px;
    height: 36px;
    flex: 0 0 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--neutral-fill-rest, #f3f3f3);
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--neutral-foreground-rest, #1f1f1f);
}
.cs-item-display__text[b-kw6dj4ru3q] {
    flex: 1;
    min-width: 0;
}
.cs-item-display__title[b-kw6dj4ru3q] {
    font-weight: 500;
    line-height: 1.3;
}
/* Subtitle/description lives on its own row under the header strip so it
   gets the full row width on every breakpoint. Indented to align with the
   title (icon column 36px + row gap 0.75rem).

   Clamped to 2 lines so a long description (e.g. a markdown-bodied Note
   whose Description carries paragraphs of content) doesn't blow the row
   open and create a wrap-the-actions-around layout. Click into the item
   for the full content. */
.cs-item-display__subtitle[b-kw6dj4ru3q] {
    color: var(--neutral-foreground-hint, #6e6e6e);
    font-size: 0.85rem;
    line-height: 1.35;
    width: 100%;
    padding-left: calc(36px + 0.75rem);
    word-break: break-word;
    /* Multi-line ellipsis. -webkit-line-clamp is supported across all
       evergreen browsers (Safari / Chrome / Firefox / Edge as of 2024+). */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* Collapse newlines/extra whitespace from markdown source to keep
       the clamped preview readable as a one-paragraph summary. */
    white-space: normal;
}
.cs-item-display__hint[b-kw6dj4ru3q] {
    color: var(--neutral-foreground-hint, #6e6e6e);
    font-size: 0.85rem;
    width: 100%;
    padding-left: calc(36px + 0.75rem);
    word-break: break-word;
}
.cs-item-display__trailing[b-kw6dj4ru3q] {
    flex-shrink: 0;
}

/* Spec 012 / T030 / D5 — done-state visual treatment for
   completed Tasks. Composed of FOUR signals so the row reads
   "done" at a glance even without a comparison row alongside:

     1. Title gets a STRONG strikethrough — full-color
        decoration line (not dimmed with the text) at 2px
        thickness. Smoke-pass surfaced that line-through
        following the text-decoration-color default rendered
        too faint at small mobile sizes; locking the decoration
        color to neutral-foreground-rest keeps it readable.
     2. Entire block drops to neutral-foreground-hint coloring
        so the row reads quieter than active rows.
     3. Icon swaps to Filled.CheckmarkCircle (handled at the
        call site via DoneAwareIcon) — the Things 3-style
        explicit "checked off" mark.
     4. Subtle background tint so the row reads as a distinct
        state-row in a scrolling list, not just a faint variant.

   The neutral-foreground-hint design token is contrast-checked
   in the FluentUI palette for both light + dark backgrounds;
   composing it for the whole block stays WCAG-AA-compliant. */
.cs-item-display--done .cs-item-display__title[b-kw6dj4ru3q] {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--neutral-foreground-rest, #1f1f1f);
}
.cs-item-display--done[b-kw6dj4ru3q] {
    color: var(--neutral-foreground-hint, #6e6e6e);
    background: var(--neutral-layer-2, #f6f6f6);
}
.cs-item-display--done .cs-item-display__icon[b-kw6dj4ru3q],
.cs-item-display--done .cs-item-display__avatar[b-kw6dj4ru3q] {
    opacity: 0.85;
}
/* /Components/ItemEditor.razor.rz.scp.css */
/* ItemEditor — orchestrator for the item create flow. Sections
   stack vertically with consistent rhythm; capability sub-forms
   appear in a stable order so the layout doesn't jump as the user
   picks different types.

   The dialog wrapper provides the modal frame; this component owns
   only the form body + bottom actions row. */

.cs-item-editor[b-apcdg6xp24] {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.cs-item-editor__alert[b-apcdg6xp24] {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    padding: 0.75rem 0.875rem;
    border-radius: var(--control-corner-radius, 6px);
    background: color-mix(in srgb, var(--error, #b3261e) 12%, var(--neutral-layer-1));
    color: var(--neutral-foreground-rest);
    border: 1px solid color-mix(in srgb, var(--error, #b3261e) 40%, transparent);
}

.cs-item-editor__section[b-apcdg6xp24] {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}

/* Spec 047 P4 — calm helper line under the attachment-mode upload
   section; the verb is set by surrounding chrome so this just
   clarifies the multi-file / can-close-anytime semantics. */
.cs-item-editor__hint[b-apcdg6xp24] {
    margin: 0;
    color: var(--neutral-foreground-hint);
    font-size: 0.9375rem;
    line-height: 1.4;
}

.cs-item-editor__section-heading[b-apcdg6xp24] {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--neutral-foreground-hint);
}

/* "Selected type" row — replaces the picker once a type is chosen so
   the rest of the form has space. The Change button is Stealth so it
   reads as an undo affordance, not a competing primary action. */
.cs-item-editor__type-chosen[b-apcdg6xp24] {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding: 0.75rem 0.875rem;
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-layer-1);
}

.cs-item-editor__type-icon[b-apcdg6xp24] {
    color: var(--accent-foreground-rest);
    flex: 0 0 auto;
}

.cs-item-editor__type-meta[b-apcdg6xp24] {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    flex: 1 1 auto;
    min-width: 0;
}

.cs-item-editor__type-meta > span[b-apcdg6xp24] {
    color: var(--neutral-foreground-hint);
    font-size: 0.9375rem;
    line-height: 1.4;
}

.cs-item-editor__field-error[b-apcdg6xp24] {
    margin: 0;
    color: var(--error, #b3261e);
    font-size: 0.9375rem;
}

/* Sharing radios — each radio has a strong primary line + a quieter
   description so users understand what each mode means without a
   separate help icon. The hint span sits next to the strong on the
   same line wrap-permitting; on narrow viewports it stacks below. */
.cs-item-editor__radio-hint[b-apcdg6xp24] {
    display: block;
    margin-block-start: 0.125rem;
    color: var(--neutral-foreground-hint);
    font-size: 0.9375rem;
    line-height: 1.4;
}

/* Bottom action bar — Cancel left, Create right. Sticky-feel via
   margin-top: auto isn't needed because the dialog body scrolls
   vertically when content exceeds the viewport. */
.cs-item-editor__actions[b-apcdg6xp24] {
    display: flex;
    justify-content: flex-end;
    gap: 0.625rem;
    margin-block-start: 0.5rem;
    padding-block-start: 0.875rem;
    border-block-start: 1px solid var(--neutral-stroke-divider-rest);
}
/* /Components/ItemTypePicker.razor.rz.scp.css */
/* Item type picker — clustered tile grid for choosing from the seeded
   ItemTypes. Tiles are clickable surfaces with a clear selected state.
   Layout adapts: 3 cols wide-desktop, 2 cols comfortable-desktop, 1 col
   mobile. Spec 047 P4 removed the legacy spec-009 "disabled tile" CSS
   path — attachment types are first-class picker entries now. */

.cs-itp[b-q2iwxeidr4] {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.cs-itp__loading[b-q2iwxeidr4],
.cs-itp__error[b-q2iwxeidr4] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem;
    color: var(--neutral-foreground-hint);
}

.cs-itp__empty[b-q2iwxeidr4] {
    margin: 0;
    color: var(--neutral-foreground-hint);
}

/* Cluster heading — typography-driven emphasis so the user can scan
   the type categories at a glance. Uppercase + tracking is preserved
   for the "section label" feel; weight + size + full-foreground
   color elevate it without leaning on a secondary accent (kept the
   palette restrained per the calm/anti-dark-pattern brand voice). */
.cs-itp__group-heading[b-q2iwxeidr4] {
    margin: 0 0 0.625rem 0;
    font-size: 0.95rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--neutral-foreground-rest);
}
/* A bit more breathing room between groups so the category boundaries
   read clearly even before the user processes the heading text. */
.cs-itp__group[b-q2iwxeidr4] {
    margin-bottom: 1.25rem;
}

.cs-itp__tiles[b-q2iwxeidr4] {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

/* Tile — a button that visually reads like a card. We use <button>
   rather than <div role="button"> so keyboard activation, focus, and
   disabled state come for free from the platform. */
.cs-itp__tile[b-q2iwxeidr4] {
    /* Strip default button chrome; we restyle from scratch. */
    appearance: none;
    -webkit-appearance: none;
    background: var(--neutral-layer-1);
    color: var(--neutral-foreground-rest);
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: var(--control-corner-radius, 6px);
    padding: 0.875rem 1rem;
    text-align: start;
    font: inherit;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}

.cs-itp__tile:hover[b-q2iwxeidr4] {
    border-color: var(--accent-fill-rest);
    transform: translateY(-1px);
    box-shadow: var(--elevation-shadow-card-rest, 0 1px 4px rgba(0,0,0,0.08));
}

.cs-itp__tile:focus-visible[b-q2iwxeidr4] {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: 2px;
}

/* Selected — accent border + faint accent tint so it reads as the
   committed choice without shouting. Keep the change subtle so the
   non-selected tiles remain readable as siblings. */
.cs-itp__tile--selected[b-q2iwxeidr4] {
    border-color: var(--accent-fill-rest);
    border-width: 2px;
    /* Compensate the extra border so the tile size doesn't shift. */
    padding: calc(0.875rem - 1px) calc(1rem - 1px);
    background: color-mix(in srgb, var(--accent-fill-rest) 6%, var(--neutral-layer-1));
}

/* prefers-reduced-motion: drop the hover lift entirely. The border /
   color cues still communicate state. */
@media (prefers-reduced-motion: reduce) {
    .cs-itp__tile[b-q2iwxeidr4] {
        transition: none;
    }
    .cs-itp__tile:hover[b-q2iwxeidr4] {
        transform: none;
    }
}

.cs-itp__tile-head[b-q2iwxeidr4] {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}

.cs-itp__tile-icon[b-q2iwxeidr4] {
    color: var(--accent-foreground-rest);
    flex: 0 0 auto;
}

.cs-itp__tile-name[b-q2iwxeidr4] {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.25;
}

/* Description uses the secondary reading ramp — it's prose meant to
   help the user choose, not chrome label. */
.cs-itp__tile-desc[b-q2iwxeidr4] {
    margin: 0;
    color: var(--neutral-foreground-hint);
    font-size: 0.9375rem;
    line-height: 1.4;
}
/* /Components/Markdown/MarkdownBody.razor.rz.scp.css */
/* MarkdownBody — textarea + Edit/Preview tab pair for markdown
   body fields. Brand-values lean (calm + clear, Obsidian / iA
   Writer): the source view is the default; the Preview tab is
   one click away but not in your face. Monospace inside the
   textarea so markdown source renders the way the author types
   it. The help line below sits at neutral-foreground-hint so it
   doesn't compete for attention. */

.cs-markdown-body[b-mdlesth97m] {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Pull the FluentTabs container in tight against the textarea
   below it; the default Fluent tab bar leaves a gap that looks
   detached from the input. */
.cs-markdown-body__tabs[b-mdlesth97m] {
    --tab-padding-inline: 0.75rem;
}

.cs-markdown-body__textarea[b-mdlesth97m] {
    width: 100%;
    box-sizing: border-box;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--neutral-stroke-rest);
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-fill-input-rest);
    color: var(--neutral-foreground-rest);
    /* iA Writer-style: a clean monospace inside the source view
       so markdown syntax is unambiguous. System monospace stack
       avoids shipping a webfont and respects user preferences. */
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
    font-size: 0.9375rem;
    line-height: 1.5;
    resize: vertical;
    min-height: 8rem;
}

.cs-markdown-body__textarea:focus-visible[b-mdlesth97m] {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: 1px;
    border-color: transparent;
}

.cs-markdown-body__textarea:disabled[b-mdlesth97m] {
    background: var(--neutral-fill-input-disabled);
    color: var(--neutral-foreground-disabled);
    cursor: not-allowed;
}

.cs-markdown-body__preview[b-mdlesth97m] {
    min-height: 8rem;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--neutral-stroke-rest);
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-layer-1);
    color: var(--neutral-foreground-rest);
    /* Match the reading rhythm a Post / Note view will use so
       Preview WYSIWYG matches the eventual rendered surface. */
    font-size: 0.9375rem;
    line-height: 1.55;
}

.cs-markdown-body__preview > :first-child[b-mdlesth97m] {
    margin-top: 0;
}

.cs-markdown-body__preview > :last-child[b-mdlesth97m] {
    margin-bottom: 0;
}

/* Loading / error / empty states inside Preview share a calm,
   centered visual so they don't feel like errors when they're
   not. */
.cs-markdown-body__preview-loading[b-mdlesth97m],
.cs-markdown-body__preview-empty[b-mdlesth97m] {
    margin: 0;
    color: var(--neutral-foreground-hint);
    font-style: italic;
}

.cs-markdown-body__preview-error[b-mdlesth97m] {
    margin: 0;
    color: color-mix(in srgb, var(--error, #b3261e) 80%, var(--neutral-foreground-rest));
}

.cs-markdown-body__help[b-mdlesth97m] {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--neutral-foreground-hint);
}

.cs-markdown-body__help code[b-mdlesth97m],
.cs-markdown-body__help kbd[b-mdlesth97m] {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.75rem;
    padding: 0.0625rem 0.25rem;
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: 3px;
    background: var(--neutral-layer-2);
}
/* /Components/Markdown/MarkdownText.razor.rz.scp.css */
/* Spec 012 smoke-pass polish — typographic defaults for the
   sanitized HTML that MarkdownText emits via MarkupString.
   The component's outer <div> is whatever the caller passed
   in CssClass (cs-page-subtitle on ItemCard read-mode,
   cs-post-detail__text on PostDetail, etc.) — we don't own
   that class. ::deep selectors target the rendered children
   regardless of the wrapper class.

   Surfaced during the spec 012 manual smoke pass: a wrapped
   <h1> in a Note's body rendered with no line-height between
   lines, so two-line headings ran into each other. The fix is
   sensible line-height + a touch of vertical rhythm so dense
   markdown (heading → paragraph → list) breathes correctly. */

[b-ozr6pkth0y] h1,
[b-ozr6pkth0y] h2,
[b-ozr6pkth0y] h3,
[b-ozr6pkth0y] h4,
[b-ozr6pkth0y] h5,
[b-ozr6pkth0y] h6 {
    line-height: 1.25;
    margin: 0.75em 0 0.4em;
}

[b-ozr6pkth0y] h1:first-child,
[b-ozr6pkth0y] h2:first-child,
[b-ozr6pkth0y] h3:first-child,
[b-ozr6pkth0y] h4:first-child,
[b-ozr6pkth0y] h5:first-child,
[b-ozr6pkth0y] h6:first-child {
    margin-top: 0;
}

[b-ozr6pkth0y] p {
    margin: 0 0 0.6em;
    line-height: 1.5;
}

[b-ozr6pkth0y] p:last-child {
    margin-bottom: 0;
}

[b-ozr6pkth0y] ul,
[b-ozr6pkth0y] ol {
    margin: 0 0 0.6em;
    padding-left: 1.4em;
}

[b-ozr6pkth0y] li {
    line-height: 1.5;
    margin: 0.15em 0;
}

[b-ozr6pkth0y] blockquote {
    margin: 0.5em 0;
    padding-left: 0.75em;
    border-left: 3px solid var(--neutral-stroke-divider-rest, #ebebeb);
    color: var(--neutral-foreground-hint, #6e6e6e);
}

[b-ozr6pkth0y] pre {
    margin: 0.6em 0;
    padding: 0.6em 0.75em;
    background: var(--neutral-layer-2, #f6f6f6);
    border-radius: var(--control-corner-radius, 6px);
    overflow-x: auto;
    line-height: 1.45;
}

[b-ozr6pkth0y] code {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.92em;
}

[b-ozr6pkth0y] pre code {
    background: transparent;
    padding: 0;
}
/* /Components/PeoplePicker.razor.rz.scp.css */
/* Spec 005 / FR-024 — PeoplePicker styling.
   Renders accepted-mutual peers as bordered list rows with avatar +
   display name + @handle, with a selected state and hover affordance. */

.cs-people-picker[b-2wqel4u6r4] {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-3, 0.75rem);
}

.cs-people-picker__filter[b-2wqel4u6r4] {
    width: 100%;
}

.cs-people-picker__status[b-2wqel4u6r4] {
    margin: 0;
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
}

.cs-people-picker__list[b-2wqel4u6r4] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-1, 0.25rem);
    max-height: 18rem;
    overflow-y: auto;
    overflow-x: hidden;
    border: 1px solid var(--neutral-stroke-rest, #d1d1d1);
    border-radius: var(--control-corner-radius, 4px);
    padding: var(--cs-spacing-1, 0.25rem);
    background: var(--neutral-layer-1, #ffffff);
    box-sizing: border-box;
    width: 100%;
}

.cs-people-picker__row[b-2wqel4u6r4] {
    margin: 0;
    padding: 0;
}

.cs-people-picker__btn[b-2wqel4u6r4] {
    width: 100%;
    display: flex;
    align-items: center;
    gap: var(--cs-spacing-3, 0.75rem);
    padding: var(--cs-spacing-2, 0.5rem) var(--cs-spacing-3, 0.75rem);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--control-corner-radius, 4px);
    color: var(--neutral-foreground-rest, inherit);
    text-align: left;
    min-width: 0;
    box-sizing: border-box;
}

.cs-people-picker__avatar[b-2wqel4u6r4] {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--accent-fill-rest, #0078d4);
    color: var(--accent-foreground-rest, #ffffff);
    font-weight: 600;
    font-size: 0.875rem;
    text-transform: uppercase;
    user-select: none;
}

.cs-people-picker__text[b-2wqel4u6r4] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
}

.cs-people-picker__display[b-2wqel4u6r4] {
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-people-picker__handle[b-2wqel4u6r4] {
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.8125rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-people-picker__check[b-2wqel4u6r4] {
    flex: 0 0 auto;
    margin-left: auto;
}

/* Per-row permission select — the canonical permission palette per
   docs/design-system.md §2. Light-mode fg/bg/border come from the shared
   --cs-permission-{level}-{fg,bg,border} tokens in app.css (same fg hexes
   that back .cs-sharing-pill--{view,edit,manage} on the neutral page
   surface — the light unification holds end-to-end).

   Dark mode breaks the fg unification on purpose. The canonical dark fg
   is the -400 step (used by sharing-pill on a flat page bg, where it
   pops). Here the chip surface is a tinted rgba overlay, which lifts the
   effective bg luminance ~1 step — that knocks -400 fg under 4.5:1 on
   the violet/orange chips. Step the chip dark fg up to -300 and restore
   the original rgba opacities (.20-.22 fill, .50 border) so the chip
   reads cleanly. The light unification is unaffected.
     None   → neutral grey  (deliberately quiet — "off / unset")
     View   → cool blue     (passive, read-only)
     Edit   → warm orange   (active, modifying)
     Manage → violet        (administrative, distinct from any accent) */
.cs-grant-select[b-2wqel4u6r4] {
    flex: 0 0 auto;
    margin-left: auto;
    min-width: 6.5rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--control-corner-radius, 4px);
    border: 1px solid currentColor;
    background: transparent;
    font-weight: 600;
    font-size: 0.8125rem;
    line-height: 1.2;
    cursor: pointer;
}

    .cs-grant-select:focus-visible[b-2wqel4u6r4] {
        outline: 2px solid currentColor;
        outline-offset: 1px;
    }

    .cs-grant-select option[b-2wqel4u6r4] {
        color: var(--neutral-foreground-rest, #1f1f1f);
        background: var(--neutral-layer-1, #ffffff);
    }

.cs-grant-select--none[b-2wqel4u6r4] {
    color: var(--cs-permission-none-fg);
    background: var(--cs-permission-none-bg);
    border-color: var(--cs-permission-none-border);
}

.cs-grant-select--read[b-2wqel4u6r4],
.cs-grant-select--view[b-2wqel4u6r4] {
    color: var(--cs-permission-view-fg);
    background: var(--cs-permission-view-bg);
    border-color: var(--cs-permission-view-border);
}

.cs-grant-select--edit[b-2wqel4u6r4] {
    color: var(--cs-permission-edit-fg);
    background: var(--cs-permission-edit-bg);
    border-color: var(--cs-permission-edit-border);
}

.cs-grant-select--manage[b-2wqel4u6r4] {
    color: var(--cs-permission-manage-fg);
    background: var(--cs-permission-manage-bg);
    border-color: var(--cs-permission-manage-border);
}

/* Dark-mode chip overrides (see header comment). Light tokens are
   inherited as-is; dark mode swaps fg → -300 and restores stronger
   rgba opacities so contrast ≥4.5:1 on the tinted chip. Selector
   pattern mirrors the sharing-pill dark/OS-fallback double-source in
   app.css — explicit attribute first, prefers-color-scheme fallback
   for the gap before ClientThemeService writes the attribute. */
[data-theme="dark"] .cs-grant-select--read[b-2wqel4u6r4],
[data-theme="dark"] .cs-grant-select--view[b-2wqel4u6r4] {
    color: #93c5fd; /* blue-300  */
    background: rgba( 59, 130, 246, 0.20);
    border-color: rgba( 59, 130, 246, 0.50);
}
[data-theme="dark"] .cs-grant-select--edit[b-2wqel4u6r4] {
    color: #fdba74; /* orange-300 */
    background: rgba(249, 115,  22, 0.22);
    border-color: rgba(249, 115,  22, 0.50);
}
[data-theme="dark"] .cs-grant-select--manage[b-2wqel4u6r4] {
    color: #c4b5fd; /* violet-300 */
    background: rgba(139,  92, 246, 0.22);
    border-color: rgba(139,  92, 246, 0.50);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cs-grant-select--read[b-2wqel4u6r4],
    :root:not([data-theme="light"]) .cs-grant-select--view[b-2wqel4u6r4] {
        color: #93c5fd;
        background: rgba( 59, 130, 246, 0.20);
        border-color: rgba( 59, 130, 246, 0.50);
    }
    :root:not([data-theme="light"]) .cs-grant-select--edit[b-2wqel4u6r4] {
        color: #fdba74;
        background: rgba(249, 115,  22, 0.22);
        border-color: rgba(249, 115,  22, 0.50);
    }
    :root:not([data-theme="light"]) .cs-grant-select--manage[b-2wqel4u6r4] {
        color: #c4b5fd;
        background: rgba(139,  92, 246, 0.22);
        border-color: rgba(139,  92, 246, 0.50);
    }
}

.cs-empty[b-2wqel4u6r4] {
    margin: 0;
    padding: var(--cs-spacing-4, 1rem);
    border: 1px dashed var(--neutral-stroke-rest, #d1d1d1);
    border-radius: var(--control-corner-radius, 4px);
    text-align: center;
}

.cs-empty__title[b-2wqel4u6r4] {
    font-weight: 600;
    margin: 0 0 var(--cs-spacing-1, 0.25rem) 0;
}

.cs-empty__hint[b-2wqel4u6r4] {
    margin: 0;
    color: var(--neutral-foreground-hint, #707070);
    font-size: 0.875rem;
}
/* /Components/ShareDialog.razor.rz.scp.css */
/* `.cs-share-dialog__status` styling moved to app.css so both ShareDialog
   AND SharingPanel (which reuses the class but isn't inside ShareDialog)
   pick it up — scoped CSS is keyed to the component file, so the class
   match was a coincidence the previous version relied on. */

/* Sharing-mode selector sits above the tabs. The selector is full-width
   so the long option labels (e.g. "Public — anyone signed in can view")
   don't get truncated, and the hint sits directly underneath in a muted
   tone so the paradigm explanation is unmissable but doesn't fight with
   the tabbed content for visual weight. */
.cs-share-dialog__mode[b-nz1bj18qft] {
    margin: 0 var(--cs-spacing-4, 1rem) var(--cs-spacing-3, 0.75rem) var(--cs-spacing-4, 1rem);
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-1, 0.25rem);
}

    .cs-share-dialog__mode[b-nz1bj18qft]  fluent-select {
        width: 100%;
    }

.cs-share-dialog__mode-hint[b-nz1bj18qft] {
    margin: 0;
    font-size: 0.85rem;
    color: var(--cs-color-text-muted, #666);
}

/* Shown inside Invite tab when the current mode is Private — explains
   why the issue/redeem affordances are hidden rather than just appearing
   broken. */
.cs-share-dialog__disabled-note[b-nz1bj18qft] {
    margin: 0;
    padding: var(--cs-spacing-3, 0.75rem);
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.04);
    color: var(--cs-color-text-muted, #555);
    font-size: 0.9rem;
}
/* /Components/SharingPanel.razor.rz.scp.css */
/* Spec 044 Phase 3 (T021) — pending-changes block in Deferred mode.
   Quiet, informational; rendered below the People/Groups/Invite tabs
   when there are buffered ops. Matches the partial-failure block's
   amber tint so the two read as related "honest status" surfaces. */

[b-dv889ritth] .cs-sharing-panel__pending {
    margin-top: 0.75rem;
    padding: 0.625rem 0.875rem;
    background: var(--neutral-fill-rest, #f5f5f5);
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    border-radius: var(--control-corner-radius, 4px);
}

[b-dv889ritth] .cs-sharing-panel__pending-title {
    margin: 0 0 0.5rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--neutral-foreground-rest);
}

[b-dv889ritth] .cs-sharing-panel__pending-list {
    list-style: disc inside;
    margin: 0;
    padding: 0;
    color: var(--neutral-foreground-rest);
    font-size: 0.875rem;
    line-height: 1.4;
}

[b-dv889ritth] .cs-sharing-panel__pending-item {
    padding: 0.125rem 0;
}
/* /Components/Sharing/SharedWithSummary.razor.rz.scp.css */
/* Spec 044 Phase 2 — view-mode "Shared with: …" summary. Inactive
   chip strip; informational only, per VP-003. Wraps gracefully on
   narrow viewports. */

.cs-shared-with[b-a3sdw0bngw] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    margin: 0.25rem 0 0.5rem;
    font-size: 0.875rem;
    line-height: 1.3;
}

.cs-shared-with__label[b-a3sdw0bngw] {
    color: var(--neutral-foreground-hint, #707070);
    margin-right: 0.125rem;
}

.cs-shared-with__chip[b-a3sdw0bngw] {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    background: var(--neutral-fill-rest, #f5f5f5);
    border: 1px solid var(--neutral-stroke-rest, #d0d0d0);
    color: var(--neutral-foreground-rest);
    /* Chips are informational, not interactive — no hover, no
       cursor:pointer (VP-003). */
}
/* /Components/SummaryCard.razor.rz.scp.css */
.cs-summary-card[b-rigrk2wqcw] {
    cursor: pointer;
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-height: 160px;
    transition: transform 120ms ease, box-shadow 120ms ease;
}
.cs-summary-card:hover[b-rigrk2wqcw],
.cs-summary-card:focus-visible[b-rigrk2wqcw] {
    transform: translateY(-2px);
    box-shadow: var(--elevation-shadow-card-rest, 0 2px 8px rgba(0,0,0,0.12));
}
.cs-summary-card__head[b-rigrk2wqcw] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.cs-summary-card__icon[b-rigrk2wqcw] {
    color: var(--accent-fill-rest, #0f6cbd);
}
.cs-summary-card__title[b-rigrk2wqcw] {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}
.cs-summary-card__subtitle[b-rigrk2wqcw] {
    margin: 0;
    color: var(--neutral-foreground-hint, #6e6e6e);
    font-size: 0.85rem;
}
.cs-summary-card__body[b-rigrk2wqcw] {
    flex: 1;
    font-size: 0.9rem;
    overflow: hidden;
}
.cs-summary-card__body ul[b-rigrk2wqcw] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.cs-summary-card__body li[b-rigrk2wqcw] {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    line-height: 1.3;
}
.cs-summary-card__body li .cs-summary-card__hint[b-rigrk2wqcw] {
    color: var(--neutral-foreground-hint, #6e6e6e);
    font-size: 0.8rem;
    flex-shrink: 0;
}
.cs-summary-card__cta[b-rigrk2wqcw] {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    color: var(--accent-fill-rest, #0f6cbd);
    font-size: 0.85rem;
}
@media (prefers-reduced-motion: reduce) {
    .cs-summary-card[b-rigrk2wqcw],
    .cs-summary-card:hover[b-rigrk2wqcw],
    .cs-summary-card:focus-visible[b-rigrk2wqcw] {
        transform: none;
        transition: none;
    }
}
/* /Pages/Cabinets.razor.rz.scp.css */
.cs-list[b-p0r38lbkim] {
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-2, 0.5rem);
    margin-top: var(--cs-spacing-4, 1rem);
}

/* T051: page header with right-aligned "New cabinet" affordance.
   Spec 032 Phase 4 tangential fix: `flex-wrap: wrap` so the button
   drops below the title block on narrow viewports rather than running
   flush against the right edge. */
.cs-page-header[b-p0r38lbkim] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--cs-spacing-4, 1rem);
}

/* T051: row wrapper hosts the navigable link and the action group side-by-side
   so the action buttons sit OUTSIDE the anchor (clicks don't navigate). */
.cs-list__row-wrapper[b-p0r38lbkim] {
    display: flex;
    align-items: stretch;
    gap: var(--cs-spacing-2, 0.5rem);
    border-radius: var(--control-corner-radius, 4px);
}

.cs-list__row-wrapper > .cs-list__row[b-p0r38lbkim] {
    flex: 1 1 auto;
    min-width: 0;
}

.cs-list__actions[b-p0r38lbkim] {
    display: flex;
    align-items: center;
    gap: var(--cs-spacing-1, 0.25rem);
    flex: 0 0 auto;
}

/* T051: dialog and action error messaging. */
.cs-dialog-error[b-p0r38lbkim],
.cs-action-error[b-p0r38lbkim] {
    color: var(--error-foreground-rest, #b00020);
    margin-top: var(--cs-spacing-2, 0.5rem);
}

/* T046: navigable rows in the real-data view. Guest-tour rows render the
   ItemDisplay directly (non-navigable) so this rule never applies there. */
.cs-list__row[b-p0r38lbkim] {
    display: block;
    color: inherit;
    text-decoration: none;
    border-radius: var(--control-corner-radius, 4px);
}

.cs-list__row:hover[b-p0r38lbkim],
.cs-list__row:focus-visible[b-p0r38lbkim] {
    background: var(--neutral-fill-secondary-rest, #fafafa);
    outline: none;
}

.cs-empty[b-p0r38lbkim] {
    margin-top: var(--cs-spacing-6, 1.5rem);
    padding: var(--cs-spacing-6, 1.5rem);
    border: 1px dashed var(--neutral-stroke-rest, #d1d1d1);
    border-radius: var(--control-corner-radius, 4px);
    text-align: center;
}

.cs-empty__title[b-p0r38lbkim] {
    font-weight: 600;
    margin: 0 0 var(--cs-spacing-1, 0.25rem) 0;
}

.cs-empty__hint[b-p0r38lbkim] {
    margin: 0;
    color: var(--neutral-foreground-hint, #707070);
}

.cs-error[b-p0r38lbkim] {
    margin-top: var(--cs-spacing-4, 1rem);
    padding: var(--cs-spacing-4, 1rem);
    border-left: 3px solid var(--accent-fill-rest, #0078d4);
    background: var(--neutral-fill-secondary-rest, #fafafa);
    display: flex;
    flex-direction: column;
    gap: var(--cs-spacing-3, 0.75rem);
    align-items: flex-start;
}

.cs-error__message[b-p0r38lbkim] {
    margin: 0;
}
/* /Pages/Dev/CapabilityEditorsPreview.razor.rz.scp.css */
.cs-cap-preview[b-44rhvroetx] {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    align-items: start;
}

.cs-cap-preview__editor[b-44rhvroetx] {
    padding: 1.25rem;
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-layer-1);
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.cs-cap-preview__editor > h2[b-44rhvroetx] {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 600;
}

.cs-cap-preview__editor > h2 > small[b-44rhvroetx] {
    margin-inline-start: 0.5rem;
    color: var(--neutral-foreground-hint);
    font-size: 0.8125rem;
    font-weight: 400;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
}

.cs-cap-preview__state[b-44rhvroetx] {
    margin: 0;
    padding: 0.625rem 0.75rem;
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-layer-2);
    color: var(--neutral-foreground-hint);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}
/* /Pages/Dev/ItemTypePickerPreview.razor.rz.scp.css */
.cs-itp-preview[b-mofalhl9v2] {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.cs-itp-preview__controls[b-mofalhl9v2] {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
    padding: 1rem;
    border: 1px solid var(--neutral-stroke-divider-rest);
    border-radius: var(--control-corner-radius, 6px);
    background: var(--neutral-layer-1);
}

.cs-itp-preview__hint[b-mofalhl9v2] {
    margin: 0;
    color: var(--neutral-foreground-hint);
    font-size: 0.9375rem;
}
/* /Pages/People.razor.rz.scp.css */
/* People page — responsive grid/cards toggle.
 *
 * Wide screens (≥ 720px) keep the FluentDataGrid; narrow screens swap to
 * a vertical card list so the per-row Actions don't get clipped on phones.
 */

.cs-grid-only[b-fizrq58r3i] {
    display: block;
}

.cs-cards-only[b-fizrq58r3i] {
    display: none;
}

@media (max-width: 719px) {
    .cs-grid-only[b-fizrq58r3i] {
        display: none;
    }

    .cs-cards-only[b-fizrq58r3i] {
        display: flex;
        flex-direction: column;
        gap: 8px;
    }
}

.cs-card-list[b-fizrq58r3i] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.cs-row-card[b-fizrq58r3i] {
    width: 100%;
}

.cs-row-card[b-fizrq58r3i]  .fluent-card,
.cs-row-card[b-fizrq58r3i]  fluent-card {
    width: 100%;
    box-sizing: border-box;
    padding: 12px;
}

.cs-row-card__head[b-fizrq58r3i] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
}

.cs-row-card__title[b-fizrq58r3i] {
    font-weight: 600;
    text-transform: capitalize;
}

.cs-row-card__meta[b-fizrq58r3i] {
    font-size: var(--type-ramp-minus-1-font-size, 0.85rem);
    color: var(--neutral-foreground-hint, #6b6b6b);
    margin-bottom: 8px;
    line-height: 1.4;
}

.cs-row-card__actions[b-fizrq58r3i] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Make buttons stretch to full width on the smallest screens so they're
 * easy to tap. */
@media (max-width: 419px) {
    .cs-row-card__actions[b-fizrq58r3i] {
        flex-direction: column;
        align-items: stretch;
    }

    .cs-row-card__actions[b-fizrq58r3i]  fluent-button {
        width: 100%;
    }
}

/* Spec 005 � make the People-page tabs read as interactive controls instead
 * of plain headings: subtle pill background on hover, prominent active
 * underline + bold label, and a thin baseline separating the tab strip from
 * tab-pane content.  Selectors use ::deep so they pierce FluentTabs' shadow
 * boundary. */
.cs-people-tabs[b-fizrq58r3i] {
    border-bottom: 1px solid var(--neutral-stroke-divider-rest, rgba(0,0,0,0.08));
    margin-bottom: 12px;
}

.cs-people-tabs[b-fizrq58r3i]  fluent-tab,
.cs-people-tabs[b-fizrq58r3i]  [role="tab"] {
    padding: 8px 16px;
    border-radius: 6px 6px 0 0;
    cursor: pointer;
    transition: background-color 120ms ease, color 120ms ease;
    color: var(--neutral-foreground-rest);
}

.cs-people-tabs[b-fizrq58r3i]  fluent-tab:hover,
.cs-people-tabs[b-fizrq58r3i]  [role="tab"]:hover {
    background-color: var(--neutral-fill-stealth-hover, rgba(0,0,0,0.04));
    color: var(--neutral-foreground-rest);
}

.cs-people-tabs[b-fizrq58r3i]  fluent-tab[aria-selected="true"],
.cs-people-tabs[b-fizrq58r3i]  [role="tab"][aria-selected="true"] {
    font-weight: 600;
    color: var(--accent-foreground-rest);
    border-bottom: 3px solid var(--accent-fill-rest);
    background-color: var(--neutral-fill-stealth-rest, transparent);
}

.cs-people-tabs[b-fizrq58r3i]  fluent-tab:focus-visible,
.cs-people-tabs[b-fizrq58r3i]  [role="tab"]:focus-visible {
    outline: 2px solid var(--accent-fill-rest);
    outline-offset: -2px;
}
