/*
    THE GUEST APP'S ONLY STYLESHEET.

    WHO IS READING THIS PAGE, because everything below follows from it: a salesperson who has never heard
    of PurchaseIT, who arrived from an email, who has no account and no reason to make one, and who is
    deciding in the first five seconds whether this is worth their afternoon. It has to look like a
    business asked them a serious question - not like an internal tool somebody pointed outwards.

    DELIBERATELY NOT THE PORTALS' SIX THEMES. A guest has no preference to remember and no settings page
    to set one on, so there is one look and it is the confident one.
*/

:root {
    --guest-ink: #101828;
    --guest-body: #475467;
    --guest-muted: #667085;
    --guest-line: #e4e7ec;
    --guest-line-soft: #f2f4f7;
    --guest-surface: #ffffff;
    --guest-canvas: #f8f9fc;

    /* One accent, used for the primary action and nothing else, so it always means "this is the button". */
    --guest-accent: #0b5cd5;
    --guest-accent-dark: #0847a6;

    --guest-hot: #b42318;
    --guest-warm: #b54708;
    --guest-cold: #175cd3;

    --guest-radius: 0.75rem;
    --guest-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 1px 3px rgba(16, 24, 40, 0.06);
}

body {
    color: var(--guest-body);
    background-color: var(--guest-canvas);
    -webkit-font-smoothing: antialiased;
}

/* --- THE MONEY FIELD ---------------------------------------------------------------------------------

    A SLOW DRIFT OF COINS AND BANKNOTES BEHIND THE PAGE (Bradley, 2026-08-23: the flat grey "looks very
    bland"). It is decoration, and the constraints on it all come from WHO is reading: somebody on a phone
    in a car park, on their own data, typing prices they are commercially responsible for.

    SO IT IS TWO REPEATING SVG TILES AND NOTHING ELSE. No canvas, no script, no per-particle DOM - two
    files in wwwroot/img, served by this app from this origin. Nothing third-party is fetched; the guest
    app refuses external assets for the token's sake and this does not make an exception.

    *** THEY ARE FILES AND NOT DATA URIS (Bradley, 2026-08-23: "make sure the URIs you used are actual
    files inside the solution"). *** They started inline - which fetched nothing and could not 404 - but a
    percent-encoded blob in a stylesheet is unreadable, undiffable, and fails SILENTLY on one bad escape:
    the layer simply renders nothing and there is no error anywhere to tell you why. As files they can be
    opened, reviewed in a diff, and seen to be wrong. The artwork is byte-for-byte what it was.

    IT ANIMATES `transform` AND ONLY `transform`, which the compositor can do without repainting anything.
    The obvious implementation - animating `background-position` on a full-viewport layer - repaints the
    whole thing every frame, and this is a page people read for twenty minutes.

    IT LOOPS SEAMLESSLY BECAUSE THE TRAVEL IS EXACTLY ONE TILE. Each layer translates by its own
    background-size and then snaps back, which is invisible on a repeating pattern. Change a
    background-size without changing its keyframe distance and you get a visible jump every cycle.

    TWO LAYERS AT DIFFERENT SIZES, SPEEDS AND DIRECTIONS, because one layer sliding in a straight line
    reads as a screensaver. Crossing drifts read as depth.

    AND IT IS FAINT ON PURPOSE - the alpha lives in the SVG strokes, around 6%. The test is that a price in
    an input is never harder to read than it was on the flat grey; anything you actually notice while
    typing is too strong.
   -------------------------------------------------------------------------------------------------- */

.guest-money-field {
    position: fixed;
    inset: 0;

    /* BEHIND EVERY CARD, AND UNCLICKABLE. The cards are opaque white, so content never sits on the
       pattern - it shows in the gutters and between them, which is where the blandness was. */
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
}

.guest-money-field::before,
.guest-money-field::after {
    content: "";
    position: absolute;

    /* OVERSIZED BY MORE THAN ONE TILE ON EVERY SIDE, so the translating edge is never on screen. */
    inset: -30%;
    background-repeat: repeat;
    will-change: transform;
}

