/* ---------------------------------------------------------------------------
   researchx.css — the only project-specific stylesheet.

   All.css, custom.css and admin.css are the shared design system (tokens, dark
   navigation rail, dense tables, pills, modals). This file holds the few things
   that are specific to the ResearchX catalogue and have no equivalent there:
   the record-state rail, the publish-state bar on the dashboard, the taxonomy
   indent and the AJAX loading placeholders.

   Loaded last, so it wins over the shared layer.
--------------------------------------------------------------------------- */

/* =========================================================================
   RECORD STATE
   The shared layer reserves its colour ramp for severity; here the same idea
   is applied to catalogue state — published / draft / archived / inactive.
   ========================================================================= */
tr[data-status] > td:first-child { position: relative; }
tr[data-status] > td:first-child::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
}

tr[data-status="published"] > td:first-child::before,
tr[data-status="active"]    > td:first-child::before { background: var(--brand); }
tr[data-status="draft"]     > td:first-child::before { background: var(--fill-high); }
tr[data-status="archived"]  > td:first-child::before { background: var(--fill-crit); }
tr[data-status="inactive"]  > td:first-child::before { background: var(--fill-low); }

/* Publish-state bar in the dashboard hero. Uses the shared .sev-stack shape,
   with the accent standing in for "published". */
.sev-stack .s-ok { background: var(--brand); }
.sev-legend i.k-ok   { background: var(--brand); }
.sev-legend i.k-warn { background: var(--fill-high); }
.sev-legend i.k-crit { background: var(--fill-crit); }

/* =========================================================================
   TAXONOMY
   Categories arrive in tree order; the indent is what shows the depth.
   ========================================================================= */
.tree-branch {
    font-family: var(--mono);
    color: var(--fg-dim);
    margin-right: 4px;
    user-select: none;
}

/* =========================================================================
   AJAX PLACEHOLDERS
   A listing is fetched after the shell paints, so the container needs
   something of the right height in the meantime.
   ========================================================================= */
.table-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 46px 20px;
    font-size: 12.5px;
    color: var(--fg-dim);
}

.spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    flex: none;
    border: 2px solid var(--surface-3);
    border-right-color: var(--brand);
    border-radius: 50%;
    animation: spin .6s linear infinite;
}

.skeleton {
    display: block;
    border-radius: var(--r-sm);
    background: linear-gradient(90deg, #e8edf1 25%, #f3f6f8 37%, #e8edf1 63%);
    background-size: 400% 100%;
    animation: rx-shimmer 1.3s ease infinite;
}

.skeleton--value { width: 62px; height: 22px; }

@keyframes rx-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* =========================================================================
   FORMS
   Field-level validation messages, painted by RX.showErrors from Laravel's
   422 body. Bootstrap draws the red control; this is the message under it.
   ========================================================================= */
.invalid-feedback {
    display: block;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--crit);
    margin-top: 3px;
}

.form-control.is-invalid, .form-select.is-invalid {
    border-color: var(--crit-line);
    background-color: #fffcfc;
}

.form-control.is-invalid:focus, .form-select.is-invalid:focus {
    border-color: var(--crit);
    box-shadow: 0 0 0 3px rgba(200, 30, 60, .13);
}

/* =========================================================================
   REPORT EDITOR
   The one screen that stays a full page: repeatable blocks for forecasts,
   sections, segmentation, regions, companies and FAQs.
   ========================================================================= */
.repeat-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line-soft);
}

.repeat-row:last-child { border-bottom: 0; }
.repeat-row .form-group { flex: 1 1 150px; margin-bottom: 0; }

.repeat-block {
    padding: 13px;
    margin-bottom: 10px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
}

.repeat-block:last-child { margin-bottom: 0; }
.repeat-block .form-group:last-of-type { margin-bottom: 9px; }

/* A repeater with nothing in it explains itself rather than showing a gap. */
.repeat-empty {
    padding: 20px;
    margin: 0;
    text-align: center;
    font-size: 12.5px;
    color: var(--fg-dim);
    background: var(--surface-2);
    border: 1px dashed var(--line);
    border-radius: var(--r-sm);
}

[data-repeat]:has([data-repeat-row]) + .repeat-empty { display: none; }

/* The editor is long, so its save bar follows the operator down the page. */
.form-actions {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    padding: 11px 14px;
    margin-top: 14px;
    background: rgba(255, 255, 255, .92);
    backdrop-filter: blur(8px);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
}

.form-actions .form-actions-note { margin-right: auto; font-size: 11.5px; color: var(--fg-dim); }

/* =========================================================================
   MISC
   ========================================================================= */
/* Counts read as data: monospace and column-aligned. */
td.num-cell { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
td.num-cell.zero { color: var(--fg-dim); }

/* The dashboard's "all reports" style link in a panel header. */
.card-header .head-link { margin-left: auto; font-size: 11.5px; }

/* A dependent select hides the options that belong to another site, rather
   than only disabling them — a long greyed-out list is harder to read than a
   short live one. */
.u-hidden { display: none !important; }

/* The ranked list rows are links on the dashboard. The grid has to be restated
   because a.drill in the shared layer sets display:block, which would otherwise
   stack the label and the count. */
a.rank-row {
    display: grid;
    grid-template-columns: 1fr 78px;
    gap: 12px;
    align-items: center;
    color: inherit;
    text-decoration: none;
}

a.rank-row:hover { color: inherit; }
a.rank-row:hover .rank-label span:last-child { text-decoration: underline; text-underline-offset: 2px; }

/* The shared layer colours these bars by severity; here the one accent means
   "reports in this category". */
.rank-bar i { background: var(--brand); }

/* Long-form copy is edited in the UI face: the shared layer sets monospace on
   every textarea, which suits a regex but not a report's prose. Identifiers
   opt back in with .text-mono. */
textarea.form-control { font-family: var(--ui); font-size: 12.5px; }
textarea.form-control.text-mono { font-family: var(--mono); font-size: 12px; }

/* =========================================================================
   API DOCS
   A copyable request line: the key reveal dialog and every endpoint's
   example share this one block rather than each rolling its own <pre>.
   ========================================================================= */
.code-block {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 9px 12px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    overflow-x: auto;
}

.code-block code {
    flex: 1 1 auto;
    color: var(--fg);
    background: transparent;
    border: 0;
    padding: 0;
    white-space: pre;
}

.code-block .copy-btn { flex: 0 0 auto; }

#revealedKeyBlock code { color: #0b6b4c; font-weight: 600; }

/* =========================================================================
   REPORT PREVIEW MODAL
   Large enough to show the frontend's own desktop layout rather than a
   cramped admin-sized rectangle. The shared modal styles size a dialog for a
   form; this one is sized for a full page of content instead.
   ========================================================================= */
.preview-modal .modal-dialog {
    width: 95vw;
    max-width: 1400px;
    height: 95vh;
    margin: 2.5vh auto;
}

.preview-modal .modal-content { height: 100%; }

.preview-modal .modal-body {
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fff;
}

.preview-modal-loading,
.preview-modal-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 96px 20px;
    color: var(--fg-muted);
    text-align: center;
}

.preview-modal-error { color: var(--fill-crit); }
.preview-modal-error i { font-size: 28px; }
