/* ============================================================================
   TrafficPortal3 shared components
   ----------------------------------------------------------------------------
   The pieces every converted page needs: page header, buttons, status pills,
   message banners, modal dialog, spinner and empty state.

   The rule this file exists to enforce: if two converted pages would both use
   it, it belongs here, not in a page's <style> block. A page's own block should
   be left holding only what is genuinely unique to that screen.

   Scope: tp-* names, used only by pages converted from TP2 iframes. Nothing
   targets a bare element or a legacy class, so no existing page is affected.
   All values come from tokens.css -- nothing here hard-codes a colour.

   Pairs with filters.css (filter panel) and results-table.css (results grid).
   ============================================================================ */

/* ---- Page shell ---- */

.tp-page {
    font-family: var(--tp-font-family);
    color: var(--tp-ink);
    padding: 22px 2% 56px;
}

.tp-page-header {
    margin: 2px 2px 20px;
}

    .tp-page-header h1 {
        margin: 0;
        font-size: 24px;
        font-weight: 650;
        /* Tightened very slightly: at this weight and size the default tracking looks loose. */
        letter-spacing: -0.015em;
        color: var(--tp-brand);
    }

    .tp-page-header p {
        margin: 5px 0 0;
        font-size: 13.5px;
        /* !important for the same reason as .tp-link: Shared/MainLayout.razor has an unscoped
           `p { color: #666666 !important }` that would otherwise paint this in the legacy grey. */
        color: var(--tp-ink-soft) !important;
    }

/* ---- Buttons ---- */

.tp-btn {
    height: 34px;
    padding: 0 14px;
    font-size: 13px;
    font-weight: 600;
    /* Explicit, not `inherit`: a button wrapped in an SfTooltip would otherwise inherit Roboto from
       Syncfusion `.e-control`, so wrapped and unwrapped buttons in the same row render in different
       typefaces and look like different weights. */
    font-family: var(--tp-font-family);
    border-radius: var(--tp-radius);
    border: 1px solid var(--tp-line);
    background: var(--tp-card);
    color: var(--tp-ink);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* A hyphenated label would otherwise break at the hyphen in a narrow table cell. */
    white-space: nowrap;
    /* Anchors a count badge positioned in the corner. */
    position: relative;
}

    .tp-btn:hover:not(:disabled) {
        background: var(--tp-line-soft);
    }

    .tp-btn:disabled {
        opacity: .5;
        cursor: not-allowed;
    }

    .tp-btn:focus-visible {
        outline: 2px solid var(--tp-brand);
        outline-offset: 2px;
    }

.tp-btn-primary {
    background: var(--tp-brand);
    border-color: var(--tp-brand);
    color: var(--tp-on-brand);
}

    .tp-btn-primary:hover:not(:disabled) {
        background: var(--tp-brand-dark);
    }

.tp-btn-danger {
    border-color: var(--tp-danger);
    color: var(--tp-danger);
}

    .tp-btn-danger:hover:not(:disabled) {
        background: var(--tp-danger-tint);
    }

/* A button that sits inside a table row, where the full 34px is too tall. */
.tp-btn-sm {
    height: 26px;
    padding: 0 8px;
    font-size: 12px;
}

/* Bootstrap Icons set `vertical-align: -.125em` on the ::before glyph so it sits nicely next to text
   on a baseline. Inside a flex button there is no baseline to sit on, and align-items:center cannot
   undo it, so the glyph ends up riding high. Making the glyph a block with line-height 1 drops the
   offset and lets the flex centering do the work. Applies to any tp- button with an icon. */
.tp-btn .bi,
.tp-filter-apply .bi,
.tp-filter-collapse-btn .bi {
    display: flex;
    align-items: center;
    line-height: 1;
}

    .tp-btn .bi::before,
    .tp-filter-apply .bi::before,
    .tp-filter-collapse-btn .bi::before {
        display: block;
        line-height: 1;
        vertical-align: baseline;
    }

