/* ==========================================================================
   FlexOps Ship Manager - Site Styles
   Core application styles and Radzen overrides
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Portal Accent Bar — visual differentiation across FlexOps portals
   Each portal claims a distinct hue so the 3px top bar wayfinds the user:
     Ship Manager   = amber (operations / "in motion")
     ApiPortal      = blue   (#1570EF)
     IdentityPortal = green  (#067647)
     SettingsHub    = teal   (#0E9384)
   Brand purple (#6C3BAA) is reserved for brand surfaces, not the accent bar.
   -------------------------------------------------------------------------- */
:root {
    --portal-accent: #DC6803; /* warning-600 amber — Ship Manager */
}

body::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--portal-accent);
    z-index: 10000;
    pointer-events: none;
}

/* --------------------------------------------------------------------------
   1. Blazor Error UI
   -------------------------------------------------------------------------- */
#blazor-error-ui {
    background: var(--flexops-error-50);
    bottom: 0;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
    display: none;
    left: 0;
    padding: 1rem 1.5rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
    border-top: 3px solid var(--flexops-error-600);
    font-family: var(--flexops-font-body, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 1rem;
    top: 50%;
    transform: translateY(-50%);
    padding: 0.5rem;
    border-radius: 4px;
    transition: background-color 150ms ease;
}

#blazor-error-ui .dismiss:hover {
    background-color: rgba(0, 0, 0, 0.05);
}

/* --------------------------------------------------------------------------
   3. Typography & Links
   (body{} background/font is set in theme.css §1)
   -------------------------------------------------------------------------- */
.rz-body {
    --rz-body-padding: 0;
}

a {
    color: var(--rz-link-color);
    text-decoration: none;
    transition: color 150ms ease;
}

a:hover,
a:focus {
    color: var(--rz-link-hover-color);
}

/* Card-as-link: when an action card is rendered as an <a> for native
   link semantics (free middle-click / Ctrl-click, screen-reader link
   announcement), neutralize the global anchor color and hover so the
   card chrome carries the visual treatment. */
a.rz-card,
a.rz-card:hover,
a.rz-card:focus {
    color: inherit;
    display: block;
}

/* --------------------------------------------------------------------------
   4. Error Boundaries
   -------------------------------------------------------------------------- */
.blazor-error-boundary {
    background: linear-gradient(135deg, var(--flexops-error-600) 0%, var(--flexops-error-700) 100%);
    padding: 1rem 1rem 1rem 3.5rem;
    color: white;
    border-radius: 8px;
    margin: 1rem 0;
    position: relative;
}

.blazor-error-boundary::before {
    content: "?";
    position: absolute;
    left: 1rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.5rem;
}

.blazor-error-boundary::after {
    content: "An error has occurred. Please refresh the page or contact support if the problem persists.";
}

/* --------------------------------------------------------------------------
   5. Loading Progress
   -------------------------------------------------------------------------- */
.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}

.loading-progress circle {
    fill: none;
    stroke: var(--flexops-gray-200);
    stroke-width: 0.5rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--flexops-brand-600);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.15s ease-in-out;
}

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: var(--font-weight-semibold);
    color: var(--flexops-gray-600);
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Loading");
}

/* USPS Hold For Pickup (HFPU) flow on ShipItOrderDetails — selected-facility
   summary card. Uses --portal-accent so the highlight matches the Ship Manager
   portal stripe (per the per-portal-accent convention). */
.hfpu-card .hfpu-selected-facility {
    background-color: var(--flexops-bg-tertiary);
    border-left: 3px solid var(--portal-accent, var(--rz-primary));
}

/* ShipItOrderDetails — Rates panel sizing.

   HISTORY: #249 made this column stretch to the taller left column and let the
   rate list absorb the slack, so Hold For Pickup and Buy Label landed on the
   card's bottom edge. That bet on the list being long enough to fill the space.
   It is not: three rates left ~330px of white under the last one, and the RATES
   UNAVAILABLE state left ~490px. The stretch did not remove the void, it just
   moved it from above the buttons to below the rates.

   NOW: the panel is sized by its own content in every state. Few rates -> a
   short card with the buttons directly under the list. Many rates -> the list
   hits its max-height and scrolls, which is what it already did. No state has
   a void, and the "is this state short?" special case is gone. */
.rate-panel-column {
    align-self: flex-start;
    display: flex;
    flex-direction: column;
}