/*
    THE TWO LAYERS.

    *** THE PATH IS RELATIVE TO THIS STYLESHEET, NOT TO THE PAGE. *** `../img/` from /css/site.css resolves
    to /img/ - which is also what a root-relative /img/ would give today, but this survives the app ever
    being hosted under a path prefix, and the pages that use it live at three different URL depths (/,
    /q/{token}, /q/{token}/rfq/{id}).

    NOT FINGERPRINTED, WHICH IS THE ONE THING TO KNOW. MapStaticAssets fingerprints assets referenced
    through the tag helpers, and does NOT rewrite url() inside a stylesheet - so an EDIT to either svg can
    be served stale from a browser cache. Renaming the file is the way to force it, and the stylesheet
    itself is versioned by asp-append-version so the new name lands immediately.
*/

/* COINS: the smaller, quicker layer. Concentric rings with a plain currency mark - abstract rather than
   any one country's coin, because this page is quoted on in whatever currency the buyer asked for. */
.guest-money-field::before {
    background-size: 300px 300px;
    background-image: url("../img/money-coins.svg");
    animation: guest-coins-drift 78s linear infinite;
}

/* BANKNOTES: the larger, slower layer, drifting the other way. */
.guest-money-field::after {
    background-size: 460px 460px;
    background-image: url("../img/money-notes.svg");
    animation: guest-notes-drift 124s linear infinite;
}

/* THE TRAVEL IS ONE TILE IN EACH AXIS - see the note above on why the number must match its layer. */
@keyframes guest-coins-drift {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-300px, -300px, 0); }
}

@keyframes guest-notes-drift {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(460px, -460px, 0); }
}

/*
    *** IT STOPS DEAD FOR ANYBODY WHO ASKED FOR THAT, AND THE PATTERN STAYS. *** Reduced motion is a real
    setting people turn on for vestibular reasons, and a drifting full-screen layer is exactly what it is
    for. Removing the pattern as well would be answering a question nobody asked - the objection is to
    movement, not to decoration.
*/
@media (prefers-reduced-motion: reduce) {
    .guest-money-field::before,
    .guest-money-field::after {
        animation: none;
    }
}

/* NOT ON PAPER. A supplier printing the requirement to walk it round a warehouse does not need this on
   every page, and a faint tile prints as grey mush. */
@media print {
    .guest-money-field { display: none; }
}

h1, h2, h3, .fw-semibold, strong {
    color: var(--guest-ink);
}

/* --- CHROME ------------------------------------------------------------------------------------- */

.guest-header {
    background: var(--guest-surface);
    border-bottom: 1px solid var(--guest-line);
}

.guest-brand {
    font-weight: 700;
    font-size: 1.2rem;
    letter-spacing: -0.02em;
    color: var(--guest-ink);
}

.guest-brand-note {
    color: var(--guest-muted);
    font-size: 0.875rem;
}

.guest-footer {
    color: var(--guest-muted);
    border-top: 1px solid var(--guest-line);
    background: var(--guest-surface);
    margin-top: 4rem;
    font-size: 0.875rem;
}

.guest-card {
    background: var(--guest-surface);
    border: 1px solid var(--guest-line);
    border-radius: var(--guest-radius);
    box-shadow: var(--guest-shadow);
}

/*
    THE GREETING, SET OFF FROM THE ROUND ITSELF BY A RULE RATHER THAN BY SIZE. It addresses a person; the
    heading under it names a requirement. Without the divider the two run together and the greeting reads
    as part of the RFQ's own title, which is where a subject line goes, not a name.
*/
.guest-greeting {
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--guest-line);
}

/*
    THE PRIMARY ACTION. Bootstrap's default blue is fine and anonymous; this one is the same blue the
    invitation email uses, so the button they clicked in their inbox and the button they press here are
    visibly the same promise.
*/
.btn-primary {
    --bs-btn-bg: var(--guest-accent);
    --bs-btn-border-color: var(--guest-accent);
    --bs-btn-hover-bg: var(--guest-accent-dark);
    --bs-btn-hover-border-color: var(--guest-accent-dark);
    --bs-btn-active-bg: var(--guest-accent-dark);
    --bs-btn-active-border-color: var(--guest-accent-dark);
    font-weight: 600;
}

.btn {
    border-radius: 0.5rem;
}