/* The icon above is a line-height:1 box, but the label keeps the inherited 1.5, so the two are
   centred on boxes of different heights and the text reads as sitting low beside the glyph. Giving
   the label the same line-height puts both on one midline. */
.tp-btn .tp-btn-label {
    line-height: 1;
}

/* ---- Status pills ---- */

.tp-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
}

.tp-pill-ok {
    background: var(--tp-success-tint);
    color: var(--tp-success);
}

.tp-pill-warn {
    background: var(--tp-warn-tint);
    color: var(--tp-warn);
}

.tp-pill-danger {
    background: var(--tp-danger-tint);
    color: var(--tp-danger);
}

/* ---- Message banners ---- */

.tp-msg {
    padding: 10px 14px;
    border-radius: 8px;
    font-size: 13px;
    margin-bottom: 12px;
}

.tp-msg-error {
    background: var(--tp-danger-tint);
    border: 1px solid var(--tp-danger-line);
    color: var(--tp-danger);
}

.tp-msg-warn {
    background: var(--tp-warn-tint);
    border: 1px solid var(--tp-warn-line);
    color: var(--tp-warn);
}

.tp-msg-info {
    background: var(--tp-brand-tint);
    border: 1px solid var(--tp-brand-tint-2);
    color: var(--tp-brand-dark);
}

.tp-msg-success {
    background: var(--tp-success-tint);
    border: 1px solid var(--tp-success-line);
    color: var(--tp-success);
}

/* ---- Modal dialog ---- */

