/* Global search dialog and shortcut tiles, keyboard shortcut hints, API documentation page.
   Split out of stomn_theme.css (original lines 6092-6556) — 2026-08-18,
   CSS @layer restructuring step 2 (Basecamp "Fra Fizzy-gjennomgang:
   CSS-arkitektur"). Numeric filename prefix controls load order (see
   app/helpers/application_helper.rb#stomn_theme_stylesheet_link_tag) —
   files are concatenated in this exact original order, so no cascade
   tie-break changes. */
@layer overrides {
/* Global search dialog (workspaces/_page_header.html.erb, search_controller.js,
   keyboard_shortcut_controller.js — Shift+J or the header search icon).
   Positioned like .app-confirm-dialog, but tall/anchored higher since it
   holds a growing results list rather than a couple of sentences. */
.global-search__dialog {
    position: fixed;
    top: 15%;
    left: 50%;
    /* Torleiv, 2026-08-15 ("Midtstill shift+j-meny over hovedseksjon"):
       left: 50% centers on the FULL viewport — same bug as
       .header-brand/.header-breadcrumb had (see their own comments), just
       here via a native <dialog>'s own fixed positioning instead of flex
       centering. The real content column shifts left by half the open
       sidebar's width, so this needs the same correction to land back
       over it instead of over the (now partly sidebar-covered) middle of
       the whole screen. */
    transform: translateX(calc(-50% - var(--sidebar-width, 0px) / 2));
    margin: 0;
    width: 32rem;
    max-width: calc(100vw - var(--space-6));
    max-height: 70vh;
    /* No title sits above the input here (unlike .document-nav-gear__dialog),
       so the top inset alone has to clear .dialog-close's own footprint
       (space-3 offset + its 2rem height) or the X sits on top of the input. */
    padding: calc(var(--space-3) + 2rem) var(--space-4) var(--space-4);
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg);
    box-shadow: var(--dialog-shadow);
    overflow: hidden;
}

/* [open] guard is load-bearing: a bare `display:` on the dialog itself
   would override the UA stylesheet's `dialog:not([open]) { display:none }`,
   making it visible at rest instead of only after showModal(). */
.global-search__dialog[open] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.global-search__dialog::backdrop {
    background: var(--dialog-backdrop);
}

.global-search__input {
    width: 100%;
    padding: var(--space-3);
    border: var(--card-border);
    border-radius: var(--radius-md);
    font-size: var(--text-size-lg);
}

.global-search__input:focus {
    outline: none;
    border-color: var(--signal-color);
}

.global-search__results {
    display: block;
    overflow-y: auto;
}

.global-search__empty {
    padding: var(--space-4) var(--space-2);
    color: rgba(28, 25, 20, 0.5);
    font-size: var(--text-size-base);
    text-align: center;
}

/* Torleiv, 2026-08-20 (#10224407226): the query-syntax cheat sheet shown
   under the empty-state message — quiet/small like .global-search__empty
   itself (a reference, not something worth drawing the eye to), listed
   rather than run together since six short rules read faster as a list
   than as a paragraph. */
.global-search__syntax-hint {
    list-style: none;
    margin: 0 auto;
    padding: 0 var(--space-4) var(--space-4);
    max-width: 320px;
    color: rgba(28, 25, 20, 0.5);
    font-size: var(--text-size-sm);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.global-search__syntax-hint code {
    font-size: 0.9em;
}

.global-search__result-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Static quick links (Mine dokumenter/Bokmerker/Personer/Mine oppgaver),
   shown above the dynamic results as four equal square tiles in a row
   (Torleiv, 2026-08-10, with a screenshot — replaces an earlier stacked-
   sections layout, see the view comment) — separated with a rule so the
   tiles and the search results don't blur together. */
.global-search__shortcuts {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-2);
    padding-bottom: var(--space-2);
    border-bottom: var(--card-border);
}

/* Square via aspect-ratio rather than a fixed height, so the row still
   reflows sanely if the dialog's own width ever changes (e.g. a narrower
   viewport) — same card language as .workspace-shortcut (radius, bg,
   hover lift), just centered icon-over-label instead of a title+text
   block, and small enough that four fit one row at this dialog width. */
.global-search__shortcut-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    aspect-ratio: 1;
    padding: var(--space-2);
    border-radius: var(--card-radius);
    background: var(--card-bg);
    color: inherit;
    text-decoration: none;
    text-align: center;
    transition: transform 0.15s ease;
    position: relative;
}

.global-search__shortcut-tile:hover {
    transform: translateY(-1px);
}

