/*
 * The psh-* component library for the Razor UI. Structure and spacing live here;
 * pages should compose these classes rather than writing inline styles (inline
 * style attributes are also blocked by the CSP convention for this app).
 */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
}

.psh-body {
    background: var(--psh-bg);
    color: var(--psh-text);
    display: flex;
    font-family: var(--psh-font);
    font-size: var(--psh-text-size);
    line-height: 1.5;
    min-height: 100vh;
}

.psh-main {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-width: 0;
}

.psh-inline-form {
    display: inline;
    margin: 0;
}

/* ---------- Side nav ----------
   Mirrors the Angular shell's mat-side-nav: dark panel ($main-navbar-bg-color),
   expandable groups, accent bar on the active item, user section at the bottom. */

.psh-sidenav {
    background: var(--psh-nav-bg);
    color: var(--psh-nav-text);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    height: 100vh;
    overflow-y: auto;
    position: sticky;
    top: 0;
    /* 312px, the Angular drawer width */
    width: 19.5rem;
    z-index: 95;
}

.psh-sidenav-header {
    align-items: center;
    display: flex;
    min-height: var(--psh-topnav-height);
    padding: 0.5rem 1rem;
}

.psh-sidenav-header img {
    display: block;
    height: 35px;
    width: auto;
}

.psh-sidenav-items {
    flex: 1;
}

/* Pill-shaped rows like the Angular mat-side-nav (border-radius 2rem). */
.psh-sidenav-item {
    align-items: center;
    background: transparent;
    border: none;
    border-radius: 2rem;
    color: var(--psh-nav-text);
    cursor: pointer;
    display: flex;
    font: inherit;
    gap: 0.6rem;
    margin: 0.1rem 0.75rem;
    padding: 0.55rem 1rem;
    text-align: left;
    text-decoration: none;
    width: calc(100% - 1.5rem);
}