.rate-panel-column > .shipping-rates-card {
    display: flex;
    flex-direction: column;
    flex: 0 0 auto;
}

.rate-panel-column > .shipping-rates-card > .shipping-rates-content {
    display: flex;
    flex-direction: column;
    flex: 0 0 auto;
}

.rate-panel-column > .shipping-rates-card > .shipping-rates-content > .rates-body {
    flex: 0 0 auto;
}

/* The scrollable rate list. Was a fixed max-height: 296px, which showed three
   rates and hid the rest behind a scrollbar -- and #249 widened the quote to
   Priority Mail as well, so the list is now far longer than it used to be.
   Viewport-relative means it grows with the window instead of being sized for
   one screen; the floor keeps it usable on a short laptop display. */
.rates-container {
    overflow-y: auto;
    /* A CEILING, not a size. The list is as tall as its rates; past that it
       scrolls. Viewport-relative so a tall monitor shows more rates before
       scrolling, and no fixed floor - a floor is how a two-rate order gets a
       band of white under it. */
    max-height: calc(100vh - 22rem);
}

/* "Order ship method: ..." under the Shipment Date field. Its parent stack is a
   centring flex column, so align-self is what pulls it to the left edge; the
   ancestor chain also carries text-align: right, which is why the alignment has
   to be stated rather than inherited. */
.flexops-rate-order-method {
    align-self: flex-start;
    width: 100%;
    text-align: left;
    margin-bottom: 0.75rem;
    color: var(--rz-text-secondary-color);
}

/* The wrappers between .rates-body and .rates-container. Each keeps the axis it
   already had -- row-direction wrappers pass height down with align-self,
   column-direction ones with flex-grow -- because flipping a direction also
   flips what align-items centres, which would move the list sideways at some
   breakpoints. */
.rates-body .rates-fill-v {
    flex: 1 1 auto;
    min-height: 0;
}

.rates-body .rates-fill-self {
    align-self: stretch;
}

.rates-body .rates-fill-col {
    display: flex;
    flex-direction: column;
}

/* Rates-unavailable card (#315). Replaces three hand-tuned indents -- 20px on the
   icon, 50px on the guidance, 35px on the issues list -- that were each guessed to
   clear the warning icon and so drifted apart the moment it changed size. The icon
   now occupies its own flex track, so a single gap does the work of all three and
   stays correct whatever the icon measures.

   Every line here used to be `font-weight: bold; font-size: 16px`, which left the
   card with no hierarchy at all. Weight and colour carry the heading now; size is
   uniform on purpose. The heading is uppercased HERE rather than typed in capitals
   in the markup, so the copy reads as a sentence in source and the shouting is a
   presentation choice. */
.rates-unavailable-card {
    width: 100%;
    box-shadow: var(--flexops-shadow-md);
}

.rates-unavailable {
    display: flex;
    align-items: flex-start;
    gap: var(--flexops-space-3);
    text-align: left;
}

.rates-unavailable__icon {
    flex: 0 0 auto;
    color: var(--flexops-text-warning-primary);
    line-height: 1;
}

.rates-unavailable__body {
    display: flex;
    flex-direction: column;
    gap: var(--flexops-space-2);
    min-width: 0;
}

.rates-unavailable__title {
    margin: 0;
    font-size: var(--flexops-text-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--flexops-text-warning-primary);
}

.rates-unavailable__guidance {
    margin: 0;
    font-size: var(--flexops-text-sm);
    font-weight: 500;
}

.rates-unavailable__issues {
    margin: 0;
    padding-left: var(--flexops-space-5);
    display: flex;
    flex-direction: column;
    gap: var(--flexops-space-1);
    font-size: var(--flexops-text-sm);
    font-weight: 400;
}

/* Loading placeholder for the rate list (#315). Was a fixed `height: 250px` -- the
   same fixed-height bug as the address cards and the Top Selling Products card: it
   can neither shrink on a short panel nor grow if the spinner changes. min-height
   keeps the reservation, so the panel does not collapse and then jump when rates
   arrive, without capping it. */
.rates-container-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 15.625rem;
}

.rates-container-loading img {
    width: var(--flexops-space-20);
    height: var(--flexops-space-20);
}

/* Print Label only renders once a label has been bought, so it never sits beside Buy
   Label and does not compete with it. The face was a hardcoded #1C64F2; blue-600 is
   the scale's nearest step (#2563EB) and the difference is not perceptible. */