.global-search__shortcut-tile-label {
    font-size: var(--text-size-xs);
    line-height: 1.2;
}

/* Positioning context for the hint badge below — lets it center directly
   above THIS icon specifically regardless of the tile's own padding/label
   height, rather than the tile's corner (Torleiv, 2026-08-11, screenshot:
   the old corner position read as an unrelated stray mark next to tile 1,
   not obviously "this icon's shortcut"). */
.global-search__shortcut-tile-icon {
    position: relative;
    display: inline-flex;
}

/* Shift+digit hint (Shift+1/2/3/4 — see keyboard_shortcut_controller.js's
   openShortcutTile/showShortcutHints), centered directly above its own
   icon. Two separate <kbd> keycaps rather than a single bare digit —
   Torleiv, 2026-08-11: needed to read unambiguously as ONE key combo
   (Shift held, then the digit), not just "press 2". Only ever visible
   while Shift is actually held (body.shift-shortcuts-active) — permanent
   keycaps on every tile would just be visual noise for the far more
   common case of clicking instead of using the keyboard.
   No transition here on purpose — tested one (opacity/transform easing)
   and found it gets stuck mid-animation specifically when the ancestor
   class change happens while this dialog is open via showModal(): the
   badge fades IN correctly but never fades back OUT, staying visible
   after Shift is released, since <dialog>'s top-layer promotion doesn't
   reliably settle a transition retriggered by an ancestor selector match
   changing. A plain instant toggle has no such failure mode. */
.global-search__shortcut-tile-hint {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: 2px;
    display: flex;
    gap: 2px;
    opacity: 0;
    pointer-events: none;
}

body.shift-shortcuts-active .global-search__shortcut-tile-hint {
    opacity: 1;
}

.global-search__shortcut-tile-hint kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.25rem;
    border-radius: var(--radius-sm);
    background: #fff;
    border: 1px solid rgba(28, 25, 20, 0.2);
    box-shadow: 0 1px 0 rgba(28, 25, 20, 0.15);
    color: rgba(28, 25, 20, 0.75);
    font-size: 9px;
    font-weight: 700;
    font-family: inherit;
    line-height: 1;
}

/* Shift+key hint badges next to header shortcut triggers (Home, search,
   avatar/user menu, Sidefelt) — Torleiv, 2026-08-16, referencing
   Basecamp's own persistent per-shortcut badges, first built as
   always-visible; then, same day, reversed: "Snarveiene må bare vises
   når en holder inn shift-knappen" — so these now use the SAME
   hold-Shift-to-reveal mechanism as the digit-tile hints above
   (body.shift-shortcuts-active), not a permanently-visible badge.
   Reuses the exact same kbd keycap look as
   .global-search__shortcut-tile-hint for one consistent "what a
   keyboard shortcut badge looks like". */
.header-shortcut-hint {
    display: inline-flex;
    gap: 2px;
    margin-left: var(--space-1);
    opacity: 0;
    pointer-events: none;
}

body.shift-shortcuts-active .header-shortcut-hint {
    opacity: 1;
}

/* Torleiv, Basecamp #10217877358 ("Snarveiene skal vises ... også i
   menyen"): the avatar menu's own items are a full-width flex row
   (icon + label), so the hint needs to be pushed to the row's own right
   edge instead of just trailing the label text with a small gap — same
   right-aligned-badge convention as sand_ui's own key-value rows,
   rather than the compact "sits right after the label" look the header
   nav's own bare Hjem/Søk triggers use (those rows are already sized to
   their content, nothing to push against). */
.header-user-menu__item .header-shortcut-hint {
    margin-left: auto;
}

.header-shortcut-hint kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.25rem;
    border-radius: var(--radius-sm);
    background: #fff;
    border: 1px solid rgba(28, 25, 20, 0.2);
    box-shadow: 0 1px 0 rgba(28, 25, 20, 0.15);
    color: rgba(28, 25, 20, 0.75);
    font-size: 9px;
    font-weight: 700;
    font-family: inherit;
    line-height: 1;
}

/* Icon-only triggers (search, avatar) have no visible label to sit the
   badge inline after — a small corner overlay instead, same idea as
   .global-search__shortcut-tile-icon's own badge placement. Needs
   position: relative on the trigger/wrapper itself (added inline where
   used) so this positions against that element, not the header at large. */
.header-shortcut-hint--corner {
    position: absolute;
    bottom: -4px;
    right: -4px;
    margin-left: 0;
}