.tp-backdrop {
    position: fixed;
    inset: 0;
    background: var(--tp-overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1200;
    padding: 16px;
}

.tp-modal {
    background: var(--tp-card);
    border-radius: 12px;
    max-width: 560px;
    width: 100%;
    box-shadow: var(--tp-shadow-modal);
    overflow: hidden;
}

.tp-modal-lg {
    max-width: 900px;
}

.tp-modal-head {
    padding: 14px 18px;
    border-bottom: 1px solid var(--tp-line);
    font-size: 16px;
    font-weight: 600;
    color: var(--tp-brand);
}

.tp-modal-body {
    padding: 18px;
    font-size: 13px;
    line-height: 1.55;
    max-height: 60vh;
    overflow: auto;
}

.tp-modal-foot {
    padding: 12px 18px;
    border-top: 1px solid var(--tp-line);
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* A document preview inside a modal. Shared/MainLayout.razor carries an unscoped
   `iframe:not([title^="Ava"]) { height: 86vh !important }` for the TP2 pages, which also catches this
   frame and makes it taller than the modal body, so the body scrolls the frame and the frame scrolls
   the PDF. Two classes plus the element out-rank that selector; !important is needed to tie with it. */
.tp-modal-body iframe.tp-pdf-frame {
    display: block;
    width: 100%;
    height: 70vh !important;
    border: 0;
}

/* ---- Spinner & empty state ---- */

.tp-spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 2px solid var(--tp-brand-tint);
    border-top-color: var(--tp-brand);
    border-radius: 50%;
    animation: tp-spin .7s linear infinite;
}

@keyframes tp-spin {
    to { transform: rotate(360deg); }
}

.tp-empty {
    padding: 34px 16px;
    text-align: center;
    color: var(--tp-ink-soft);
    font-size: 13px;
}

/* ---- Generic card, for anything that is not the results table ---- */

.tp-card {
    background: var(--tp-card);
    border: 1px solid var(--tp-line);
    border-radius: var(--tp-radius-card);
    box-shadow: var(--tp-shadow);
    overflow: hidden;
}

@media (max-width: 768px) {
    .tp-page {
        padding: 16px 12px 40px;
    }
}

/* Inline text link inside a table row or panel.

   The !important is not decoration. Shared/MainLayout.razor carries an unscoped `a { color: white
   !important; }` in a <style> block that renders on every page, so every anchor in the app is white
   unless a rule outranks it -- and !important in a stylesheet beats even an inline style attribute.
   Until that rule is fixed (it would force a retest of every page), link colours here must fight it. */
.tp-link {
    color: var(--tp-brand) !important;
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

    .tp-link:hover {
        color: var(--tp-brand-dark) !important;
        text-decoration: underline;
    }

    .tp-link:focus-visible {
        outline: 2px solid var(--tp-brand);
        outline-offset: 2px;
        border-radius: 3px;
    }

/* A BUTTON that should read as an inline link, for a click that runs page code rather than going
   somewhere -- e.g. an invoice number that opens the preview. Used with .tp-link, which supplies the
   colour; this only removes the button chrome. The !important on the colour is .tp-link's own. */
.tp-link-plain {
    background: none;
    border: 0;
    padding: 0;
    font-family: inherit;
    cursor: pointer;
}

    .tp-link-plain:disabled {
        cursor: default;
        opacity: .6;
    }

/* A link to something voided or otherwise bad, e.g. TP2's red "V-" invoice numbers. */
.tp-link.tp-link-danger {
    color: var(--tp-danger) !important;
}

/* An anchor that should look like a row button. Used with `tp-btn tp-btn-sm`, which supply the box;
   this only beats MainLayout's global `a { color: white !important }` (see the note on .tp-link). */
.tp-link-btn {
    color: var(--tp-ink) !important;
    text-decoration: none;
}

    .tp-link-btn:hover {
        color: var(--tp-ink) !important;
    }


/* Between the card breakpoint and 1200px the buttons drop their labels and show the icon alone, so a
   row of them stops pushing the table wider than the window. Below 1025px the table becomes stacked
   cards, where there is room again, so the labels come back. The `title` carries the wording either
   way, and any count (e.g. "(2)") stays visible -- it is the part that changes. */
@media (min-width: 769px) and (max-width: 1200px) {
    .tp-btn-label {
        display: none;
    }

    .tp-btn {
        min-width: 32px;
        padding: 0 8px;
        justify-content: center;
    }
}

/* A label with a long and a short form, e.g. "Voided" / "V". The short one takes over only while the
   results are still a TABLE and space is tight -- in card mode each field has its own line, so the
   full word comes back. Only one is ever visible, and the element carrying them should have a `title`
   so the meaning is still reachable. */
.tp-label-short {
    display: none;
}

@media (min-width: 769px) and (max-width: 950px) {
    .tp-label-long {
        display: none;
    }

    .tp-label-short {
        display: inline;
        font-weight: 700;
    }

    /* A single letter does not need the full pill padding around it. */
    .tp-pill {
        padding: 2px 6px;
    }
}

/* Lead line at the top of a dialog body. */
.tp-modal-lead {
    margin: 0 0 14px;
    font-size: 13.5px;
    color: var(--tp-ink);
}

/* A choice in a dialog: the whole row is the target, not just the radio. Bigger hit area, and the
   selected one is obvious without having to look at a 13px dot -- which matters for this audience. */
.tp-choice {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 12px 14px;
    margin-bottom: 10px;
    border: 1px solid var(--tp-line);
    border-radius: 10px;
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

    .tp-choice:last-child {
        margin-bottom: 0;
    }

    .tp-choice:hover {
        border-color: var(--tp-brand-tint-2);
        background: var(--tp-brand-tint);
    }

.tp-choice-on {
    border-color: var(--tp-brand);
    background: var(--tp-brand-tint);
}

.tp-choice input[type="radio"] {
    margin-top: 2px;
    /* The native control is tiny; the row does the work but the dot still has to be findable. */
    width: 16px;
    height: 16px;
    accent-color: var(--tp-brand);
    flex: 0 0 auto;
}

.tp-choice-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.tp-choice-title {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--tp-ink);
}

.tp-choice-hint {
    font-size: 12.5px;
    color: var(--tp-ink-soft);
    line-height: 1.45;
}