.fx-print-label-button {
    background-color: var(--flexops-blue-600);
    text-align: left;
}

/* Rate/Insurance panel structure (#315). These were 33 `Style=` attributes on
   RadzenRow / RadzenColumn / RadzenLabel, several byte-identical, none reusable and
   none on the token scale. Classes are global rather than a scoped .razor.css
   because Radzen renders its own root elements and the CSS-isolation scope
   attribute is not reliably forwarded through a third-party component. */
.ship-panel-card {
    width: 100%;
    max-width: 31.4375rem;
}

.ship-row {
    display: flex;
    align-items: center;
}

.ship-row--tight {
    margin-bottom: var(--flexops-space-1);
}

.ship-row--spaced {
    margin-bottom: var(--flexops-space-4);
}

/* The label/control pair in Insurance and Shipment Date. Was width: 174px with
   heights of 27/30/33px -- three values for one row rhythm, each tuned to a
   different control. The height is the control's business, not the column's. */
.ship-field-col {
    width: 10.875rem;
}

.ship-card-title {
    width: 100%;
    color: var(--rz-text-color);
    font-weight: var(--flexops-font-weight-semibold);
    margin-bottom: var(--flexops-space-1);
}

.ship-card-note {
    width: 100%;
    color: var(--flexops-text-tertiary);
    font-weight: var(--flexops-font-weight-regular);
}

.ship-field-label {
    width: 100%;
    color: var(--rz-text-color);
    font-weight: var(--flexops-font-weight-medium);
}

.ship-control-full {
    width: 100%;
}

.ship-text-danger {
    color: var(--rz-danger);
}

.ship-text-warning {
    color: var(--rz-warning);
}

.ship-nowrap {
    white-space: nowrap;
}

.ship-panel-heading {
    width: 100%;
    margin-top: var(--flexops-space-1);
    margin-bottom: var(--flexops-space-4);
    font-weight: var(--flexops-font-weight-semibold);
}

.ship-stack-center {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.ship-stack-end {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.ship-col-right {
    text-align: right;
    height: auto;
}

.ship-row--gap-y {
    margin-top: var(--flexops-space-2);
    margin-bottom: var(--flexops-space-2);
}

.ship-row--controls {
    gap: var(--flexops-space-2);
    flex-wrap: nowrap;
    margin-bottom: var(--flexops-space-4);
}

.ship-row--rates {
    margin-top: var(--flexops-space-1);
    margin-bottom: 0;
}

.ship-note-inline {
    width: 100%;
    margin-top: var(--flexops-space-1);
    color: var(--flexops-text-tertiary);
    font-weight: var(--flexops-font-weight-regular);
}

.ship-field-heading {
    width: 100%;
    margin-top: var(--flexops-space-1);
    color: var(--rz-text-secondary-color);
    font-weight: var(--flexops-font-weight-semibold);
}

/* The date picker needs a positioning context for its popup; the 200px is the
   control's own width, not a layout guess. */
.ship-datepicker-wrap {
    position: relative;
    width: 12.5rem;
}

/* Bare icon button: the browser's button chrome is removed rather than restyled,
   so the image is the entire affordance. Focus is left to the shared focus ring. */
.ship-icon-button {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    flex: 0 0 auto;
}

.ship-icon-button img {
    width: var(--flexops-space-6);
    height: var(--flexops-space-6);
}

/* Create Order's action bar.

   Replaces two byte-identical button blocks, above and below a six-section, 72-control form. In
   the middle of that form the operator was near neither copy, and the pair had to be edited in
   lockstep - the argument for duplicating them was reachability, which duplication did not
   actually deliver.

   Sticky keeps one copy always reachable, and gives the created-order receipt somewhere the
   operator is already looking when they press Submit. The portals are desktop-only at a 1280px
   minimum, so this does not have to survive a phone viewport. */
.order-action-bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: var(--flexops-space-2);
    margin-top: var(--flexops-space-4);
    padding: var(--flexops-space-3) var(--flexops-space-4);
    background: var(--flexops-bg-primary);
    border-top: 1px solid var(--flexops-border-secondary);
    border-radius: var(--flexops-radius-xl) var(--flexops-radius-xl) 0 0;
    box-shadow: var(--flexops-shadow-lg);
}

.order-action-bar-buttons {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.5rem;
}