.global-search,
.header-user-menu__trigger {
    position: relative;
}

.global-search__result {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md);
    color: inherit;
    text-decoration: none;
}

.global-search__result:hover,
.global-search__result--active {
    background: rgba(28, 25, 20, 0.06);
}

/* Wraps title-row + the optional context line (module/excerpt) so they
   stack, while title-row itself stays a row (title/subtitle side by
   side) — min-width: 0 is load-bearing, without it a flex child won't
   shrink below its content's natural width, so the title/context
   ellipsis truncation below never actually kicks in. */
.global-search__result-text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
}

.global-search__result-title-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.global-search__result-title {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.global-search__result-subtitle {
    flex-shrink: 0;
    color: rgba(28, 25, 20, 0.45);
    font-size: var(--text-size-xs);
}

/* Where a Document/Folder lives, plus a content-match excerpt when that's
   why it matched (see SearchController#node_location/#excerpt_around) —
   without this a content-only hit gave no visible reason it was in the
   list at all. */
.global-search__result-context {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(28, 25, 20, 0.4);
    font-size: var(--text-size-xs);
}

/* API documentation page (app/views/api_docs/show.html.erb) */
.api-docs__code {
    overflow-x: auto;
    padding: var(--space-3);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
    font-family: ui-monospace, monospace;
    font-size: var(--text-size-sm);
    white-space: pre-wrap;
    word-break: break-all;
}

.api-docs__table-wrap {
    overflow-x: auto;
    padding: 0;
}

.api-docs__table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-size-base);
}

.api-docs__table th,
.api-docs__table td {
    padding: var(--space-2) var(--space-3);
    text-align: left;
    border-bottom: 1px solid rgba(28, 25, 20, 0.08);
    vertical-align: top;
}

.api-docs__table th {
    color: var(--text-500, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.api-docs__table tr:last-child td {
    border-bottom: none;
}

.api-docs__table code {
    font-family: ui-monospace, monospace;
    font-size: var(--text-size-sm);
}

/* The shared .page-title-header__back sits bottom-left, absolutely
   positioned within the header's own generous padding — fine on every
   other page that uses it, but on api_docs its left edge lines up with
   the TOC sidebar starting right below, reading as if it belongs to the
   sidebar rather than the page (Torleiv, 2026-08-12). Flow it above the
   title instead, just on this page — a plain, page-scoped override, not
   a change to the shared rule every other back-link page relies on. */
.api-docs-page .page-title-header__back {
    position: static;
    text-align: left;
    margin-bottom: var(--space-4);
}

/* API docs page layout — a small, self-contained TOC + prose column.
   Deliberately its own sticky (position:sticky, no JS, no shared
   --page-header-height var) rather than reusing .document-layout/
   .document-focus, which drive the still-unresolved sticky-header bug —
   this page has no reason to share that machinery or its risk. */
.api-docs-layout {
    display: flex;
    align-items: flex-start;
    gap: var(--space-6);
}

.api-docs-toc {
    position: sticky;
    /* Same real-measured-height variable .document-page-header uses (set
       by sticky_offset_controller.js) — a guessed small offset here let
       the sidebar's own sticky position slide up underneath the app's
       actual, taller sticky top bar once scrolled (Torleiv, 2026-08-12). */
    top: calc(var(--page-header-height, 60px) + var(--space-4));
    flex: none;
    width: 220px;
}

.api-docs-toc__label {
    margin: 0 0 var(--space-2);
    color: var(--text-500, #888);
    font-size: var(--text-size-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.api-docs-toc__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0 0 var(--space-4);
    padding: 0;
    list-style: none;
}

.api-docs-toc__list a {
    display: block;
    padding: var(--space-1) 0;
    color: var(--text-500, #888);
    font-size: var(--text-size-sm);
    line-height: 1.4;
    text-decoration: none;
}

.api-docs-toc__list a:hover {
    color: var(--text-900, #111);
}

.api-docs-toc__copy {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
    color: var(--text-700, #444);
    font-size: var(--text-size-sm);
    cursor: pointer;
}

.api-docs-toc__copy:hover {
    color: var(--text-900, #111);
}

.api-docs-content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.api-docs-content p {
    margin: 0 0 var(--space-3);
    line-height: 1.6;
    max-width: 68ch;
}

.api-docs-content p:last-child {
    margin-bottom: 0;
}

@media (max-width: 900px) {
    .api-docs-layout {
        flex-direction: column;
    }

    .api-docs-toc {
        position: static;
        width: auto;
    }
}


} /* @layer overrides */