/* Long labels truncate with an ellipsis (tooltip carries the full text). */
.psh-sidenav-item > span:first-of-type {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.psh-sidenav-item:hover {
    background: var(--psh-nav-active-bg);
}

/* Active item: the icon tints accent-green, like the Angular nav. */
.psh-sidenav-item.psh-active {
    font-weight: 600;
}

.psh-sidenav-item.psh-active .psh-nav-icon {
    color: var(--psh-nav-accent);
}

.psh-nav-icon {
    flex-shrink: 0;
    height: 1.1rem;
    width: 1.1rem;
}

.psh-sidenav-group > span {
    flex: 1;
}

.psh-sidenav-chevron-btn {
    align-items: center;
    background: transparent;
    border: none;
    border-radius: var(--psh-radius-sm);
    color: inherit;
    cursor: pointer;
    display: flex;
    flex: 0 0 auto;
    justify-content: center;
    padding: 0.25rem;
}

.psh-sidenav-chevron-btn:hover {
    background: var(--psh-nav-bg);
}

.psh-sidenav-chevron-btn .psh-nav-icon {
    transition: transform 0.15s ease;
}

.psh-sidenav-group.psh-expanded .psh-sidenav-chevron-btn .psh-nav-icon {
    transform: rotate(180deg);
}

.psh-sidenav-child {
    padding-left: 2.7rem;
}

/* Nested groups indent one step per level */
.psh-sidenav-children .psh-sidenav-item {
    padding-left: 2.4rem;
}

.psh-sidenav-children .psh-sidenav-children .psh-sidenav-item {
    padding-left: 3.6rem;
}

.psh-sidenav-footer {
    border-top: 1px solid var(--psh-nav-active-bg);
    padding-bottom: 0.5rem;
}

.psh-sidenav-backdrop {
    background: rgb(10 14 20 / 0.55);
    inset: 0;
    position: fixed;
    z-index: 94;
}

/* Desktop pin/unpin: the Angular fixed-toggle-btn equivalent. Unpinned, the nav
   becomes an icon-only rail that expands over the content on hover. Scoped to
   desktop - mobile always uses the hamburger drawer. */
@media (min-width: 921px) {
    body.psh-sidenav-collapsed .psh-sidenav {
        bottom: 0;
        left: 0;
        overflow-x: hidden;
        position: fixed;
        top: 0;
        transition: width 0.15s ease;
        /* 65px, the Angular rail width */
        width: 4rem;
    }

    /* Rail: icons only (pin the nav to get labels back). Group rows still
       navigate to their first child. The header block goes entirely - the
       Angular rail has no logo strip. */
    body.psh-sidenav-collapsed .psh-sidenav .psh-sidenav-item span,
    body.psh-sidenav-collapsed .psh-sidenav .psh-sidenav-children,
    body.psh-sidenav-collapsed .psh-sidenav .psh-sidenav-chevron-btn,
    body.psh-sidenav-collapsed .psh-sidenav .psh-sidenav-header {
        display: none;
    }

    /* Icons scale up in the rail, like the Angular fa-2x treatment. */
    body.psh-sidenav-collapsed .psh-sidenav .psh-nav-icon {
        height: 1.65rem;
        width: 1.65rem;
    }

    body.psh-sidenav-collapsed .psh-sidenav .psh-sidenav-item {
        justify-content: center;
        margin: 0.35rem 0.4rem;
        padding: 0.55rem 0.4rem;
    }

    body.psh-sidenav-collapsed .psh-main {
        margin-left: 4rem;
    }
}

/* Straddles the nav's right edge, vertically centered on the top bar band
   (clear of the user section at the bottom); slides to the screen edge when
   collapsed. Centering on the top bar - rather than a fixed distance below
   it - keeps it clear of a page's own <h1>, which starts right at the top of
   the content area on pages that don't add extra top spacing.
   Positioned by its left edge, not a translateX(-50%) center, and biased
   toward the nav side: a symmetric straddle reaches ~22px past the boundary,
   which is more than the topbar/page's own left gap (1rem/16px) - so a
   centered button always overlapped whatever text starts right at that gap
   (the topbar title, a page <h1>). This inset keeps a small "straddle" peek
   across the boundary without reaching that far. */
.psh-nav-pin-btn {
    align-items: center;
    background: var(--psh-nav-bg);
    border: 1px solid var(--psh-nav-active-bg);
    border-radius: 5rem;
    color: var(--psh-nav-text);
    cursor: pointer;
    display: flex;
    justify-content: center;
    left: calc(19.5rem - 1.25rem);
    padding: 0.3rem 0.55rem;
    position: fixed;
    top: calc(var(--psh-topnav-height) / 2);
    transform: translateY(-50%);
    transition: left 0.2s ease;
    z-index: 96;
}

body.psh-sidenav-collapsed .psh-nav-pin-btn {
    left: calc(4rem - 1.25rem);
}

.psh-nav-pin-btn .psh-nav-icon {
    height: 0.9rem;
    transform: rotate(90deg);
    transition: transform 0.2s ease;
    width: 0.9rem;
}

body.psh-sidenav-collapsed .psh-nav-pin-btn .psh-nav-icon {
    transform: rotate(-90deg);
}

/* ---------- Top bar ---------- */

.psh-topbar {
    align-items: center;
    background: var(--psh-surface);
    box-shadow: 0 2px 6px rgb(0 0 0 / 0.12);
    display: flex;
    gap: var(--psh-gap-sm);
    height: var(--psh-topnav-height);
    padding: 0 var(--psh-gap);
    position: sticky;
    top: 0;
    z-index: 20;
}

/* Pages with nothing but the search box in the topbar (no title, no tabs -
   see ViewData["TopBarPlain"]) drop the card-like surface/shadow so the bar
   reads as part of the page instead of an obviously empty toolbar, and are
   shorter too - the full topbar height was sized for a title/tabs row, not
   a lone search field, and stacked on top of .psh-page's own padding-top it
   read as a lot of dead air before the page's actual content. */
.psh-topbar-plain {
    background: transparent;
    box-shadow: none;
    height: 2.75rem;
}

/* Less top padding to match - there's no bar edge here to breathe away from
   the way there is on a normal (non-plain) topbar. */
.psh-topbar-plain + .psh-page {
    padding-top: 0.75rem;
}

/* The breadcrumb's own top margin just stacks on top of the page padding
   above - drop it here specifically; its bottom margin before the <h1>
   below is unaffected, and other pages using .psh-breadcrumb keep both. */
.psh-topbar-plain + .psh-page .psh-breadcrumb {
    margin-top: 0;
}

.psh-topbar-title {
    font-weight: 600;
    margin-left: 1rem;
}

/* Divider between the section title and its tabs (Angular breadcrumb rule). */
.psh-topbar-title:not(:last-child) {
    border-right: 1px solid var(--psh-border);
    padding-right: var(--psh-gap);
}

.psh-topbar-logo {
    display: block;
    height: 2rem;
    width: auto;
}

.psh-topbar-menu-btn {
    background: transparent;
    border: none;
    color: var(--psh-text);
    cursor: pointer;
    display: none;
    padding: 0.25rem;
}

@media (max-width: 920px) {
    /* Mobile always uses the full-width hamburger drawer; the rail state and
       its content offset don't apply. */
    .psh-sidenav,
    body.psh-sidenav-collapsed .psh-sidenav {
        bottom: 0;
        left: 0;
        margin-left: 0;
        position: fixed;
        top: 0;
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        width: 15rem;
    }

    body.psh-sidenav-open .psh-sidenav {
        transform: none;
    }


    .psh-topbar-menu-btn {
        display: flex;
    }

    /* Mobile uses the hamburger drawer instead of pin/unpin */
    .psh-nav-pin-btn {
        display: none;
    }
}

/* ---------- Page / cards ---------- */

/* Full-width like the Angular shell - pages fill the space beside the nav.
   Use .psh-page-narrow on a page's root element when a form reads better
   constrained. */
.psh-page {
    padding: var(--psh-gap-lg) var(--psh-gap);
    width: 100%;
}

.psh-page-narrow {
    margin: 0 auto;
    max-width: var(--psh-page-max-width);
}

.psh-page h1 {
    font-size: 1.4rem;
    margin: 0 0 var(--psh-gap) 0;
}

.psh-card {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    padding: var(--psh-gap-lg);
}

.psh-card + .psh-card {
    margin-top: var(--psh-gap);
}

.psh-empty {
    color: var(--psh-text-muted);
    padding: var(--psh-gap-lg);
    text-align: center;
}

/* Wiki category tree (Wiki/List.cshtml, _WikiTreeNode.cshtml) - expand/
   collapse is native <details>/<summary>, no JS. */
.psh-tree-root,
.psh-tree-children {
    list-style: none;
    margin: 0;
    padding: 0;
}

.psh-tree-children {
    margin-left: 1.4rem;
    padding-top: 0.25rem;
}

.psh-tree-item {
    padding: 0.15rem 0;
}

.psh-tree-row {
    align-items: flex-start;
    display: flex;
    gap: var(--psh-gap-sm);
}

.psh-tree-details {
    flex: 0 1 auto;
    min-width: 0;
}

.psh-tree-details > summary {
    cursor: pointer;
}

.psh-tree-link {
    align-items: center;
    display: inline-flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.psh-tree-actions {
    align-items: center;
    display: flex;
    flex: 0 0 auto;
    gap: 0.25rem;
}

.psh-text-muted {
    color: var(--psh-text-muted);
}

.psh-page-info-footer {
    margin-top: var(--psh-gap-lg);
}

.psh-page-info-footer span + span {
    margin-left: 0.35rem;
}

/* Rendered rich-text documents (footer pages, the wiki view/preview panes).
   overflow-x scrolls oversized content (a wide image, a long code line -
   .psh-prose pre already does its own overflow-x below) in place instead of
   growing the box - same reasoning as the fenced-code-block rule. */
.psh-prose {
    overflow-x: auto;
}

.psh-prose h1,
.psh-prose h2,
.psh-prose h3 {
    margin: 1.2em 0 0.4em;
}

.psh-prose p {
    margin: 0 0 0.75em;
}

.psh-prose ul,
.psh-prose ol {
    margin: 0 0 0.75em;
    padding-left: 1.5rem;
}

.psh-prose h4,
.psh-prose h5,
.psh-prose h6 {
    margin: 1.2em 0 0.4em;
}

.psh-prose code {
    background: var(--psh-surface-raised);
    border-radius: var(--psh-radius-sm);
    font-family: var(--psh-font-mono);
    font-size: 0.9em;
    padding: 0.1em 0.3em;
}

.psh-prose pre {
    background: var(--psh-surface-raised);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    margin: 0 0 0.75em;
    overflow-x: auto;
    padding: var(--psh-gap-sm);
}

.psh-prose pre code {
    background: none;
    padding: 0;
}

.psh-prose blockquote {
    border-left: 3px solid var(--psh-border);
    color: var(--psh-text-muted);
    margin: 0 0 0.75em;
    padding: 0.2em 0 0.2em 1rem;
}

.psh-prose img {
    height: auto;
    max-width: 100%;
}

.psh-prose table {
    border-collapse: collapse;
    margin: 0 0 0.75em;
    width: 100%;
}

.psh-prose th,
.psh-prose td {
    border: 1px solid var(--psh-border);
    padding: 0.4rem 0.6rem;
    text-align: left;
}

/* Wiki "red link" - a Markdown link whose target page doesn't exist yet
   (WikiMarkdownService); clicking it opens a pre-filled create form. */
.psh-prose a.missing-page-link {
    color: var(--psh-danger);
    text-decoration: underline dotted;
}

/* An <img> whose src 404s (wiki-content.js's error handler adds this) - the
   native broken-image glyph is easy to miss, especially with the empty alt
   text the editor inserts, so give it a visible placeholder instead. */
.psh-prose img.psh-broken-image {
    background-color: var(--psh-danger-bg);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c0392b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'/%3E%3Cpath d='M21 15l-5-5L5 21'/%3E%3Cline x1='3' y1='3' x2='21' y2='21'/%3E%3C/svg%3E");
    background-position: center;
    background-repeat: no-repeat;
    background-size: 2rem;
    border: 1px dashed var(--psh-danger);
    border-radius: var(--psh-radius-sm);
    display: inline-block;
    min-height: 3rem;
    min-width: 3rem;
}

/* {TOC} token (WikiMarkdownService.BuildToc) - a compact inset box like the
   legacy wiki's "Contents" box, with nested CSS-counter numbering
   (1, 1.1, 1.1.1) instead of the browser default of restarting per level. */
.psh-toc {
    background: var(--psh-surface-raised);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    display: inline-block;
    margin: 0 0 1em;
    padding: 0.75rem 1.25rem;
}

.psh-toc-title {
    font-weight: 700;
    margin: 0 0 0.4em;
}

.psh-toc-toggle {
    font-weight: 400;
    font-size: var(--psh-text-size-sm);
    margin-left: 0.4em;
}

.psh-toc ol {
    counter-reset: psh-toc-counter;
    list-style: none;
    margin: 0;
    padding-left: 1.25rem;
}

.psh-toc > ol {
    padding-left: 0;
}

.psh-toc li {
    counter-increment: psh-toc-counter;
}

.psh-toc li::before {
    color: var(--psh-text-muted);
    content: counters(psh-toc-counter, ".") ". ";
    font-weight: 600;
}

.psh-toc.psh-toc-collapsed ol {
    display: none;
}

/* <nowiki>...</nowiki> - literal text, not parsed as Markdown
   (WikiMarkdownService). */
.psh-nowiki {
    background: var(--psh-surface-raised);
    border-radius: var(--psh-radius-sm);
    display: inline-block;
    font-family: var(--psh-font-mono);
    padding: 0.1em 0.4em;
}

/* Fenced code block syntax highlighting (RazorAssets/js/wiki-content.js) -
   a small hand-written tokenizer, not a vendored library. */
.tok-keyword { color: #b258c4; font-weight: 600; }
.tok-string { color: #2e9d55; }
.tok-number { color: #d2792f; }
.tok-comment { color: #8a93a8; font-style: italic; }
.tok-tag { color: #d84f7a; }
.tok-attr { color: #2f96b4; }

[data-theme="dark"] .tok-keyword { color: #d089e0; }
[data-theme="dark"] .tok-string { color: #6bc98a; }
[data-theme="dark"] .tok-number { color: #e0a06a; }
[data-theme="dark"] .tok-comment { color: #9aa4b0; }
[data-theme="dark"] .tok-tag { color: #ea86a4; }
[data-theme="dark"] .tok-attr { color: #7cc4dc; }

/* Wiki editor's Markdown toolbar (RazorAssets/js/wiki-editor.js) - inserts
   syntax into the plain-text textarea, matching the legacy wiki's actual
   editor rather than a rich-text WYSIWYG. */
.psh-editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-bottom: 0.4rem;
}

/* One row per image in the "Browse Library" modal (Edit.cshtml). */
.psh-attachment-row {
    align-items: center;
    border-bottom: 1px solid var(--psh-border);
    display: flex;
    gap: 0.5rem;
    padding: 0.35rem 0;
}

.psh-attachment-row a {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.psh-attachment-row .psh-btn {
    margin-left: auto;
}

.psh-library-thumb {
    border-radius: var(--psh-radius-sm);
    flex-shrink: 0;
    height: 2rem;
    object-fit: cover;
    width: 2rem;
}

/* Admin Media Library (Pages/Admin/MediaLibrary.cshtml): one row per folder
   or file, folders listed above files within a directory. */
.psh-media-row {
    align-items: center;
    border-bottom: 1px solid var(--psh-border);
    display: flex;
    gap: 0.6rem;
    padding: 0.5rem 0;
}

.psh-media-row-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.psh-media-row-meta {
    flex-shrink: 0;
    font-size: var(--psh-text-size-sm);
    white-space: nowrap;
}

.psh-media-row-actions {
    display: flex;
    gap: 0.35rem;
    margin-left: auto;
}

.psh-breadcrumb {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin: 0.75rem 0;
}

.psh-breadcrumb-sep {
    color: var(--psh-text-muted, currentColor);
    opacity: 0.6;
}

.psh-breadcrumb-current {
    font-weight: 600;
}

.psh-breadcrumb-link {
    background: none;
    border: none;
    color: var(--psh-link, inherit);
    cursor: pointer;
    font: inherit;
    padding: 0;
    text-decoration: underline;
}

/* Folder picker inside the "Move to..." modal. */
.psh-media-move-item {
    align-items: center;
    display: flex;
    gap: 0.4rem;
    margin: 0.2rem 0.3rem 0.2rem 0;
}

/* Fixed to the viewport bottom and centered, like the Angular footer. */
.psh-footer {
    align-items: center;
    background: var(--psh-bg);
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    font-size: 70%;
    gap: 0.5rem;
    justify-content: center;
    left: 0;
    padding: 0.3rem var(--psh-gap);
    position: fixed;
    right: 0;
    z-index: 15;
}

.psh-footer a {
    color: var(--psh-text-muted);
    text-decoration: none;
}

.psh-footer a:hover {
    color: var(--psh-text);
    text-decoration: underline;
}

.psh-footer-sep {
    color: var(--psh-text-muted);
}

/* Keep page content clear of the fixed footer. */
.psh-page {
    padding-bottom: 3rem;
}

@media (max-width: 920px) {
    /* The Angular footer is hidden on mobile. */
    .psh-footer {
        display: none;
    }
}

/* ---------- Forms ---------- */

.psh-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: var(--psh-gap);
}

.psh-field-grid {
    display: grid;
    gap: 0 var(--psh-gap);
    grid-template-columns: 1fr 1fr;
}

/* Grid items default to min-width:auto, which refuses to shrink below its
   content's intrinsic width - so wide content (e.g. a big image in the
   Markdown preview) would grow this whole column instead of scrolling
   inside it, squeezing the sibling column. min-width:0 lets the track
   actually honor the 1fr split. */
.psh-field-grid > .psh-field {
    min-width: 0;
}

.psh-field-full {
    grid-column: 1 / -1;
}

.psh-label {
    color: var(--psh-text-muted);
    font-size: var(--psh-text-size-sm);
    font-weight: 600;
}

.psh-input,
.psh-select,
.psh-textarea {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    color: var(--psh-text);
    font: inherit;
    padding: 0.5rem 0.65rem;
    width: 100%;
}

.psh-input:focus,
.psh-select:focus,
.psh-textarea:focus,
.psh-btn:focus-visible {
    box-shadow: 0 0 0 3px var(--psh-focus-ring);
    outline: none;
}

.psh-input.input-validation-error,
.psh-select.input-validation-error,
.psh-textarea.input-validation-error {
    border-color: var(--psh-danger);
}

/* Locked to the same fixed height as the Markdown textarea beside it
   (below) so the two always line up - a max-height here (with the
   textarea's native resize handle left on) let the textarea grow taller
   than this and spill over whatever followed it. */
#wiki-preview-pane {
    height: 36rem;
    overflow-y: auto;
}

/* The Markdown source textarea (Edit.cshtml) - resize is off so it can't
   drift from #wiki-preview-pane's height above; other .psh-textarea fields
   with no paired preview (e.g. Help/Edit.cshtml) keep the default resize. */
[data-markdown-source] {
    height: 36rem;
    resize: none;
}

.psh-error,
.field-validation-error {
    color: var(--psh-danger);
    font-size: var(--psh-text-size-sm);
}

.validation-summary-errors {
    background: var(--psh-danger-bg);
    border: 1px solid var(--psh-danger);
    border-radius: var(--psh-radius-sm);
    color: var(--psh-danger);
    margin-bottom: var(--psh-gap);
    padding: 0.6rem 0.8rem;
}

.validation-summary-errors ul {
    margin: 0;
    padding-left: 1.1rem;
}

.validation-summary-valid {
    display: none;
}

/* ---------- Buttons ---------- */
/* Pill-shaped (999px) to match .psh-chip and .psh-topbar-tabs - one button
   shape across the whole app rather than three different silhouettes. */

.psh-btn {
    background: var(--psh-primary);
    border: 1px solid var(--psh-primary);
    border-radius: 999px;
    color: var(--psh-primary-contrast);
    cursor: pointer;
    display: inline-block;
    font: inherit;
    font-weight: 600;
    padding: 0.5rem 1rem;
    text-align: center;
    text-decoration: none;
}

.psh-btn:hover {
    background: var(--psh-primary-hover);
    border-color: var(--psh-primary-hover);
}

/* display: inline-block above otherwise beats the [hidden] attribute's
   default UA styling (an author rule always wins over the UA stylesheet
   regardless of specificity), so any button toggled via `hidden` - like
   #psh-mfa-off-btn - would silently stay visible without this. */
.psh-btn[hidden] {
    display: none;
}

.psh-btn-secondary {
    background: var(--psh-surface);
    border-color: var(--psh-border);
    color: var(--psh-text);
}

.psh-btn-secondary:hover {
    background: var(--psh-bg);
    border-color: var(--psh-border);
}

.psh-btn-danger {
    background: var(--psh-danger);
    border-color: var(--psh-danger);
    color: #fff;
}

.psh-btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--psh-text-muted);
}

.psh-btn-ghost:hover {
    background: var(--psh-bg);
    border-color: transparent;
    color: var(--psh-text);
}

.psh-btn-sm {
    font-size: var(--psh-text-size-sm);
    padding: 0.3rem 0.65rem;
}

.psh-btn-block {
    display: block;
    width: 100%;
}

.psh-btn:disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

.psh-btn-icon {
    align-items: center;
    display: inline-flex;
    justify-content: center;
    padding: 0.5rem 0.6rem;
}

.psh-btn-icon .psh-nav-icon {
    height: 1.1rem;
    width: 1.1rem;
}

.psh-excel-icon {
    display: block;
    height: 1.2rem;
    width: 1.2rem;
}

/* ---------- Tables ---------- */

/* Fixed-height scroll region with a sticky header, like the Angular tables'
   scrollHeight="650px". */
.psh-table-wrap {
    max-height: 650px;
    overflow: auto;
}

.psh-table {
    border-collapse: collapse;
    width: 100%;
}

.psh-table th,
.psh-table td {
    border: 1px solid var(--psh-border);
    padding: 0.65rem 0.7rem;
    text-align: left;
    vertical-align: middle;
}

/* Dark headers, like the Angular shell's $table-header-bg */
.psh-table th {
    background: var(--psh-table-header-bg);
    color: var(--psh-table-header-text);
    font-size: var(--psh-text-size-sm);
    font-weight: 650;
    position: sticky;
    top: 0;
    vertical-align: top;
    white-space: nowrap;
    z-index: 2;
}

/* Zebra striping + hover, matching stripedRows/rowHover on every p-table. */
.psh-table tbody tr:nth-child(even) {
    background: var(--psh-bg);
}

.psh-table tbody tr:hover {
    background: var(--psh-table-hover);
}

.psh-row-click {
    cursor: pointer;
}

/* Admin dashboard: one bordered panel per nav group (Angular #adminSection). */
.psh-page-title {
    font-size: 1.4rem;
    margin: 0 0 0.5rem;
}

.psh-title-rule {
    border: none;
    border-top: 1px solid var(--psh-border);
    margin: 0 0 var(--psh-gap-lg);
}

/* Same surface/shadow/hover-lift language as the Dashboard's category tiles
   (.psh-tile) - kept as its own class rather than reused directly since an
   admin panel's *structure* differs (a group stacks child links below its
   header; a leaf is just one clickable card - see Admin/Dashboard.cshtml). */
.psh-admin-panel {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-left: 4px solid var(--psh-nav-accent);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.3rem 1.2rem;
    transition: box-shadow 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.psh-admin-panel:hover {
    border-color: #adb5bd;
    border-left-color: var(--psh-nav-accent);
    box-shadow: 0 4px 12px rgb(16 24 40 / 0.12), 0 2px 4px rgb(16 24 40 / 0.08);
    transform: translateY(-1px);
}

.psh-admin-panel-title {
    align-items: center;
    display: flex;
    font-size: 1.02rem;
    font-weight: 700;
    gap: 0.65rem;
    margin: 0;
}

.psh-admin-panel-icon {
    align-items: center;
    background: color-mix(in srgb, var(--psh-primary) 9%, transparent);
    border-radius: var(--psh-radius);
    display: flex;
    flex-shrink: 0;
    height: 2.6rem;
    justify-content: center;
    width: 2.6rem;
}

.psh-admin-panel-icon .psh-nav-icon {
    color: var(--psh-primary);
    height: 1.4rem;
    width: 1.4rem;
}

.psh-admin-panel a {
    color: var(--psh-text);
    text-decoration: none;
}

.psh-admin-panel a:hover {
    color: var(--psh-primary);
    text-decoration: underline;
}

.psh-admin-panel-link {
    color: inherit;
    text-decoration: none;
}

.psh-admin-panel-link:hover .psh-admin-panel-title {
    color: var(--psh-primary);
}

@media (min-width: 921px) {
    /* Fixed 4-up like the Angular col-md-3 tiles. */
    .psh-tile-grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* Centered ~2/3-width video player (Angular col-md-8 offset-md-2). */
.psh-video-center {
    margin: 0 auto var(--psh-gap-lg);
    max-width: 66%;
}

@media (max-width: 920px) {
    .psh-video-center {
        max-width: 100%;
    }
}

/* Clamped long text with click-to-expand (Angular app-ellipsis). */
.psh-clamp {
    -webkit-box-orient: vertical;
    cursor: pointer;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    overflow: hidden;
}

.psh-clamp-open {
    -webkit-line-clamp: unset;
}

.psh-help-link {
    color: var(--psh-primary);
    text-decoration: none;
}

.psh-help-link:hover {
    text-decoration: underline;
}

/* Security tab: two inline groups on one row, like the Angular layout. */
.psh-security-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-lg);
    justify-content: space-around;
    margin-bottom: var(--psh-gap);
}

.psh-security-group {
    flex: 1 1 18rem;
    max-width: 26rem;
}

.psh-delete-row {
    justify-content: flex-end;
    margin-bottom: var(--psh-gap);
}

/* MFA status pill (Angular badge). */
.psh-badge {
    border-radius: 999px;
    display: inline-block;
    font-size: var(--psh-text-size-sm);
    font-weight: 700;
    margin-right: 0.4rem;
    padding: 0.1rem 0.7rem;
}

.psh-badge-on {
    background: var(--psh-success);
    color: #ffffff;
}

.psh-badge-off {
    background: var(--psh-border);
    color: var(--psh-text);
}

/* Fresh recovery codes: amber dashed callout with a monospace grid. */
.psh-recovery-fresh {
    background: #fff8e1;
    border: 2px dashed #e0a800;
    border-radius: var(--psh-radius-sm);
    color: #533f03;
    padding: var(--psh-gap);
}

.psh-recovery-grid {
    display: grid;
    font-family: var(--psh-font-mono);
    gap: 0.3rem 1.5rem;
    grid-template-columns: repeat(2, max-content);
    margin: 0 0 var(--psh-gap-sm);
}

/* Vertical stack of MFA method choices (Angular .mfa-choice buttons). */
.psh-mfa-choices {
    display: flex;
    flex-direction: column;
    gap: var(--psh-gap-sm);
    max-width: 22rem;
}

/* display: flex above otherwise beats the [hidden] attribute's default UA
   styling, since an author rule always wins over the UA stylesheet
   regardless of specificity - same fix as .psh-popover-panel[hidden] etc. */
.psh-mfa-choices[hidden] {
    display: none;
}

.psh-mfa-choices .psh-btn {
    text-align: left;
}

.psh-mfa-key {
    background: var(--psh-bg);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    padding: 0.15rem 0.5rem;
}

/* Status indicators at the top of the edit-user page (lock/bounce/active). */
.psh-user-indicators {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

.psh-indicator {
    align-items: center;
    background: var(--psh-danger-bg);
    border: 1px solid var(--psh-danger);
    border-radius: 999px;
    color: var(--psh-danger);
    cursor: pointer;
    display: inline-flex;
    font: inherit;
    font-size: var(--psh-text-size-sm);
    font-weight: 600;
    gap: 0.4rem;
    padding: 0.3rem 0.8rem;
}

.psh-indicator .psh-nav-icon {
    height: 1rem;
    width: 1rem;
}

.psh-section-title {
    align-items: center;
    display: flex;
    gap: 0.5rem;
}

.psh-section-title .psh-nav-icon {
    height: 1.3rem;
    width: 1.3rem;
}

/* Full-width info banner (Angular alert-info), e.g. the SMS opt-in block. */
.psh-alert-info {
    align-items: center;
    background: var(--psh-info-bg);
    border: 1px solid var(--psh-info);
    border-radius: var(--psh-radius-sm);
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
    padding: 0.75rem var(--psh-gap);
}

.psh-optin-label {
    align-items: center;
    cursor: pointer;
    display: inline-flex;
    gap: 0.5rem;
}

/* Borderless notification list, like the Angular preference rows. */
.psh-notif-row {
    align-items: center;
    display: flex;
    gap: var(--psh-gap);
    padding: 0.6rem 0;
}

.psh-notif-row + .psh-notif-row {
    border-top: 1px solid var(--psh-border);
}

.psh-notif-desc {
    margin-left: auto;
    text-align: right;
}

.psh-buttongroup .psh-inline-form + .psh-inline-form .psh-chip {
    margin-left: -1px;
}

.psh-buttongroup .psh-inline-form .psh-chip {
    border-radius: 0;
}

.psh-chip-first {
    border-bottom-left-radius: var(--psh-radius-sm) !important;
    border-top-left-radius: var(--psh-radius-sm) !important;
}

.psh-chip-last {
    border-bottom-right-radius: var(--psh-radius-sm) !important;
    border-top-right-radius: var(--psh-radius-sm) !important;
}

.psh-buttongroup .psh-chip {
    background: var(--psh-surface);
    cursor: pointer;
    font: inherit;
}

/* Sticky bottom action bar, like the Angular app-fixed-buttons region.
   position: sticky (not fixed) deliberately - fixed is always positioned
   against the viewport, ignoring the sidenav's flexbox-reserved width, which
   put this bar's left edge (and thus its buttons) underneath the sidenav
   (z-index 95 vs. this bar's 16) on every page that uses it. Sticky respects
   its normal-flow container's width (already correctly offset past the
   sidenav by .psh-main's flex layout) while still pinning to the viewport
   bottom on scroll. */
.psh-fixed-buttons {
    align-items: center;
    background: var(--psh-surface);
    border-top: 1px solid var(--psh-border);
    bottom: 0;
    display: flex;
    gap: var(--psh-gap-sm);
    padding: 0.6rem var(--psh-gap);
    position: sticky;
    z-index: 16;
}

/* Pushed to the far side of the Back/Save buttons instead of its usual
   below-the-content spot (Edit.cshtml only) - since the bar is sticky, this
   stays on screen the whole time you're editing instead of only when
   scrolled to the bottom. */
.psh-fixed-buttons .psh-page-info-footer {
    margin: 0 0 0 auto;
    text-align: right;
}

.psh-fixed-buttons-spacer {
    height: 4rem;
}

/* Back-arrow chip at the left of the tab row (Angular drill-in affordance). */
.psh-tab-back {
    align-items: center;
    border: 1px solid var(--psh-border);
    border-radius: 999px;
    color: var(--psh-text-muted);
    display: flex;
    padding: 0.25rem 0.6rem;
    text-decoration: none;
}

.psh-tab-back:hover {
    background: rgb(156 206 82 / 0.15);
    border-color: var(--psh-nav-accent);
}

.psh-tab-back .psh-nav-icon {
    height: 1rem;
    width: 1rem;
}

/* Info banner above a list, like the Angular page-description block. */
.psh-page-description {
    align-items: center;
    display: flex;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

.psh-page-description p {
    margin: 0;
}

.psh-desc-icon .psh-nav-icon {
    color: var(--psh-primary);
    height: 1.2rem;
    width: 1.2rem;
}

/* Red padlock beside a locked-out user's name (Angular faUserLock). */
.psh-lock-icon .psh-nav-icon {
    color: var(--psh-danger);
    height: 0.95rem;
    margin-left: 0.3rem;
    vertical-align: middle;
    width: 0.95rem;
}

.psh-email-cell {
    align-items: center;
    display: inline-flex;
    gap: var(--psh-gap-sm);
}

.psh-email-cell .psh-btn {
    align-items: center;
    display: inline-flex;
    gap: 0.25rem;
}

.psh-email-cell .psh-nav-icon {
    height: 0.85rem;
    width: 0.85rem;
}

.psh-btn-info {
    background: var(--psh-info);
    border-color: var(--psh-info);
    color: #ffffff;
}

/* Client-side column chooser toggles cells with [hidden]. */
.psh-table th[hidden],
.psh-table td[hidden] {
    display: none;
}

/* cellClass passthrough from the Vm column metadata */
.psh-table .text-center {
    text-align: center;
}

.psh-table .th-width-13 {
    width: 13%;
}

/* Loading mask during live-search fetches, like the p-table loading overlay. */
.psh-table-region {
    position: relative;
}

.psh-table-loading .psh-table-wrap {
    opacity: 0.45;
}

.psh-table-loading::after {
    animation: psh-spin 0.8s linear infinite;
    border: 3px solid var(--psh-border);
    border-radius: 50%;
    border-top-color: var(--psh-nav-accent);
    content: "";
    height: 2rem;
    left: calc(50% - 1rem);
    position: absolute;
    top: 8rem;
    width: 2rem;
    z-index: 6;
}

@keyframes psh-spin {
    to { transform: rotate(360deg); }
}

.psh-th-label {
    margin-bottom: 0.3rem;
}

.psh-col-search {
    font-size: var(--psh-text-size-sm);
    font-weight: 400;
    min-width: 6rem;
    padding: 0.25rem 0.5rem;
}

.psh-editor {
    background: var(--psh-surface);
    min-height: 12rem;
}

.psh-table-toolbar {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

/* Left cluster (New / chooser / Filters / clear chip) wraps as one group,
   mirroring the Angular caption's two-group flex layout. */
.psh-table-toolbar-group {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
}

.psh-table-toolbar-group .psh-btn {
    align-items: center;
    display: inline-flex;
    gap: 0.35rem;
}

.psh-table-toolbar-group .psh-nav-icon {
    height: 1rem;
    width: 1rem;
}

.psh-table-toolbar-search {
    display: flex;
    gap: var(--psh-gap-sm);
    margin-left: auto;
}

.psh-colchooser {
    position: relative;
}

.psh-colchooser > .psh-btn {
    align-items: center;
    display: inline-flex;
    gap: 0.35rem;
}

.psh-colchooser .psh-nav-icon {
    height: 0.9rem;
    width: 0.9rem;
}

/* ---------- Table filter popover ---------- */
/* Mirrors the Angular tables' Filters button + p-popover. */

.psh-filter-popover {
    position: relative;
}

.psh-btn-warn {
    background: var(--psh-surface);
    border-color: #e0a800;
    color: #b38600;
}

.psh-btn-warn:hover {
    background: var(--psh-bg);
    border-color: #e0a800;
}

.psh-btn-clear-filters {
    background: var(--psh-success-bg);
    border-color: var(--psh-success);
    color: var(--psh-success);
    font-size: var(--psh-text-size-sm);
}

.psh-btn-clear-filters:hover {
    background: var(--psh-bg);
}

.psh-popover-panel[hidden] {
    display: none;
}

.psh-popover-panel {
    align-items: flex-start;
    background: var(--psh-surface-raised);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    box-shadow: var(--psh-shadow);
    display: flex;
    /* Filters stack vertically (one filter per line); each row's own
       fields still sit on a single line. */
    flex-direction: column;
    gap: 0.75rem;
    left: 0;
    max-width: min(90vw, 64rem);
    min-width: 20rem;
    padding: 0.75rem;
    position: absolute;
    top: calc(100% + 0.25rem);
    width: max-content;
    z-index: 30;
}

/* Each filter row keeps its own fields on one line. */
.psh-popover-panel .psh-chip-row,
.psh-popover-panel .psh-daterange-form,
.psh-popover-panel .psh-filter-bar {
    align-items: center;
    display: flex;
    flex-wrap: nowrap;
    gap: 0.5rem;
    margin: 0;
}

/* The global-audit form stacks its items too (one filter per line). */
.psh-popover-panel .psh-filter-bar {
    align-items: flex-start;
    flex-direction: column;
}

/* A date range's two pickers always share a line. */
.psh-daterange-inline {
    align-items: center;
    display: inline-flex;
    flex-wrap: nowrap;
    gap: 0.5rem;
}

/* Consistent control widths inside the filter popovers. The extra
   .psh-filter-item selectors outweigh its later width:auto rule. */
.psh-popover-panel .psh-select,
.psh-popover-panel .psh-filter-item .psh-select {
    width: 16rem;
}

.psh-popover-panel .psh-input-date,
.psh-popover-panel .psh-filter-item .psh-input-date {
    width: 10.5rem;
}

.psh-colchooser-panel[hidden] {
    display: none;
}

.psh-colchooser-panel {
    background: var(--psh-surface-raised);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    box-shadow: var(--psh-shadow);
    display: flex;
    flex-direction: column;
    left: 0;
    min-width: 12rem;
    padding: 0.35rem;
    position: absolute;
    top: calc(100% + 0.25rem);
    z-index: 30;
}

.psh-colchooser-option {
    align-items: center;
    border-radius: var(--psh-radius-sm);
    cursor: pointer;
    display: flex;
    gap: 0.5rem;
    padding: 0.35rem 0.5rem;
}

.psh-colchooser-option:hover {
    background: var(--psh-bg);
}

.psh-search-field {
    position: relative;
    width: 16rem;
}

.psh-search-field .psh-input {
    padding-right: 2.25rem;
}

.psh-search-btn {
    align-items: center;
    background: transparent;
    border: none;
    bottom: 0;
    color: var(--psh-text-muted);
    cursor: pointer;
    display: flex;
    padding: 0 0.6rem;
    position: absolute;
    right: 0;
    top: 0;
}

.psh-search-btn:hover {
    color: var(--psh-text);
}

.psh-search-btn .psh-nav-icon {
    height: 1rem;
    width: 1rem;
}

/* Global nav search box (topbar) - see Pages/Shared/_Layout.cshtml. */
.psh-topbar-search {
    margin-left: auto;
}

@media (max-width: 920px) {
    .psh-topbar-search.psh-search-field {
        width: 8rem;
    }
}

/* /wiki/search results page. */
.psh-search-page-form {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap);
    margin-bottom: var(--psh-gap);
}

.psh-search-page-field {
    width: 24rem;
    max-width: 100%;
}

/* Search typeahead dropdown - see RazorAssets/js/search-typeahead.js. Anchored
   to .psh-search-field/.psh-search-page-field, which are already
   position: relative. */
.psh-search-suggestions {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    left: 0;
    list-style: none;
    margin: 0.25rem 0 0;
    max-height: 20rem;
    overflow-y: auto;
    padding: 0.25rem;
    position: absolute;
    right: 0;
    top: 100%;
    z-index: 20;
}

.psh-search-suggestion {
    align-items: center;
    border-radius: var(--psh-radius-sm);
    cursor: pointer;
    display: flex;
    gap: 0.5rem;
    overflow: hidden;
    padding: 0.45rem 0.6rem;
}

.psh-search-suggestion-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.psh-search-suggestion-category {
    color: var(--psh-text-muted);
    flex-shrink: 0;
    font-size: 0.8rem;
}

.psh-search-suggestion:hover,
.psh-search-suggestion-active {
    background: var(--psh-bg);
}

.psh-search-results {
    display: flex;
    flex-direction: column;
    gap: var(--psh-gap-sm);
    list-style: none;
    margin: 0;
    padding: 0;
}

.psh-search-result-header {
    align-items: center;
    display: flex;
    gap: 0.5rem;
}

.psh-search-result-header .psh-nav-icon {
    color: var(--psh-text-muted);
    flex-shrink: 0;
    height: 1.1rem;
    width: 1.1rem;
}

.psh-search-result-title {
    font-weight: 600;
}

.psh-search-result-category {
    font-size: 0.875rem;
}

.psh-search-excerpt {
    color: var(--psh-text-muted);
    margin: 0.4rem 0 0;
}

.psh-search-excerpt mark {
    background: rgb(156 206 82 / 0.35);
    color: inherit;
}

.psh-table-sort {
    color: inherit;
    text-decoration: none;
}

.psh-table-sort:hover {
    text-decoration: underline;
}

/* Currently sorted column - accent tint, like the Angular sorted header. */
.psh-table-sort.psh-sorted {
    color: var(--psh-nav-accent);
}

.psh-sort-icon {
    font-size: 0.75em;
}

/* Neutral glyph on sortable-but-unsorted columns, like p-sortIcon at rest. */
.psh-sort-idle {
    opacity: 0.45;
}

/* ---------- Segmented button group (filter popovers) ---------- */
/* Mirrors the Angular p-buttongroup Yes/No/All filters. */

.psh-buttongroup {
    display: inline-flex;
    margin-bottom: var(--psh-gap);
}

/* Only when it is NOT the fused-chip segmented control above - a plain
   row of independent buttons (Edit/History/Copy for AI/..., Tree View/
   All Pages/Archived) needs real spacing between them, not the chips'
   deliberate zero-gap/negative-margin fusion. */
.psh-buttongroup:not(:has(.psh-chip)) {
    gap: 0.5rem;
}

.psh-btn-active {
    background: var(--psh-nav-accent);
    border-color: var(--psh-nav-accent);
    color: #1c2430;
    font-weight: 600;
}

.psh-buttongroup .psh-chip {
    border-radius: 0;
    margin-left: -1px;
}

.psh-buttongroup .psh-chip:first-child {
    border-bottom-left-radius: var(--psh-radius-sm);
    border-top-left-radius: var(--psh-radius-sm);
    margin-left: 0;
}

.psh-buttongroup .psh-chip:last-child {
    border-bottom-right-radius: var(--psh-radius-sm);
    border-top-right-radius: var(--psh-radius-sm);
}

.psh-buttongroup .psh-chip-active {
    background: var(--psh-primary);
    border-color: var(--psh-primary);
    color: var(--psh-primary-contrast);
}

/* Theme toggle: segmented Light/Dark with icons in the user submenu,
   like the Angular mat-button-toggle-group. */
.psh-theme-row {
    cursor: default;
}

.psh-theme-toggle .psh-chip {
    align-items: center;
    background: transparent;
    border-color: var(--psh-nav-active-bg);
    color: var(--psh-nav-text);
    cursor: pointer;
    display: inline-flex;
    font: inherit;
    gap: 0.3rem;
}

.psh-theme-toggle .psh-chip .psh-nav-icon {
    height: 0.9rem;
    width: 0.9rem;
}

/* The sidenav's theme-toggle chips assume a dark nav bar behind them
   (white text); on the auth page it sits on the normal light/dark body
   background instead, so use the general text/border tokens there. */
.psh-auth-theme-toggle {
    display: flex;
    justify-content: center;
    margin-top: var(--psh-gap-lg);
}

.psh-auth-theme-toggle.psh-theme-toggle .psh-chip {
    border-color: var(--psh-border);
    color: var(--psh-text);
}

.psh-theme-toggle .psh-chip.psh-chip-active {
    background: var(--psh-nav-accent);
    border-color: var(--psh-nav-accent);
    color: #1c2430;
}

.psh-table-actions {
    text-align: right;
    white-space: nowrap;
}

.psh-table-actions .psh-btn + .psh-btn,
.psh-table-actions .psh-inline-form + .psh-btn,
.psh-table-actions .psh-btn + .psh-inline-form,
.psh-table-actions .psh-inline-form + .psh-inline-form {
    margin-left: 0.35rem;
}

/* ---------- Pager ---------- */

.psh-pager {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    justify-content: center;
    margin-top: var(--psh-gap);
}

/* Report text sits with the page controls, like the PrimeNG paginator strip. */
.psh-pager-summary {
    color: var(--psh-text-muted);
    font-size: var(--psh-text-size-sm);
    margin-left: 0.5rem;
}

.psh-pager-link {
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    color: var(--psh-text);
    min-width: 2rem;
    padding: 0.25rem 0.5rem;
    text-align: center;
    text-decoration: none;
}

a.psh-pager-link:hover {
    background: var(--psh-bg);
}

/* Current page in the primary green, like the PrimeNG highlight. */
.psh-pager-current {
    background: var(--psh-primary);
    border-color: var(--psh-primary);
    color: var(--psh-primary-contrast);
}

.psh-pager-gap {
    color: var(--psh-text-muted);
    padding: 0 0.25rem;
}

.psh-pager-size {
    align-items: center;
    display: flex;
    gap: 0.4rem;
    margin-right: var(--psh-gap);
}

.psh-pager-size .psh-select {
    padding: 0.25rem 0.5rem;
    width: auto;
}

.psh-center {
    text-align: center;
}

/* Outlined, like the Angular nav's "BETA" stamp (transparent fill). */
.psh-env-badge {
    background: transparent;
    border: 1px solid var(--psh-nav-accent);
    border-radius: var(--psh-radius-sm);
    color: var(--psh-nav-accent);
    font-size: 0.85rem;
    font-weight: 700;
    margin-left: var(--psh-gap-sm);
    padding: 0.1rem 0.45rem;
    text-transform: uppercase;
}

/* ---------- Auth layout ----------
   Matches the Angular login: centered logo above a narrow centered panel. */

.psh-auth-body {
    background: var(--psh-bg);
    display: block;
}

.psh-auth {
    display: block;
    margin: 0 auto;
    max-width: 28rem;
    padding: var(--psh-gap-lg) var(--psh-gap) var(--psh-gap);
    width: 100%;
}

.psh-auth-logo {
    display: block;
    height: 125px;
    margin: var(--psh-gap) auto var(--psh-gap-lg);
    width: auto;
}

.psh-auth-panel h2 {
    font-size: 1.2rem;
    margin: 0 0 var(--psh-gap) 0;
    text-align: center;
}

.psh-auth-panel .psh-btn {
    width: 100%;
}

.psh-auth-links {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-top: var(--psh-gap);
}

/* The Angular float-right auth links (forgot password, back to login). */
.psh-auth-links-right {
    align-items: flex-end;
}

/* Login button left, forgot link right - the Angular login row. */
.psh-auth-row {
    align-items: center;
    display: flex;
    justify-content: space-between;
}

/* Verify + Resend side by side, like the Angular MFA panel. */
.psh-auth-btn-row {
    display: flex;
    gap: var(--psh-gap-sm);
}

.psh-password-reqs {
    font-size: var(--psh-text-size-sm);
    margin-top: var(--psh-gap-lg);
}

.psh-auth-links a {
    color: var(--psh-auth-link);
    font-size: var(--psh-text-size-sm);
    text-decoration: none;
}

.psh-auth-links a:hover {
    text-decoration: underline;
}

@media (max-width: 640px) {
    .psh-field-grid {
        grid-template-columns: 1fr;
    }
}

/* ---------- Show/hide password ---------- */

.psh-input-group {
    display: flex;
}

.psh-input-group .psh-input {
    border-bottom-right-radius: 0;
    border-top-right-radius: 0;
    flex: 1;
}

.psh-input-group .psh-input-group-btn {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-bottom-right-radius: var(--psh-radius-sm);
    border-left: none;
    border-top-right-radius: var(--psh-radius-sm);
    color: var(--psh-text-muted);
    cursor: pointer;
    font: inherit;
    padding: 0 0.75rem;
}

.psh-input-group .psh-input-group-btn:hover {
    color: var(--psh-text);
}

.psh-input-group-btn svg {
    display: block;
    height: 1.15rem;
    width: 1.15rem;
}

.psh-input-group-btn .psh-icon-eye-off,
.psh-input-group-btn.psh-visible .psh-icon-eye {
    display: none;
}

.psh-input-group-btn.psh-visible .psh-icon-eye-off {
    display: block;
}

/* ---------- Top-bar tabs (the Angular secondary-nav pattern) ---------- */

.psh-topbar-tabs {
    align-self: stretch;
    display: flex;
    margin-left: var(--psh-gap);
    min-width: 0;
    overflow-x: auto;
    /* Setting only overflow-x forces the UA to compute overflow-y as auto
       too (per spec), so a 1px height rounding difference between this
       stretched row and its pill children was enough to trigger a vertical
       scrollbar nobody wanted - this row only ever needs to scroll sideways. */
    overflow-y: hidden;
}

/* Rounded pill chips with a green active fill, like the Angular
   top-secondary-nav tabs. */
.psh-topbar-tabs {
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0;
}

.psh-topbar-tabs a {
    align-items: center;
    border: 1px solid var(--psh-border);
    border-radius: 999px;
    color: var(--psh-text-muted);
    display: flex;
    padding: 0.25rem 0.9rem;
    text-decoration: none;
    white-space: nowrap;
}

.psh-topbar-tabs a:hover {
    background: rgb(156 206 82 / 0.15);
    border-color: var(--psh-nav-accent);
    color: var(--psh-text);
}

.psh-topbar-tabs a.psh-tab-active {
    background: var(--psh-nav-accent);
    border-color: var(--psh-nav-accent);
    color: #1c2430;
    font-weight: 600;
}

.psh-card-title {
    font-size: 1.05rem;
    margin: 0 0 var(--psh-gap) 0;
}

.psh-action-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

.psh-mfa-qr {
    background: #fff;
    display: inline-block;
    margin: var(--psh-gap-sm) 0;
    padding: 0.75rem;
}

.psh-recovery-codes {
    background: var(--psh-success-bg);
    border: 1px solid var(--psh-success);
    border-radius: var(--psh-radius-sm);
    margin-bottom: var(--psh-gap);
    padding: var(--psh-gap-sm) var(--psh-gap);
}

.psh-recovery-codes ul {
    columns: 2;
    margin: 0.5rem 0 0;
    padding-left: 1.25rem;
}

.psh-check {
    align-items: center;
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

/* Stack of checkboxes placed beside a taller field column, e.g. Title/Tags. */
.psh-check-stack {
    display: flex;
    flex-direction: column;
    margin-bottom: var(--psh-gap);
}

/* Small circular "?" button that opens a help modal, e.g. beside the markdown toolbar. */
.psh-help-icon {
    align-items: center;
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-radius: 50%;
    color: var(--psh-text-muted);
    cursor: pointer;
    display: inline-flex;
    font: inherit;
    font-size: var(--psh-text-size-sm);
    font-weight: 600;
    height: 1.75rem;
    justify-content: center;
    padding: 0;
    width: 1.75rem;
}

.psh-help-icon:hover,
.psh-help-icon:focus-visible {
    border-color: var(--psh-primary);
    color: var(--psh-primary);
    outline: none;
}

/* ---------- Home dashboard (centered logo, like the Angular dashboard) ---------- */

.psh-dashboard {
    text-align: center;
}

.psh-dashboard img {
    height: auto;
    max-width: min(100%, 40rem);
}

/* Dashboard category tile grid (Dashboard.cshtml). */
.psh-tile-grid {
    display: grid;
    gap: var(--psh-gap);
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

.psh-tile {
    background: var(--psh-surface);
    border: 1px solid var(--psh-border);
    border-left: 4px solid var(--psh-nav-accent);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    padding: 1.3rem 1.2rem;
    text-decoration: none;
    transition: box-shadow 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.psh-tile:hover {
    border-color: #adb5bd;
    border-left-color: var(--psh-nav-accent);
    box-shadow: 0 4px 12px rgb(16 24 40 / 0.12), 0 2px 4px rgb(16 24 40 / 0.08);
    transform: translateY(-1px);
}

.psh-tile:hover .psh-tile-title {
    color: var(--psh-primary);
}

.psh-tile-icon {
    align-items: center;
    background: color-mix(in srgb, var(--psh-primary) 9%, transparent);
    border-radius: var(--psh-radius);
    display: flex;
    height: 2.6rem;
    justify-content: center;
    width: 2.6rem;
}

.psh-tile-icon .psh-nav-icon {
    color: var(--psh-primary);
    height: 1.4rem;
    width: 1.4rem;
}

.psh-tile-title {
    font-size: 1.02rem;
    font-weight: 700;
    transition: color 0.15s ease;
}

.psh-tile-count {
    color: var(--psh-text-muted);
    font-size: 0.85rem;
}

/* Software & AI ecosystem diagram below the tiles (Dashboard.cshtml). The
   image has a white background, so the frame stays white in dark mode too. */
.psh-dashboard-diagram {
    margin-top: calc(var(--psh-gap-lg) * 2);
}

.psh-dashboard-diagram-title {
    font-size: 1.15rem;
    margin: 0 0 var(--psh-gap-sm);
}

.psh-dashboard-diagram a {
    background: #ffffff;
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    display: block;
    overflow: hidden;
}

.psh-dashboard-diagram img {
    display: block;
    height: auto;
    width: 100%;
}

/* Subcategory/article browse list appended to a page with children
   (Wiki/View.cshtml). */
.psh-child-group-title {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    margin: var(--psh-gap-lg) 0 var(--psh-gap-sm);
    text-transform: uppercase;
}

.psh-child-list {
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    overflow: hidden;
}

.psh-child-row {
    align-items: center;
    border-bottom: 1px solid var(--psh-border);
    color: inherit;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm) var(--psh-gap);
    justify-content: space-between;
    padding: 0.75rem 1rem;
    text-decoration: none;
}

.psh-child-row:last-child {
    border-bottom: none;
}

.psh-child-row:hover {
    background: var(--psh-bg);
}

.psh-child-row:hover .psh-child-row-title {
    color: var(--psh-primary);
}

.psh-child-row-title {
    color: inherit;
    flex: 1 1 auto;
    font-weight: 600;
    text-decoration: none;
}

.psh-child-row-tags {
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    gap: 0.35rem;
    justify-content: flex-end;
}

.psh-drag-handle {
    color: var(--psh-text-muted);
    cursor: grab;
    display: inline-flex;
    flex-shrink: 0;
}

.psh-favorite-row.psh-dragging {
    opacity: 0.4;
}

/* ---------- Video embed (16:9) ---------- */

.psh-video-frame {
    aspect-ratio: 16 / 9;
    width: 100%;
}

.psh-video-frame iframe {
    border: 0;
    height: 100%;
    width: 100%;
}

/* ---------- Filter chips ---------- */

.psh-chip-row {
    align-items: center;
    display: flex;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

.psh-chip {
    border: 1px solid var(--psh-border);
    border-radius: 999px;
    color: var(--psh-text);
    font-size: var(--psh-text-size-sm);
    padding: 0.2rem 0.75rem;
    text-decoration: none;
}

.psh-chip:hover {
    background: var(--psh-bg);
}

.psh-filter-bar {
    align-items: flex-end;
    display: flex;
    flex-wrap: wrap;
    gap: var(--psh-gap-sm);
    margin-bottom: var(--psh-gap);
}

.psh-filter-item {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.psh-filter-item .psh-select,
.psh-filter-item .psh-input {
    width: auto;
}

.psh-daterange-form {
    align-items: center;
    display: flex;
    gap: var(--psh-gap-sm);
    margin-left: auto;
}

.psh-input-date {
    width: auto;
}

.psh-chip-active {
    background: var(--psh-nav-accent);
    border-color: var(--psh-nav-accent);
    color: #1c2430;
    font-weight: 600;
}

/* ---------- Modals ---------- */

.psh-modal-overlay {
    align-items: center;
    background: rgb(10 14 20 / 0.55);
    display: flex;
    inset: 0;
    justify-content: center;
    position: fixed;
    z-index: 90;
}

.psh-modal-overlay[hidden] {
    display: none;
}

.psh-modal {
    background: var(--psh-surface-raised);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius);
    box-shadow: var(--psh-shadow);
    max-width: 26rem;
    padding: var(--psh-gap-lg);
    width: calc(100% - 2rem);
}

.psh-modal h2 {
    font-size: 1.15rem;
    margin: 0 0 var(--psh-gap-sm) 0;
}

/* Header bar + x + footer band, like the ng-bootstrap modal chrome. */
.psh-modal-header {
    align-items: center;
    border-bottom: 1px solid var(--psh-border);
    display: flex;
    justify-content: space-between;
    margin: calc(var(--psh-gap-lg) * -1) calc(var(--psh-gap-lg) * -1) var(--psh-gap);
    padding: var(--psh-gap-sm) var(--psh-gap-lg);
}

.psh-modal-header h2 {
    margin: 0;
}

/* Amber warning strip for confirm dialogs (Angular alert-modal). */
.psh-modal-header-warn {
    background: #ffc107;
    border-top-left-radius: var(--psh-radius);
    border-top-right-radius: var(--psh-radius);
    color: #1c2430;
}

.psh-modal-header-warn h2 {
    color: #1c2430;
}

.psh-modal-x {
    background: transparent;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 1.3rem;
    line-height: 1;
    padding: 0 0.25rem;
}

.psh-modal-footer {
    border-top: 1px solid var(--psh-border);
    display: flex;
    gap: var(--psh-gap-sm);
    justify-content: flex-end;
    margin: var(--psh-gap) calc(var(--psh-gap-lg) * -1) calc(var(--psh-gap-lg) * -1);
    padding: var(--psh-gap-sm) var(--psh-gap-lg);
}

.psh-btn-outline-danger {
    background: transparent;
    border-color: var(--psh-danger);
    color: var(--psh-danger);
}

.psh-btn-outline-danger:hover {
    background: var(--psh-danger-bg);
}

.psh-btn-lg {
    font-size: 1.05rem;
    padding: 0.65rem 1.4rem;
}

.psh-modal-footer-center {
    justify-content: center;
}

/* Green checks in the permission matrix (Angular faCheck). */
.psh-perm-check {
    color: var(--psh-success);
    font-weight: 700;
    text-align: center;
}

.psh-text-center {
    text-align: center;
}

.psh-modal-wide {
    max-width: 46rem;
}

/* Tall modal whose body scrolls while the header bar and footer stay put
   (e.g. the markdown help on the wiki editor). */
.psh-modal-scroll {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 2rem);
}

.psh-modal-scroll > .psh-modal-header,
.psh-modal-scroll > .psh-modal-footer {
    flex: none;
}

.psh-modal-scroll > .psh-prose {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 0.5rem;
}

.psh-modal pre {
    background: var(--psh-bg);
    border: 1px solid var(--psh-border);
    border-radius: var(--psh-radius-sm);
    font-family: var(--psh-font-mono);
    font-size: var(--psh-text-size-sm);
    margin: 0 0 var(--psh-gap) 0;
    max-height: 60vh;
    overflow: auto;
    padding: var(--psh-gap-sm);
    white-space: pre-wrap;
    word-break: break-word;
}

/* ---------- Toasts ---------- */

/* Top-center, like the Angular ngx-toastr placement. */
.psh-toast-host {
    display: flex;
    flex-direction: column;
    gap: var(--psh-gap-sm);
    left: 50%;
    max-width: 24rem;
    position: fixed;
    top: var(--psh-gap-sm);
    transform: translateX(-50%);
    width: 24rem;
    z-index: 100;
}

/* Solid saturated fills with a bold title line, click to dismiss. */
.psh-toast {
    background: var(--psh-info);
    border: none;
    border-radius: var(--psh-radius-sm);
    box-shadow: var(--psh-shadow);
    color: #ffffff;
    cursor: pointer;
    padding: 0.65rem 0.85rem;
}

.psh-toast-title {
    display: block;
    margin-bottom: 0.15rem;
}

.psh-toast-success {
    background: var(--psh-success);
}

.psh-toast-error {
    background: var(--psh-danger);
}