/* --- THE LINE TABLE ----------------------------------------------------------------------------- */

/*
    IT SCROLLS INSIDE ITSELF RATHER THAN PUSHING THE PAGE SIDEWAYS.

    A bid form has more columns than a phone has width, and a supplier pricing from a car park is a real
    case rather than a hypothetical one. A horizontally scrolling PAGE hides the submit button; a
    horizontally scrolling TABLE does not.
*/
.guest-lines {
    overflow-x: auto;
    margin: 0 -0.25rem;
    padding: 0 0.25rem;
}

.guest-lines table {
    min-width: 52rem;
}

/*
    *** COLUMN WIDTHS ARE DECLARED, NOT LEFT TO THE BROWSER (Bradley, testing 2026-08-22). ***

    Auto layout sizes every column to its widest content, so one long description made the item column
    swallow the row and squeezed the four inputs into ragged slivers of different widths. Fixing the input
    columns and letting the item column take what is left is what makes the controls line up down the page
    - which is what the eye is actually checking when it scans a form.
*/
.guest-lines thead th {
    color: var(--guest-muted);
    font-weight: 600;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    border-bottom: 1px solid var(--guest-line);
    white-space: nowrap;
    vertical-align: bottom;
}

.guest-lines tbody td {
    border-bottom: 1px solid var(--guest-line-soft);
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
}

.guest-col-no    { width: 2.5rem; }
.guest-col-qty   { width: 6rem; }
.guest-col-price { width: 11rem; }
.guest-col-pack  { width: 9rem; }
.guest-col-lead  { width: 6.5rem; }
/* PER-LINE VAT (2026-08-24). Wide enough for "Standard rate" and "Same as bid" without wrapping. */
.guest-col-vat   { width: 9.5rem; }
/* WIDER SINCE 2026-08-24: the "Not quoting" control now carries its own words, and 6rem fitted a bare
   checkbox - it would break the label across three lines. */
.guest-col-nq    { width: 8.5rem; }
/* The item column takes whatever is left, which is what "no width" means under table-layout: fixed. */
.guest-col-item  { min-width: 16rem; }

/* A line marked "not quoting" keeps its boxes visible but stops inviting numbers into them. */
.guest-muted-field {
    opacity: 0.45;
}

/*
    THE NORMALISATION PREVIEW - §5.3's first hazard control.

    "R550.00 / 120 = R4.583333 per Each", live, as they type. Reserved height even when empty, so the row
    does not jump the moment somebody types their first digit.
*/
.guest-normalised {
    font-size: 0.8rem;
    color: var(--guest-muted);
    min-height: 1.25rem;
    margin-top: 0.25rem;
}

.guest-normalised.is-set {
    color: var(--guest-ink);
    font-variant-numeric: tabular-nums;
}

/*
    HOT / WARM / COLD.

    ICON AND TEXT, NEVER COLOUR ALONE - the same rule the buyer's hazard flags follow, and for the same
    reason: about one man in twelve cannot tell the red from the green, and this is the only feedback a
    losing supplier ever gets about the field.
*/
.guest-band {
    font-weight: 600;
    font-size: 0.8rem;
}

.guest-band-hot { color: var(--guest-hot); }
.guest-band-warm { color: var(--guest-warm); }
.guest-band-cold { color: var(--guest-cold); }

.guest-outcome {
    font-size: 0.85rem;
    color: var(--guest-muted);
}

/* --- FORMS -------------------------------------------------------------------------------------- */

.form-control, .form-select {
    border-color: var(--guest-line);
    border-radius: 0.5rem;
}

.form-control:focus, .form-select:focus {
    border-color: var(--guest-accent);
    box-shadow: 0 0 0 3px rgba(11, 92, 213, 0.12);
}

.form-label {
    color: var(--guest-ink);
    font-weight: 500;
}

/* Money and quantities line up column-wise only if the digits are the same width. */
input[type="number"] {
    font-variant-numeric: tabular-nums;
}

/* --- THE JOIN CALL TO ACTION -------------------------------------------------------------------- */

.guest-join {
    background: linear-gradient(180deg, #ffffff 0%, #f4f7fe 100%);
    border: 1px solid var(--guest-line);
    border-radius: var(--guest-radius);
}

/*
    THE LIVE WATCH — the countdown to the next automatic reload.

    IT IS DELIBERATELY QUIETER THAN A BAND AND LOUDER THAN A FOOTNOTE. This started as one line inside the
    "revision N is in" alert and read as small print about something that had already happened, when it is
    an instrument about what happens next (Bradley, 2026-08-22: "it just wants clear"). So it gets its own
    card and a figure big enough to read across a desk - and still no accent colour, because the accent on
    this page means "this is the button" and the band colours mean a commercial fact. A clock is neither.

    TABULAR FIGURES SO IT DOES NOT JITTER. A proportional font re-lays the whole line every second as the
    digits change width, which turns a calm countdown into a twitch at the edge of the eye.
*/
.guest-watch {
    border-left: 3px solid var(--guest-accent);
}

.guest-watch-clock {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1;
    color: var(--guest-ink);
    font-variant-numeric: tabular-nums;
    min-width: 3.5rem;
}

/*
    PAUSED LOOKS STOPPED, AND THAT IS THE POINT OF SHOWING IT AT ALL. A supplier who has started typing
    needs to know the page is not about to reload under them, and the clock going grey and showing a dash
    says it faster than the sentence beside it does.
*/
.guest-watch.is-paused {
    border-left-color: var(--guest-line);
}

.guest-watch.is-paused .guest-watch-clock {
    color: var(--guest-muted);
}

/* ---------------------------------------------------------------------------------------------------
   "NOT QUOTING" (Bradley, 2026-08-24: "the checkbox is very light and the users claim to not see it").

   WHAT WAS WRONG. The control was a default .form-check-input - a 1em square with a pale border - alone
   in a 6rem column, and its only <label> carried d-md-none, which hides a label from md UPWARDS. So on
   every desktop it was an unlabelled grey outline whose meaning lived in a table header two rows away.
   An unticked checkbox also looks identical to a disabled one, which is the worst possible ambiguity on
   a form that really does disable itself once a round closes.

   THE REPLACEMENT STATES ITS OWN STATE IN WORDS at every width, and fills solid when it is on. Nobody
   has to read a border colour.

   AMBER, NOT RED: declining a line is a normal answer on an RFQ, not an error.

   NO ICON FONT. This site ships bootstrap and jquery only, so the tick is a ::before glyph rather than
   a <i class="bi ...">, which would render as blank space here.
   --------------------------------------------------------------------------------------------------- */

.guest-noquote-toggle {
    width: 100%;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: normal;
    padding: 0.35rem 0.4rem;
    border: 1px solid var(--guest-line);
    color: var(--guest-body);
    background-color: var(--guest-surface);
}

.guest-noquote-toggle:hover {
    border-color: var(--guest-warm);
    color: var(--guest-warm);
}

/* THE ON STATE. Solid amber with a tick, so a declined line is visible from across the table rather
   than on inspection. */
.btn-check:checked + .guest-noquote-toggle {
    border-color: var(--guest-warm);
    background-color: var(--guest-warm);
    color: #fff;
}

.btn-check:checked + .guest-noquote-toggle::before {
    content: "\2713\00a0";
}

/* Keyboard focus has to be visible on a control whose whole problem was being invisible. */
.btn-check:focus-visible + .guest-noquote-toggle {
    outline: 0;
    box-shadow: 0 0 0 0.2rem rgba(181, 71, 8, 0.35);
}

/* A CLOSED ROUND DISABLES THE FORM, and the toggle must say so differently from "not ticked" - the
   ambiguity that made the old checkbox unreadable. */
.btn-check:disabled + .guest-noquote-toggle {
    opacity: 0.5;
    cursor: default;
}


/* THE WHOLE ROW SAYS SO TOO, which is the second half of the fix: a supplier scanning forty lines for
   the ones they have declined should not have to read forty small buttons. Applied by bid-form.js. */
.guest-line-noquote td {
    background-color: #fffaf5;
}

/* The "excluding VAT" / "this line" hints under a column heading. Smaller and lighter than the heading
   so it reads as a qualifier rather than as a second column name. */
.guest-col-hint {
    font-size: 0.72rem;
    line-height: 1.1;
}
